Наблюдаемый из наблюдаемой коллекции в шаблоне - PullRequest
0 голосов
/ 28 мая 2018

Поскольку заголовок определенно не соответствует моим намерениям, вот что я пытаюсь сделать.

Я хочу отобразить список элементов в представлении, который я получаю асинхронно из серверной части (яу меня есть служба с методом 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 голосов
/ 28 мая 2018

Вы можете восстановить родительские отношения дочернего элемента item> subitem, используя операторы rxjs.Вот пример :

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` });
  }
}
0 голосов
/ 28 мая 2018

Вы использовали async в шаблоне, что означает, что привязка данных для шаблона загружена лениво.Таким образом, вы ничего не можете сделать, кроме как снова использовать async для дочернего элемента.

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

Вышеприведенное вызвало бы функцию, которая возвращает наблюдаемое, а ? означает, что результат необязателен передсвойство 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 для подэлемента этого родителя.Вам нужно будет использовать оператор ?, поскольку данные загружаются лениво и не будут существовать при первом отображении элементов.

...