ngFor内的AsyncPipe用于项目

时间:2019-02-13 13:18:57

标签: angular

如何使用AsyncPipe 内部 ngFor,或者什么是对列表项进行异步调用的最佳实践?

示例: 假设我有一个产品订单,并且想显示产品的制造商。但是需要从存储(本地存储)中加载制造商才能显示出来。我最初的解决方案是使用以下(未经调试的伪代码):

HTML:

<ol>
  <li *ngFor="let prod of order.toProducts">
    {{ prod.Name }}: {{ DisplayManufacturer(prod) | async }}
  </li>
<ol>

TypeScript:

public async DisplayManufacturer(prod: product) {
    let manufacturer = await this.storageService.Load(prod.manufacturerId);
    if (manufacturer) {
        return manufacturer.name + ' (' + manufacturer.address + ')';
    }
    return "";
}

这-当然-导致无限循环。

我的下一个解决方案是遍历ngOnInit内的所有订单及其所有产品,以找到制造商并将其存储在Map中,以供以后在表达式中使用。

我认为应该有一个更好的解决方案-因为这还没有结束:我还必须实现DoCheck来检查是否有任何产品阵列或制造商更改并重新加载了上述地图。而对于每个相似引用的字段,都是如此。

2 个答案:

答案 0 :(得分:1)

在替换数据之前,您不需要使用异步/等待或加载所有数据。将字段添加到product类型,并分配一个Promise或Observable来解析为所需数据。

服务

Load(id: any): any {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(`Manufacturer id [${id}], name, address`);
        }, Math.random() * 5000 + 2000);
    });
}

组件

ngOnInit() {
    for (let i = 1; i < 10; i++) {
        this.order.toProducts.push(
            { Name: 'ProdName' + i, manufacturerId: i, data: this.storageService.Load('manufacturerId#' + i) },
        );
    }
}

模板

<ol>
  <li *ngFor="let prod of order.toProducts">
    {{ prod.Name }}: {{ prod.data | async }}
  </li>
<ol>

完整的示例:https://stackblitz.com/edit/angular-gpqvuu

答案 1 :(得分:0)

您可以获得产品:

products$ = this.myService.getProducts();

然后是制造商,并将他们加入产品:

manufacturersAndProducts$ = this.products$.pipe(
  switchMap(products => forkJoin(products
    .map(product => this.myService.getManufacturerForProduct(product))
  )).pipe(
    map(manufacturers => products
      .map((product, index) => ({ product, manufacturer: manufacturers[index] }))
    )
  )
);

然后将其用于HTML

<ng-container *ngIf="manufacturersAndProducts$ | async as list">
  <div *ngFor="let item of list">
    {{ item.product.name }} is made by {{ item.manufacturer.name }}
  </div>
</ng-container>

但这是一个不好的例子,因为使用HTTP调用,您实际上并不需要这种反应式编程。例如,当产品列表每10秒左右更改一次时,此功能很有用。

要回答您的疑问,您的问题是与上下文无关的:它不应该与异步有关,而应与模板方面的良好实践有关。

您不应在模板中使用不纯函数(具有副作用的函数),否则,正如您所说的,视图将再次呈现,这将导致无限循环或充其量出现性能问题。

您应该使用一个纯函数,或者构造一个包含所有数据的完整对象(就像我在这里所做的那样,但是您不需要异步管道)