ngFor 块内模板中的异步管道触发 http GET 调用循环
Async Pipe in Template inside ngFor block triggers http GET calls loop
我有以下组件模板:
<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}`);
}
我的目标是调用该方法并使用模板中的异步管道订阅可观察对象。但是,当我 运行 应用程序生成无穷无尽的 GET 和 OPTIONS 请求时。
另外,如果我将方法调用放在 ngFor 之外,也会发生同样的情况。该调用需要在 ngFor 内部执行,因为每个集合项的参数都不同。
为什么只调用一次,订阅后就不再调用了?
您的问题很可能与变更检测有关。
每次 angular 认为绘制模板所需的内容可能会发生变化(即只要有浏览器事件,除非您的组件是 OnPush
),它会重新绘制组件,从而重新触发循环和可观察对象。
在这种情况下,您有两个选择:
- 确保在不需要时不会触发变更检测(例如让您的组件遵循
OnPush
ChangeDetectionStrategy
),但它主要仅在 [=13= 的一组有限的情况下才有效] 触发组件的更新。
- 只在
ngOnInit
或 ngOnChanges
中执行一次请求(在 data
是组件的 @Input()
的情况下)并将结果存储在数组中您基于模板执行 for 循环(我会这样做)。
Angular 在每个事件周期调用 getNext
,并且每次 getNext
发出新的 http
请求和 returns 新的 Observable
。您需要从第一个函数调用中缓存 Observable
。我建议您在控制器中的某处创建它们,然后将模板作为变量传入。
在模板中调用函数通常不是一个好主意,因为它会导致不可预知的结果。这是重构代码以避免这种情况的方法:
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>
这是我创建的一个 stackblitz,您可以在其中看到类似机制的工作原理:https://stackblitz.com/edit/angular-nyn4qz
我有以下组件模板:
<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}`);
}
我的目标是调用该方法并使用模板中的异步管道订阅可观察对象。但是,当我 运行 应用程序生成无穷无尽的 GET 和 OPTIONS 请求时。
另外,如果我将方法调用放在 ngFor 之外,也会发生同样的情况。该调用需要在 ngFor 内部执行,因为每个集合项的参数都不同。
为什么只调用一次,订阅后就不再调用了?
您的问题很可能与变更检测有关。
每次 angular 认为绘制模板所需的内容可能会发生变化(即只要有浏览器事件,除非您的组件是 OnPush
),它会重新绘制组件,从而重新触发循环和可观察对象。
在这种情况下,您有两个选择:
- 确保在不需要时不会触发变更检测(例如让您的组件遵循
OnPush
ChangeDetectionStrategy
),但它主要仅在 [=13= 的一组有限的情况下才有效] 触发组件的更新。 - 只在
ngOnInit
或ngOnChanges
中执行一次请求(在data
是组件的@Input()
的情况下)并将结果存储在数组中您基于模板执行 for 循环(我会这样做)。
Angular 在每个事件周期调用 getNext
,并且每次 getNext
发出新的 http
请求和 returns 新的 Observable
。您需要从第一个函数调用中缓存 Observable
。我建议您在控制器中的某处创建它们,然后将模板作为变量传入。
在模板中调用函数通常不是一个好主意,因为它会导致不可预知的结果。这是重构代码以避免这种情况的方法:
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>
这是我创建的一个 stackblitz,您可以在其中看到类似机制的工作原理:https://stackblitz.com/edit/angular-nyn4qz