![](/img/trans.png)
[英]Angular 2 Observable with setInterval not updating in template using async pipe
[英]Angular display template if observable is falsey with async pipe
我有一个 API 调用,它可能会返回一些数据,或者如果不存在数据,可能会返回一些虚假的东西。 如果有数据,我想从 stream 中tap
出来并做一些副作用,但如果是假的,我希望没有副作用发生但仍然显示我的模板代码。
我正在使用异步 pipe 来获取模板中的数据,但如果数据是假的,它将不会显示。
我已经看到用 object 包装ngIf
的技术,因此它的评估结果为真,但它似乎不是我的代码的正确解决方案。
我的模板:
<form *ngIf="loadedData$ | async">
...
</form>
我的 class:
loadedData$: Observable<boolean>;
ngOnInit(): void {
this.loadedData$ = this.getCurrentBranding().pipe(
tap(branding => {
if (branding) {
// Do side effects
}
}),
// current hack to make the template show
map(() => true)
);
}
private getCurrentBranding(): Observable<Branding> {
// API call, may return an object, or null
}
您始终可以尝试使其尽可能语义化。 您使用map
的方法不是一个坏主意,只是您实际上失去了对数据的访问权限。 最好将它分成两个Observables
:
readonly data$: Observable<BrandingData> = this.getCurrentBranding().pipe(
shareReplay({ refCount: true, bufferSize: 1 })
);
readonly loadingData$: Observable<boolean> = this.data$.pipe(
mapTo(false),
startWith(true)
);
然后,您可以通过检查是否正在加载数据来显示您的表单:
<form *ngIf="(loadingData$ | async) === false"></form>
这里发生的是,通过订阅模板中的loadingData$
,实际上也订阅了data$
osbervable,这将触发 API 请求。 通过使用shareReplay
,您可以确保此请求仅在每次订阅时执行一次。
“典型”是使用 object 作为“如果”方式
<!--see that the if is always "true" -is an object- -->
<form *ngIf="{response:loadedData$ | async} as res">
<!--you has the response in res.response-->
<ng-container *ngIf="res.response===false">
the result of the call is false
</ng-container>
<ng-container *ngIf="res.response!===false">
{{res.response|json}}
</ng-container>
</form>
我一直习惯于为我的组件使用一个可观察的对象来合并多个流,并将它们组合成一个 state。 通常这涉及到扫描操作符,但在这种情况下它不是必需的(尽管也许你也想合并这些副作用)。
在下面的代码中, getCurrentBranding将在组件中的异步pipe 订阅时执行。 为了防止多次执行,您可以使用一个根元素,使用 Angular的表达式将发射转换为模板变量。 或者,您可以使用shareReplay 。
startWith运算符用于提供初始值,因此将始终显示根元素。 该表单最初将被隐藏,直到从 api 返回结果。 数据将来自相同的可观察对象,并从根元素处创建的模板变量访问。
this.state$ = this.getCurrentBranding().pipe(
tap(branding => { /* Do side effects */ ),
map(data => ({ data, isLoaded: true}),
startWith(({ data: [], isLoaded: false})
);
<ng-container *ngIf="(state$ | async) as state">
<form *ngIf="state.isLoaded">
<!-- ... -->
</form>
<ol *ngFor="let o of state.data">
<!-- ... -->
</ol>
</ng-container>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.