我开始对RxJS运算符有一定的了解,但是我仍然对其中的一些困难。在实现搜索组件时,我具有以下代码:
searchResult$: Observable<LunrDoc []>;
searchResultLength$: Observable<number>;
ngAfterViewInit(): void {
// observable to produce an array of search hits
this.searchResult$ = fromEvent<Event>(this.searchInput.nativeElement, 'keyup').pipe(
debounceTime(1000),
switchMap(e => this.ss.search((e.target as HTMLTextAreaElement).value)),
share()
);
// observable to return the length of the array
this.searchResultLength$ = this.searchResult$.pipe(
map(sr => sr ? sr.length : 0),
share()
);
}
这在模板中使用如下:
<p *ngIf="(searchResultLength$ | async) > 0">
Total Documents: {{ (searchResultLength$ | async) | number }}
</p>
<p *ngFor="let doc of (searchResult$ | async)">
<span *ngIf="doc.path" [routerLink]="doc.path" style="color: darkblue; font-weight: bold; text-underline: darkblue; cursor: pointer">
{{ doc.title }}
</span>
{{ doc.content.substring(0, 400) }}
</p>
发生的情况是,当searchResult$
发出非null数组时,可观察到的第一段元素中的呈现结果为“ Total Documents:”,其后没有数字。 * ngFor 装饰段落完全符合预期。
我相信,原因是第二个async
管道被激活,并在发出最后一个值后订阅了共享的observable。因此,它永远不会收到“下一个”呼叫。
是否有RxJS运算符代替share
来解决此问题?还是我想念其他东西?
答案 0 :(得分:1)
如@IngoBürk所建议。 shareReplay(1)
可能就是您想要的。 1表示缓冲区大小(应播放多少个值)。
我还将建议避免创建多个可观察对象。
例如这将创建两个不同的订户。
<p *ngIf="(searchResultLength$ | async) > 0">
Total Documents: {{ (searchResultLength$ | async) | number }}
</p>
替代方法是:
<p *ngIf="(searchResultLength$ | async) as searchResultLength > 0">
Total Documents: {{ searchResultLength | number }}
</p>
通过查看代码并尝试了解其功能,我认为您可以进行这些更改以获得所需的输出。
组件:
searchResult$: Observable<LunrDoc []>;
ngAfterViewInit(): void {
this.searchResult$ = fromEvent<Event>(this.searchInput.nativeElement, 'keyup')
.pipe(
debounceTime(1000),
switchMap(e => this.ss.search((e.target as HTMLTextAreaElement).value)),
);
}
您不需要share
或shareReplay
,因为它们似乎没有提供模板所需的任何功能。除非模板中还有其他代码在您的问题中不可见。
可观察到的this.searchResultLength$
似乎也很多余,因为它只是length
返回的值的this.searchResult$
属性。
模板:
<ng-container *ngIf="{searchResult: searchResult$ | async} as vm">
<p *ngIf="vm.searchResult.length > 0">
Total Documents: {{ vm.searchResult }}
</p>
<p *ngFor="let doc of vm.searchResult">
<span *ngIf="doc.path" [routerLink]="doc.path" style="color: darkblue; font-weight: bold; text-underline: darkblue; cursor: pointer">
{{ doc.title }}
</span>
{{ doc.content.substring(0, 400) }}
</p>
</ng-container>
包装器ng-container
将始终显示,因为ngIf
条件的计算结果为真实值。
注意
在处理触发可观察的输入时,请考虑使用ditinctUntilChanged
运算符:https://www.learnrxjs.io/operators/filtering/distinctuntilchanged.html