Наблюдается из события щелчка ‹button› в Angular2

Какой предпочтительный способ создания наблюдаемого из события onclick кнопки с помощью Angular 2?

Я не уверен, считается ли лучшей практикой захват нативного элемента из DOM в коде компонента (как мне это сделать?) Или есть какой-то другой ярлык, о котором я не знаю.


person GBa    schedule 12.06.2016    source источник
comment
См. github.com/angular/angular/issues/4062   -  person Mark Rajcok    schedule 12.06.2016
comment
@MarkRajcok, спасибо, это поучительно. Какой хороший способ сделать это сегодня?   -  person GBa    schedule 12.06.2016


Ответы (5)


Вы можете использовать Observable.fromEvent, как описано в Angular2 RxJS получает ошибку Observable_1.Observable.fromEvent is not a function

Или просто вперед к наблюдаемому как

private obs = new Subject();
public obs$ = this.obs.asObservable();

@HostListener('click', ['$event']) 
clickHandler(event){
  this.obs.next(event);
}

or

<button (click)="obs.next($event)">
person Günter Zöchbauer    schedule 12.06.2016
comment
Я не согласен со вторым подходом после прочтения статьи создателя rxjs. medium.com/@benlesh/ - person Yew Hong Tat; 21.02.2021

Не зацикливайтесь на этом.

@ViewChild('button') button;
clicks$:Observable<any>;

ngOnInit() {
  this.clicks$ = Observable.fromEvent(this.button.nativeElement, 'click');
}
person JoshuaDavid    schedule 15.02.2017
comment
Примечание: если кнопка изначально скрыта из-за * ngIf, тогда кнопка будет нулевой. Хотя есть способы обойти это (используя сеттер для button и flatmap / switchmap), это может быстро усложниться. В этих случаях лучше использовать ответ Джона. - person Simon_Weaver; 26.09.2018
comment
Я думаю, что fromEvent следует вызывать в обратном вызове ngAfterViewInit, потому что в ngOnInit this.button все еще не определен ... - person user2010955; 08.06.2020
comment
из RxJS 6 Observable.fromEvent() устарел. Используйте только fromEvent() вместо Observable.fromEvent(). - person Cichy; 17.11.2020

Пример @Gunter у меня не совсем сработал, потому что мой компилятор не распознал publ.

Вот пример того, что у меня сработало: modal.component.ts

import { Output, Component } from '@angular/core';
import {Subject} from "rxjs/Subject";

export class MyModal{

    private clickStream = new Subject<Event>();

    @Output() observ = this.clickStream.asObservable();

    buttonClick(event:Event){
        this.clickStream.next(event);
    }
}

Внутри modal.component.html:

<button type="button" class="btn btn-default" (click)="buttonClick($event)">click me</button>
person Jon    schedule 15.08.2016

Если вы попытаетесь использовать @ViewChild, а ваша кнопка не отображается на странице во время инициализации (из-за * ngIf), то присвоение будет нулевым.

Вы можете использовать сеттер вместе с @ViewChild и запускать инициализацию при первом появлении кнопки.

@ViewChild('btnAdd')
set btnAdd(btnAdd: Button) { ... } 

Это быстро становится неуклюжим и неудобным, особенно если из этого вы создаете наблюдаемый поток.

Гибридный способ может быть следующим:

btnAskAnotherClicks$ = new Subject<Event>();

<button mat-flat-button (click)="btnAskAnotherClicks$.next($event)">Ask another question...</button>

Это позволяет вам использовать поток кликов для создания цепочек, но без проблем, если кнопка изначально скрыта из-за * ngIf.

Не нравится next в вашем шаблоне? Я тоже не особо. Но я согласен с async, и это детали реализации. Ну это вам решать -)

person Simon_Weaver    schedule 26.09.2018
comment
Также оказывается, что вы также можете выполнить new Subject<void>(), а затем btn.next() без необходимости передавать значение. Это может быть полезно, если нет полезного смысла события. - person Simon_Weaver; 06.03.2019
comment
В настоящее время используется выхлопная карта внутри канала объекта, чтобы остановить спам-вызовы http. Но после того, как один звонок закончился, спамер может продолжать работу. Есть ли способ решить эту проблему? - person liqSTAR; 23.12.2019

Для тех, кто использует кнопки AngularMaterial и конвейерные операторы RxJS, несколько небольших модификаций для ответа @JoshuaDavid:

Некоторая кнопка в шаблоне, помеченная переменной шаблона:

<button #btnTemplateName mat-icon-button></button>

Код компонента:

import { Observable, fromEvent } from 'rxjs';

// Note importing from lettable/pipeable operators - 'operators' plural
import { tap } from 'rxjs/operators';

import { MatButton } from '@angular/material/button';

//Access the button through the template variable, typed to MatButton
@ViewChild('btnTemplateName') myBtn: MatButton;
myBtnClicks$: Observable<any>;


ngAfterViewInit() {

    // Note the need to access the native element in MatButton through the extended property chain
    this.myBtnClicks$ = 
      Observable.fromEvent(this.myBtn._elementRef.nativeElement, 'click');

    // Can now subscribe (using lettable/pipeable operators)
    this.myBtnClicks$.pipe(
       tap(() => console.log("Button clicked")),
    )
    .subscribe(event => console.log("Event:" + JSON.stringify(event)));
}
person joedev    schedule 04.05.2018