Я собираюсь объяснить контекст, который у меня есть, прежде чем объяснить проблему проектирования службы с Angular и RxJS.
У меня есть один объект с этой моделью:
{
id: string;
title: string;
items: number[];
}
Я получаюкаждый объект этого типа (называемый «элемент») - от GET /element/:id
Каждый элемент имеет items: number[]
, который содержит массив чисел, и у каждого числа есть URL, поэтому я делаю новый GET /element/:id/:itemNumber
для каждогономер и вернуть детали детали.Модель детализации выглядит следующим образом:
{
idItem: string;
title: string;
}
Так что в моем сервисе я хочу предоставить компонентам метод, который будет возвращать Observable, он получит массив объектов, где у каждого объекта есть элементмодель с одним дополнительным свойством, которое будет массивом ее подробных элементов.Итак, я собираюсь показать, что у меня есть:
Служба:
getElement(id: string): any {
return this.http.get<Element>(this.basePath + `/element/${id}`).pipe(
map(element => this.getAllItemsDetail(element))
}
getAllItemsDetail(element: Element): any {
return of(...element.items).pipe(
map(val => this.getItemDetail(element.id, val)),
concatAll()
);
}
Моя проблема в том, что я не понимаю, как я могу, в RxJS, после map(element => this.getAllItemsDetail(element))
в методе getElement
объедините возвращаемый им массив элементов и предыдущий элемент, который у меня есть, перед картой, содержащей объект элемента.Мне нужно добавить «что-нибудь» после этой карты, чтобы вычислить Object.Assign для объединения обоих объектов.
EDIT
С ответом @ chiril.sarajiu,он дает мне более чем одну подсказку, с помощью switchMap
я могу отобразить наблюдаемое (map
используется для объектов, "выполнить вычисление с объектом результата").Так что мой код, это не самая красивая версия, которую я знаю ..., я попробую, но она работает.Таким образом, окончательный код выглядит следующим образом:
getElement(id: string): any {
return this.http.get<Element>(this.basePath + `/element/${id}`).pipe(
switchMap(element => this.getAllItemsDetail(element)),
map(result => { return Object.assign({}, result.element, {itemsDetail: result.items})})
);
}
getAllItemsDetail(element: Element): any {
const results$ = [];
for (let i = 0; i < element.items.length; i++) {
results$.push(this.getItemDetail(element.id, element.items[i]));
}
return zip(...results$).pipe(
map(items => { return Object.assign({}, { element, items })})
);
}
Помните, что zip не будет выдавать значения, если результаты $ пустые, в этом случае вы можете добавить (не определено) к массиву результатов $и после учтите, что предметы будут [undefined]