模板中 Observable collection 的 Observable
Observable of Observable collection in template
由于标题肯定不会进一步推动我的意图,这就是我正在尝试做的事情。
我想在视图中显示项目列表,这是我从后端异步获取的(我有一个服务,该服务使用名为 fetchItems()
的方法来获取它们,该方法具有 Observable<Item[]>
return类型)。
我通过设置 this.items = this.itemService.fetchItems();
.
在组件构造函数中初始化此列表
我通过 *ngFor="let item of items | async"
.
在视图中显示此项目列表
到目前为止,还不错,一切都按预期进行。
每个项目都有一个字段 subItemId
。我想用这个键来显示,在前面提到的列表中,类型 SubItem
的实际子项 object。我可以通过 this.subItemService.findById(subItemId)
得到这个项目,其中 returns Observable<SubItem>
.
我该怎么做?
我显然不能从模板中调用像 getSubItem(item: Item): SubItem
这样的组件方法,因为它会被一遍又一遍地调用。
我不想修改 itemService.fetchItem()
方法来急切地加载子项,因为它们可能在所有使用它的地方都不需要。
答案可能很明显,但我只使用 Angular (6) 几天。
您在模板中使用了 async
,这意味着模板的数据绑定是延迟加载的。所以除了对子项目再次使用 async
之外,你真的无能为力。
<div *ngFor="let item of items | async">
<span>{{(getSubItem(item: Item) | async)?.title}}</span>
</div>
上面会调用一个 returns 可观察的函数,?
意味着在读取 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
用于该父项的子项。您需要使用 ?
运算符,因为数据是延迟加载的,并且在第一次呈现项目时不存在。
您可以使用 rxjs 运算符重建 item > subitem 的父子关系。这是一个 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` });
}
}
由于标题肯定不会进一步推动我的意图,这就是我正在尝试做的事情。
我想在视图中显示项目列表,这是我从后端异步获取的(我有一个服务,该服务使用名为 fetchItems()
的方法来获取它们,该方法具有 Observable<Item[]>
return类型)。
我通过设置 this.items = this.itemService.fetchItems();
.
在组件构造函数中初始化此列表
我通过 *ngFor="let item of items | async"
.
到目前为止,还不错,一切都按预期进行。
每个项目都有一个字段 subItemId
。我想用这个键来显示,在前面提到的列表中,类型 SubItem
的实际子项 object。我可以通过 this.subItemService.findById(subItemId)
得到这个项目,其中 returns Observable<SubItem>
.
我该怎么做?
我显然不能从模板中调用像 getSubItem(item: Item): SubItem
这样的组件方法,因为它会被一遍又一遍地调用。
我不想修改 itemService.fetchItem()
方法来急切地加载子项,因为它们可能在所有使用它的地方都不需要。
答案可能很明显,但我只使用 Angular (6) 几天。
您在模板中使用了 async
,这意味着模板的数据绑定是延迟加载的。所以除了对子项目再次使用 async
之外,你真的无能为力。
<div *ngFor="let item of items | async">
<span>{{(getSubItem(item: Item) | async)?.title}}</span>
</div>
上面会调用一个 returns 可观察的函数,?
意味着在读取 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
用于该父项的子项。您需要使用 ?
运算符,因为数据是延迟加载的,并且在第一次呈现项目时不存在。
您可以使用 rxjs 运算符重建 item > subitem 的父子关系。这是一个 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` });
}
}