比如说,我有两个观察值要被模板使用,一个带有数据,另一个作为加载指示器:
public readonly data$ = this.backend.get<Data>(...).pipe(
finalize((
{
this.isLoadingSubject$.next(1);
return () => this.isLoadingSubject$.next(-1);
})()
);
private readonly isLoadingSubject$ = new Subject<number>();
public readonly isLoading$ = isLoadingSubject$.pipe(
scan((acc, value) => acc + value, 0),
map((i) => i > 0),
);
关于finalize
的解释:我正在使用iLife在data$
的管道被触发时开始加载,并在完成时结束加载.我使用的是递增或递减的数字,而不是布尔值,因为可能有多个同时请求(isLoading$
机制由许多可观察的管道使用).
在我的模板中,我这样使用它:
<ng-container *ngIf="data$ | async as data">
{{ data }}
<button [disabled]="isLoading$ | async">some button</button>
</ng-container>
问题是对isLoading$
的订阅很晚:这个订阅只在data$
发出后发生,而前.next(+1)
被忽略,因为没有订阅者.
我如何优雅地解决这个问题?
我try 过但不喜欢的变通方法:
- 立即订阅
isLoading$
以使其成为热门——这似乎是浪费,在阅读代码时,不清楚为什么会这样做.因此,如果仅仅从代码上看不清楚它的用途,那么这似乎是一个糟糕的解决方法. - 重新排列模板,使
isLoading$
在第一个<ng-container>
中,然后data$
在第二个<ng-container>
中-但我必须处理*ngIf
在加载false
时不渲染模板,因此我必须将其包装在一个对象中,这似乎再次浪费.而且,这会导致每次加载切换时都重新渲染所有内容,这很愚蠢. - 查看了
publishReplay()
运算符,但这已被弃用. - 将
data$
和isLoading$
包装在同一个<ng-container>
中的一个对象中,但是当加载指示器改变时,整个模板就会被重新渲染,这非常浪费——我只想禁用一个按钮.