在模板中可观察到Observable集合

时间:2018-05-28 14:37:34

标签: angular rxjs observable angular-template

由于标题肯定不会进一步促进我的意图,这就是我想要做的事情。

我想在视图中显示一个项目列表,我从后端异步获取(我有一个名为fetchItems()的方法的服务来获取具有Observable<Item[]>返回类型的方法。
我通过设置this.items = this.itemService.fetchItems();在组件构造函数中初始化此列表 我通过*ngFor="let item of items | async"显示视图中的项目列表。

到目前为止,这么好,一切都按预期工作。

每个项目都有一个字段subItemId。我想使用此键在上述列表中显示类型为SubItem的实际子项对象。我可以通过this.subItemService.findById(subItemId)获取此项目,该项目会返回Observable<SubItem>

我该怎么做呢?

我显然不能从模板中调用getSubItem(item: Item): SubItem这样的组件方法,因为它会被反复调用。
我不想修改itemService.fetchItem()方法以急切加载子项,因为它们可能在任何使用它的地方都不需要。

答案可能很明显,但我只与Angular(6)合作了几天。

2 个答案:

答案 0 :(得分:1)

您在模板中使用了async,这意味着模板的数据绑定是延迟加载的。因此,除了对子项目再次使用async之外,您无法做任何事情。

<div *ngFor="let item of items | async">
    <span>{{(getSubItem(item: Item) | async)?.title}}</span>
</div>

上面会调用一个返回observable的函数,?表示在读取title属性之前结果是可选的。

你可以看到这里的限制是什么。如果您需要多个属性,则必须执行另一个async操作。这不太实际。

您需要加载模板的所有数据或更改API后端以在单个API调用中获取所有数据。

你最终会需要这样的东西。

 this.itemService.fetchItems().first().subscribe((items)=>{ 
       this.items = items;
       this.items.forEach((item)=>{ 
            this.getSubItem(item).first().subscribe((sub)=> {
                 // attach the child to the parent item
                 item.child = sub;
            });
       });
 });

然后,您可以在模板中迭代items,并使用item.child作为该父项的子项。您需要使用?运算符,因为数据是延迟加载的,并且在第一次呈现项目时不会存在。

答案 1 :(得分:1)

您可以重建项目的父子关系&gt; subitem使用rxjs运算符。这是一个example

export class AppComponent {
  name = 'Angular 6';
  itemsWithSubItems: Observable<any>;
  subItems: Observable<any[]>;
  getItems(): Observable<{ subItemId: number, itemName: string, subItem?: any }[]> {
    return of([{ subItemId: 1, itemName: 'One'}, { subItemId: 2, itemName: 'Two' }, { subItemId: 3, itemName: 'Three' }, { subItemId: 4, itemName: 'Four' }])
      .pipe(shareReplay());
  }

  constructor() {
    this.itemsWithSubItems = this.getItems().pipe(
        flatMap(items => from(items)),
        switchMap(item => this.getSubItemById(item.subItemId), 
          (outerValue, innerValue, outerIndex, innerIndex) => {
            outerValue.subItem = innerValue;
            return outerValue
          }),
        toArray());
    this.itemsWithSubItems.subscribe(x => console.log('x', x))
  }

  getSubItemById(subItemId: number): Observable<{name: string}> {
    return of({ name: `${subItemId}-SubItem` });
  }
}