angular - 订阅 *ngIf 背后的 DOM 事件
问题描述
我希望能够将 DOM 事件作为可观察流处理,调用过滤器、concatMap 等,如下例所示。
@Component({
template: `<button #btn>Submit<button`,
selector: 'app-test',
})
class TestComponent implements AfterViewInit, OnDestroy {
private destroy$ = new Subject<boolean>();
@ViewChild('btn') private btn: ElementRef<HtmlButtonElement>;
constructor(private testService: TestService) { }
ngAfterViewInit() {
fromEvent(btn.nativeElement, 'click').pipe(
exhaustMap(() = > {
return this.testService.save();
}),
takeUntil(this.destroy$),
).subscribe();
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
}
但有时我想监听事件的元素位于 *ngIf 后面,并且在 ngAfterViewInit 运行时不存在。仍然以反应方式侦听事件的最佳方法是什么?
ngOnViewChecked
我尝试的一种方法是在检查是否存在的 if 语句后面设置与上述相同的订阅ElementRef
,并使用标志来避免多个订阅。但我发现那很乱。
做这样的事情是一个好习惯吗?
@Component({
template: `<button (click)="clickEvent.emit()">Submit<button`,
selector: 'app-test',
})
class TestComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<boolean>();
clickEvent = new EventEmitter<void>();
constructor(private testService: TestService) { }
ngOnInit() {
this.clickEvent.pipe(
exhaustMap(() = > {
return this.testService.save();
}),
takeUntil(this.destroy$),
).subscribe();
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
}
我应该用 替换EventEmitter
吗Subject
?有没有比这些更好的方法?
编辑:为了清楚起见,我的问题与订阅由于 *ngIf 而可能不存在的元素的事件有关
解决方案
@ViewChildren
与 a一起使用QueryList
来监听 DOM 变化。
import { Component, AfterViewInit, OnDestroy, ElementRef, ViewChildren, QueryList } from '@angular/core';
import { Subject, fromEvent, of } from 'rxjs';
import { exhaustMap, takeUntil, switchMap, map, filter } from 'rxjs/operators';
@Component({
selector: 'app-test',
template: `<button #btn>Submit<button`
})
export class TestComponent implements AfterViewInit, OnDestroy {
private destroy$ = new Subject<boolean>();
// Any time a child element is added, removed, or moved,
// the query list will be updated, and the changes observable
// of the query list will emit a new value.
@ViewChildren('btn') private btn: QueryList<ElementRef>;
constructor(private testService: TestService) { }
ngAfterViewInit() {
this.btn.changes.pipe(
// only emit if there is an element and map to the desired stream
filter((list: QueryList<ElementRef>) => list.length > 0),
switchMap((list: QueryList<ElementRef>) => fromEvent(list.first.nativeElement, 'click')),
// add your other operators
exhaustMap(() => this.testService.save()),
takeUntil(this.destroy$),
).subscribe(console.log);
// Trigger a change event to emit the current state
this.btn.notifyOnChanges()
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
}
推荐阅读
- mysql - MySQL中的并行存储过程执行
- vba - Access VBA中的表单使用函数从网络ID设置字段
- html - 如何在不降低图像质量的情况下加载图像而不影响我的网站的加载速度
- jasper-reports - 如何更改饼图中的颜色(jaspersoft 工作室)
- python - 如何使用函数过滤数据框?
- git - Git 搞乱头和大师
- django - 如何在 Django admin 中显示正确的名称对象而不是“XXX 对象”
- python - 如何在保持结构的同时写入预先存在的 xml 文件?
- php - PluginManager::get 无法获取或创建 FileQueryPlugin 的实例
- hyperledger-fabric - 订购者是否存储所有区块链?