Sci*_*ion 5 javascript rxjs typescript angular
我尝试在我的组件中执行以下操作 changeDetection: ChangeDetectionStrategy.OnPush,
@ViewChild('searchInput') input: ElementRef;
ngAfterViewInit() {
this.searchText$ = fromEvent<any>(this.input.nativeElement, 'keyup')
.pipe(
map(event => event.target.value),
startWith(''),
debounceTime(300),
distinctUntilChanged()
);
}
Run Code Online (Sandbox Code Playgroud)
并在模板中
<div *ngIf="searchText$ | async as searchText;">
results for "<b>{{searchText}}</b>"
</div>
Run Code Online (Sandbox Code Playgroud)
它不起作用,但是如果我删除OnPush,它会起作用。我不太确定为什么因为异步管道应该触发更改检测。
编辑:
根据答案,我尝试用以下内容替换我所拥有的内容:
this.searchText$ = interval(1000);
Run Code Online (Sandbox Code Playgroud)
没有任何@Input,async管道正在标记我的组件进行检查,它工作得很好。所以我不明白为什么我没有和fromEvent
默认情况下,每当 Angular 启动更改检测时,它都会一一检查所有组件,检查是否有更改,如果更改则更新其 DOM。当您将默认更改检测更改为 时会发生什么ChangeDetection.OnPush?
Angular 改变了它的行为,并且只有两种方法来更新组件 DOM。
@Input 属性引用已更改
手动调用markForCheck()
如果您执行其中一项,它将相应地更新 DOM。在您的情况下,您不使用第一个选项,因此您必须使用第二个选项并markForCheck()在任何地方调用 。但有一种情况,每当你使用异步管道时,它都会为你调用这个方法。
异步管道订阅 Observable 或 Promise 并返回其发出的最新值。当发出新值时,异步管道会标记要检查更改的组件。当组件被销毁时,异步管道会自动取消订阅以避免潜在的内存泄漏。
所以这里没有什么魔法,它markForCheck()在幕后调用。但如果是这样,为什么你的解决方案不起作用?为了回答这个问题,让我们深入研究 AsyncPipe 本身。如果我们检查源代码 AsyncPipes 转换函数看起来像这样
transform(obj: Observable<any>|Promise<any>|null|undefined): any {
if (!this._obj) {
if (obj) {
this._subscribe(obj);
}
this._latestReturnedValue = this._latestValue;
return this._latestValue;
}
....// some extra code here not interesting
}
Run Code Online (Sandbox Code Playgroud)
因此,如果传递的值不是未定义的,它将订阅该可观察对象并相应地执行操作(markForCheck()每当值发出时调用)
现在这是最关键的部分
,Angular 第一次调用转换方法时,它是未定义的,因为您在回调searchText$内ngAfterViewInit()初始化(视图已经渲染,因此它也调用异步管道)。因此,当您初始化searchText$字段时,该组件的更改检测已经完成,因此它不知道searchText$已经定义了该字段,随后它不再调用 AsyncPipe,因此问题是它永远无法订阅 AsyncPipe变化,你要做的就是markForCheck()在初始化后只调用一次,Angular 在该组件上再次运行changeDetection,更新 DOM 并调用 AsyncPipe,它将订阅该可观察的
ngAfterViewInit() {
this.searchText$ =
fromEvent<any>(this.input.nativeElement, "keyup").pipe(
map((event) => event.target.value),
startWith(""),
debounceTime(300),
distinctUntilChanged()
);
this.cf.markForCheck();
}
Run Code Online (Sandbox Code Playgroud)