angular2 ręcznie wyzwalające zdarzenie kliknięcia na konkretny element

82

Próbuję programowo wywołać zdarzenie kliknięcia (lub jakiekolwiek inne zdarzenie) na elemencie, innymi słowy, chcę poznać podobne funkcje, jakie oferuje metoda jQuery .trigger () w angular2.

Czy jest jakaś wbudowana metoda, aby to zrobić? ..... jeśli nie, proszę zasugerować, jak mogę to zrobić

Rozważ następujący fragment kodu

<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>

W tym przypadku, gdy użytkownik kliknie btnAdd , powinno uruchomić zdarzenie click na imgFile

Jorin
źródło
Musisz tylko imgFile.click()zamiast tego showImageBrowseDlg()postępować zgodnie z poniższą odpowiedzią @ akshay-khale stackoverflow.com/a/41675017/344029 (po dodaniu zmiennej <input #imgFile)
DJDaveMark

Odpowiedzi:

184

Angular4

Zamiast

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

posługiwać się

    this.fileInput.nativeElement.dispatchEvent(event);

ponieważ invokeElementMethodnie będzie już częścią renderera.

Angular2

Użyj ViewChild ze zmienną szablonu, aby uzyskać odniesienie do wejścia pliku, a następnie użyj modułu renderującego, aby wywołać dispatchEventzdarzenie:

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]);
  }
}

Aktualizacja

Ponieważ zespół Angular nie odradza już bezpośredniego dostępu do DOM, ten prostszy kod może być również używany

this.fileInput.nativeElement.click()

Zobacz także https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent

Günter Zöchbauer
źródło
10
this.fileInput.nativeElement.click()wydaje się, że również działa.
lbrahim
3
@lbrahim, zgadza się. W tamtym czasie była to silna sugestia, aby zamiast tego unikać dostępu do właściwości lub metod nativeElementi używania Renderer. Myślę, że zmieniło się to całkiem niedawno i bezpośredni dostęp do DOM jest teraz w porządku, ale nie będzie działać z renderowaniem po stronie serwera i WebWorkerami.
Günter Zöchbauer
1
@AralRoca następnie użyj @ViewChildren('fileInput') QueryList<ElementRef>;Zobacz także stackoverflow.com/questions/32693061/…
Günter Zöchbauer
1
Nie jestem do końca pewien i nie widziałem oficjalnych dokumentów, które o tym wspominają, ale o ile pamiętam, było to wspomniane w niektórych wydaniach GitHub. Myślę też, że pamiętam, że niektóre przykłady dokumentów zostały zaktualizowane w celu usunięcia mechanizmu renderującego i korzystania z bezpośredniego dostępu do DOM. Odniosłem wrażenie, że jeśli nie zamierzasz używać renderowania po stronie serwera lub robotów internetowych, to jest to po prostu uciążliwe ograniczenie i wielu programistów nie dba o to i w ten sposób usunęli z tego silna zasada.
Günter Zöchbauer
1
@ManuChadha po co w ogóle używać jquery? Może to prowadzić do problemów, gdy Angular i jquery myślą, że obaj są w pełni kontrolowani przez FOM. jquery stało się ostatnio znacznie mniej istotne, ponieważ różnice między przeglądarkami są znacznie mniejsze, a większość starszych przeglądarek całkowicie porzuciła obsługę.
Günter Zöchbauer
27

Chciałem też podobną funkcjonalność, gdzie mam kontrolę plik wejściowy z display:nonei kontroli Przycisk gdzie chciałem wyzwalacza kliknij zdarzenie wejścia pliku kontrolnym po kliknięciu na przycisk poniżej jest kod, aby to zrobić

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

takie proste i działa bez zarzutu ...

Akshay Khale
źródło
1
Użyłem dokładnie tego, aby kliknąć przycisk po naciśnięciu klawisza Enter w polu tekstowym:<input #name type="text" (keyup.enter)="addBtn.click()"> <button #addBtn (click)="add(name.value)" type="button">Add</button>
DJDaveMark
4

To zadziałało dla mnie:

<button #loginButton ...

i wewnątrz kontrolera:

@ViewChild('loginButton') loginButton;
...
this.loginButton.getNativeElement().click();
Marco C.
źródło
Dzięki stary. działało jak urok z ionic3. :)
DwlRathod
2

Odpowiedź Güntera Zöchbauera jest właściwa. Wystarczy rozważyć dodanie następującego wiersza:

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]);
  }

W moim przypadku dostałbym błąd „złapany RangeError: maksymalny rozmiar stosu wywołań przekroczony”, jeśli nie. (Mam kartę div uruchamianą po kliknięciu i plik wejściowy w środku)

odnowienie
źródło
1
Możesz również ustawić klucz „bubbles” na false, co zapobiega
propagowaniu
2

Jeśli chcesz imitować, kliknij element DOM w ten sposób:

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

i mam na stronie coś takiego:

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

Twoja funkcja w component.tspowinna wyglądać następująco:

showLogin(event) {
   event.stopPropagation();
   document.getElementById('login-menu').click();
}
Rammgarot
źródło
1

Aby uzyskać natywne odniesienie do czegoś takiego ion-input, jak , używając tego

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

i wtedy

this.fileInput.nativeElement.querySelector('input').click()
davejoem
źródło
Dziękuję bardzo! Pracowałem nad tym, żeby to zadziałało w Ionic. Pozdrawiam
fromage9747
Zapraszamy
davejoem