Observable from <button> click event in Angular2

浪尽此生 提交于 2020-11-30 02:58:52

问题


What's the preferred way to create an observable from a button's onclick event using Angular 2?

I'm not sure if it's considered best practice to grab the native element from the DOM in the component code (how do I do this?), or if there's some other shortcut I don't know about.


回答1:


You can use Observable.fromEvent like explained in Angular2 RxJS getting 'Observable_1.Observable.fromEvent is not a function' error

Or just forward to an observable like

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

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

or

<button (click)="obs.next($event)">



回答2:


Don't overthink it.

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

ngOnInit() {
  this.clicks$ = Observable.fromEvent(this.button.nativeElement, 'click');
}



回答3:


@Gunter's example didn't quite work for me, because my compiler didn't recognize publ.

Here's an example of what worked for me: 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);
    }
}

Inside modal.component.html:

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



回答4:


If you try to use @ViewChild and your button isn't visible on the page at init time (due to an *ngIf) then the assignment will be null.

You can use a setter in conjunction with @ViewChild, and run your initialization when the button first appears.

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

This quickly gets clumsy and inconvenient - especially if you create an observable stream from this.

A hybrid way might be as follows:

btnAskAnotherClicks$ = new Subject<Event>();

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

This allows you to use the click stream to create chains, but no issues if the button is initially hidden due to *ngIf.

Don't like next in your template? Neither do I particularly. But I'm ok with async, and they're both implementation details. Well that's up to you to decide -)




回答5:


For those using AngularMaterial buttons and pipeable RxJS operators, some slight mods to @JoshuaDavid's answer:

Some button in template tagged with a template variable:

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

The component code:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';

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


来源:https://stackoverflow.com/questions/37770226/observable-from-button-click-event-in-angular2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!