angular2 activando manualmente el evento de clic en un elemento particular

81

Estoy tratando de activar el evento de clic (o cualquier otro evento) en el elemento programáticamente.En otras palabras, quiero conocer las características similares que ofrece el método jQuery .trigger () en angular2.

¿Existe algún método integrado para hacer esto? ..... si no, por favor sugiera cómo puedo hacer esto

Considere el siguiente fragmento de código

<form [ngFormModel]="imgUploadFrm"
          (ngSubmit)="onSubmit(imgUploadFrm)">
        <br>
        <div class="input-field">
            <input type="file" id="imgFile" (click)="onChange($event)" >
        </div>
        <button id="btnAdd" type="submit" (click)="showImageBrowseDlg()" )>Add Picture</button>
 </form>

Aquí, cuando el usuario hace clic en btnAdd , debería disparar el evento de clic en imgFile

Jorin
fuente
Solo necesita en imgFile.click()lugar de showImageBrowseDlg()si sigue la siguiente respuesta de @ akshay-khale stackoverflow.com/a/41675017/344029 (después de agregar la variable <input #imgFile)
DJDaveMark

Respuestas:

182

Angular4

En vez de

    this.renderer.invokeElementMethod(
        this.fileInput.nativeElement, 'dispatchEvent', [event]);

utilizar

    this.fileInput.nativeElement.dispatchEvent(event);

porque invokeElementMethodya no será parte del renderizador.

Angular2

Use ViewChild con una variable de plantilla para obtener una referencia a la entrada del archivo, luego use el Renderer para invocar dispatchEventy disparar el evento:

import { Component, Renderer, ElementRef, ViewChild } from '@angular/core';
@Component({
  ...
  template: `
...
<input #fileInput type="file" id="imgFile" (click)="onChange($event)" >
...`
})
class MyComponent {
  @ViewChild('fileInput') fileInput:ElementRef;

  constructor(private renderer:Renderer) {}

  showImageBrowseDlg() {
    // from http://stackoverflow.com/a/32010791/217408
    let event = new MouseEvent('click', {bubbles: true});
    this.renderer.invokeElementMethod(
        this.fileInput.nativeElement, 'dispatchEvent', [event]);
  }
}

Actualizar

Dado que el equipo de Angular ya no desaconseja el acceso directo al DOM, este código más simple también se puede usar

this.fileInput.nativeElement.click()

Véase también https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent

Günter Zöchbauer
fuente
10
this.fileInput.nativeElement.click()también funciona, parece.
Ibrahim
3
@lbrahim eso es correcto. En ese momento era una fuerte sugerencia evitar acceder a las propiedades o métodos nativeElementy utilizarlos Rendereren su lugar. Creo que esto cambió bastante recientemente y el acceso directo al DOM está bien ahora, pero no funcionará con la representación del lado del servidor y WebWorkers.
Günter Zöchbauer
1
@AralRoca y luego use @ViewChildren('fileInput') QueryList<ElementRef>;Ver también stackoverflow.com/questions/32693061/…
Günter Zöchbauer
1
No estoy completamente seguro de eso y no he visto documentos oficiales que lo mencionen, pero por lo que recuerdo se mencionó en algunos números de GitHub. También creo recordar que algunos ejemplos de documentos se actualizaron para eliminar el renderizador y usar el acceso DOM directo. Tengo la impresión de que si no tiene la intención de utilizar la representación del lado del servidor o los trabajadores web, entonces es solo una limitación engorrosa y a muchos desarrolladores no les importa eso y que esta es la forma en que eliminaron de hacer de eso un regla fuerte.
Günter Zöchbauer
1
@ManuChadha ¿por qué usar jquery? Podría dar lugar a problemas cuando Angular y jquery piensan que ambos están en pleno control del FOM. jquery se ha vuelto mucho menos relevante recientemente porque las diferencias entre los navegadores son mucho menores y la mayoría de los navegadores descartaron completamente la compatibilidad con navegadores antiguos.
Günter Zöchbauer
27

También quería una funcionalidad similar en el que tengo un control de entrada de archivos con display:noney un control Button donde quería gatillo evento click del archivo de entrada de control al hacer clic en el botón, a continuación es el código para hacerlo

<input type="button" (click)="fileInput.click()" class="btn btn-primary" value="Add From File">
<input type="file" style="display:none;" #fileInput/>

tan simple como eso y funciona a la perfección ...

Akshay Khale
fuente
1
<input #name type="text" (keyup.enter)="addBtn.click()"> <button #addBtn (click)="add(name.value)" type="button">Add</button>
Usé
4

Esto funcionó para mí:

<button #loginButton ...

y dentro del controlador:

@ViewChild('loginButton') loginButton;
...
this.loginButton.getNativeElement().click();
Marco C.
fuente
gracias amigo. funcionó de maravilla con ionic3. :)
DwlRathod
esto no funciona en Angular 7+
davejoem
2

La respuesta de Günter Zöchbauer es la correcta. Solo considere agregar la siguiente línea:

showImageBrowseDlg() {
    // from http://stackoverflow.com/a/32010791/217408
    let event = new MouseEvent('click', {bubbles: true});
    event.stopPropagation();
    this.renderer.invokeElementMethod(
        this.fileInput.nativeElement, 'dispatchEvent', [event]);
  }

En mi caso, obtendría un error de "RangeError atrapado: tamaño máximo de pila de llamadas excedido" si no. (Tengo una tarjeta div que se dispara al hacer clic y el archivo de entrada en el interior)

renegación
fuente
1
También puede establecer la clave de "burbujas" en falso, lo que evita que el evento
burbujee en el
2

Si desea imitar, haga clic en el elemento DOM de esta manera:

<a (click)="showLogin($event)">login</a>

y tener algo como esto en la página:

<li ngbDropdown>
    <a ngbDropdownToggle id="login-menu">
        ...
    </a>
 </li>

tu función component.tsdebería ser así:

showLogin(event) {
   event.stopPropagation();
   document.getElementById('login-menu').click();
}
Rammgarot
fuente
0

Para obtener la referencia nativa a algo como un ion-input, ry usando esto

@ViewChild('fileInput', { read: ElementRef }) fileInput: ElementRef;

y entonces

this.fileInput.nativeElement.querySelector('input').click()
davejoem
fuente