【问题标题】:Observable from <button> click event in Angular2可从 Angular2 中的 <button> 点击事件观察到
【发布时间】:2016-10-12 17:16:00
【问题描述】:

使用 Angular 2 从按钮的 onclick 事件创建 observable 的首选方法是什么?

我不确定在组件代码中从 DOM 中获取本机元素是否被认为是最佳做法(我该怎么做?),或者是否还有其他一些我不知道的快捷方式。

【问题讨论】:

标签: angular rxjs angular2-observables


【解决方案1】:

别想太多。

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

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

【讨论】:

  • 注意:如果按钮最初由于 *ngIf 而被隐藏,那么按钮将为空。虽然有一些方法可以解决这个问题(通过使用 button 和 flatmap / switchmap 的设置器),但它很快就会变得复杂。在这些情况下,最好使用 Jon 的答案。
  • 我认为 fromEvent 应该在 ngAfterViewInit 回调中调用,因为在 ngOnInit 中 this.button 仍未定义...
  • 来自 RxJS 6 Observable.fromEvent() 已被弃用。仅使用fromEvent() 而不是Observable.fromEvent()
【解决方案2】:

您可以使用Observable.fromEvent,如Angular2 RxJS getting 'Observable_1.Observable.fromEvent is not a function' error 中所述

或者只是转发到一个可观察的喜欢

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

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

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

【讨论】:

【解决方案3】:

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

【讨论】:

    【解决方案4】:

    如果您尝试使用 @ViewChild 并且您的按钮在初始化时在页面上不可见(由于 *ngIf),则分配将为空。

    您可以将 setter 与 @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 没意见,它们都是实现细节。好吧,这由你决定 -)

    【讨论】:

    • 事实证明,您也可以先执行new Subject&lt;void&gt;(),然后再执行btn.next(),而无需传递值。如果事件没有有用的意义,这可能很有用。
    • 目前在主题的管道内使用exhaustMap来停止发送垃圾http调用。但一个电话打完后,“垃圾邮件发送者”可以继续前进。有没有办法解决这个问题?
    【解决方案5】:

    对于那些使用 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)));
    }
    

    【讨论】:

      猜你喜欢
      • 2015-10-07
      • 1970-01-01
      • 2016-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      相关资源
      最近更新 更多