ngFor 块内模板中的异步管道触发 http GET 调用循环
Posted
技术标签:
【中文标题】ngFor 块内模板中的异步管道触发 http GET 调用循环【英文标题】:Async Pipe in Template inside ngFor block triggers http GET calls loop 【发布时间】:2018-07-26 13:11:58 【问题描述】:我有以下组件模板:
<div *ngFor="let ctrl of data; trackBy:ctrl?.Id">
<div *ngIf="getNext(ctrl.nextDate) | async as next">
<span>next | date: 'dd.MM.yyyy'</span>
</div>
</div>
getNext() 是一个返回Observable<Date>
的简单方法:
public getNext(deadline: string): Observable<Date>
return this.http.get<Date>(`$this.config.apiEndpoint/api/meeting?deadline=$deadline`);
我的目标是调用该方法并使用模板中的异步管道订阅 observable。但是,当我运行应用程序时,会生成无休止的 GET 和 OPTIONS 请求。
另外,如果我将方法调用放在 ngFor 之外,也会发生同样的情况。由于每个集合项的参数不同,因此需要在 ngFor 内部执行调用。
为什么方法只调用一次,订阅后就不再产生调用?
【问题讨论】:
【参考方案1】:在模板中调用函数通常不是一个好主意,因为它会导致不可预测的结果。您可以通过以下方式重组代码以避免这种情况:
data: any = [....] // some data
data$: Observable[];
ngOnInit()
this.data$ = this.data.map(elem => this.getNext(elem));
public getNext(deadline: string): Observable<Date>
return this.http.get<Date>(`$this.config.apiEndpoint/api/meeting?deadline=$deadline`);
在你的模板中:
<div *ngFor="let ctrl of data$">
<div *ngIf="ctrl | async as next">
<span>next | date: 'dd.MM.yyyy'</span>
</div>
</div>
这是我创建的堆栈闪电战,您可以在其中看到类似机制的工作原理:https://stackblitz.com/edit/angular-nyn4qz
【讨论】:
“在模板中调用函数通常不是一个好主意,因为它会导致不可预测的结果。” - 什么是不可预测结果的示例? @Zze 一个不可预知的结果就是例如问题中的问题:) 大声笑,正是:D @VictorNoël 正如您的回答中所解释的那样,这并非不可预测。尽管不幸的是,它的工作方式与预期的完全一样 - 导致此问题的循环变化检测。虽然这是公认的答案,但在这个答案中,首先没有解释实际问题是什么。 @Zze 你是对的,这是不可预测的,因为它永远不会像在模板中使用函数的开发人员所期望的那样。无论如何,感谢您的信任投票!【参考方案2】:Angular 在每个事件循环中调用getNext
,并且每次getNext
发出新的http
请求并返回新的Observable
。您需要从第一个函数调用中缓存Observable
。我建议您在控制器中的某处创建它们,然后将模板作为变量传递。
【讨论】:
【参考方案3】:您的问题肯定与变更检测有关。
每当 angular 认为绘制模板所需的内容可能会发生变化(即,只要有浏览器事件,除非您的组件是 OnPush
),它都会重新绘制组件,从而重新触发循环和 observable .
在这种情况下,您有两个选择:
确保在不需要时不会触发更改检测(例如,通过使您的组件遵循OnPush
ChangeDetectionStrategy
),但它主要仅在触发组件更新的@Input()
的有限集合时才有效.
只在ngOnInit
或ngOnChanges
中执行一次请求(如果data
是您的组件的@Input()
),并将结果存储在一个数组中,您的模板基于该数组执行循环(我会走这条路)。
【讨论】:
以上是关于ngFor 块内模板中的异步管道触发 http GET 调用循环的主要内容,如果未能解决你的问题,请参考以下文章
Angular *ngFor 使用异步管道绑定到 observable - 发生了啥?
带有 ngSwitch 的条件按钮也带有来自异步管道数组的 ngFor
找不到“object”类型的不同支持对象“[object Object]”。 NgFor 仅支持绑定到 Iterables,例如带有异步管道的数组