在ngFor块内的模板中的异步管道触发http GET调用循环

时间:2018-02-15 17:26:11

标签: angular typescript observable rxjs5

我有以下组件模板:

<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请求。

此外,如果我将方法调用放在ng之外,同样的事情也会发生。调用需要在ngFor内执行,因为每个集合项的参数都不同。

为什么简单地调用该方法一次,订阅后不再生成调用?

3 个答案:

答案 0 :(得分:4)

在模板中调用函数通常不是一个好主意,因为它会导致不可预测的结果。这是您重构代码以避免这种情况的方法:

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

答案 1 :(得分:3)

肯定你的问题与变化检测有关。

每次角度考虑可以对绘制模板所需的内容进行更改(即,除非您的组件为OnPush,否则任何时候都有浏览器事件),它将重新绘制组件,从而重新触发循环和可观察的。

在这种情况下,您有两种选择:

  • 确保在不需要时不会触发更改检测(例如,让您的组件跟随OnPush ChangeDetectionStrategy),但只有当@Input()有限的ngOnInit时,它才会起作用触发组件的更新。
  • 仅在ngOnChangesdata中执行请求(在@Input()是您的组件 middle = lowerIndex + (higherIndex - lowerIndex) / 2; = 0 + (7 - 0) / 2 = 0 + 7 / 2 = 3. //remember the truncation in int. 的情况下),并将结果存储在您的数组中以你的模板为基础进行for循环(我会这样做)。

答案 2 :(得分:3)

Angular在每个事件周期调用getNext,每次getNext发出新的http请求并返回新的Observable。您需要从第一个函数调用中缓存Observable。我建议你在控制器的某个地方创建它们,然后将模板作为变量传递。