#javascript #angular #typescript #rxjs
#javascript #угловой #typescript #rxjs
Вопрос:
Я собираюсь объяснить контекст, который у меня есть, прежде чем объяснить проблему проектирования сервиса с помощью Angular и RxJS.
У меня есть один объект с этой моделью:
{
id: string;
title: string;
items: number[];
}
Я получаю каждый объект этого типа (называемый «элемент») через GET /element/:id
У каждого элемента есть элемент, items: number[]
который содержит массив чисел, и у каждого числа есть URL, поэтому я создаю новый GET /element/:id/:itemNumber
для каждого числа и возвращаю детали элементов. Эта модель детализации элемента похожа:
{
idItem: string;
title: string;
}
Итак, в моем сервисе я хочу предоставить компонентам метод, который вернет наблюдаемое, он получит массив объектов, где каждый объект имеет модель элемента с одним дополнительным свойством, которое будет представлять собой массив его подробных элементов. Итак, я собираюсь показать, что у меня есть:
Служба:
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
методе объединить возвращаемый им массив items и предыдущий элемент, который у меня есть перед картой, на которой есть объект element. Мне нужно добавить «что угодно» после этой карты, чтобы вычислить объект.Назначьте объединение обоих объектов.
Редактировать
С ответом @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 не будет выдавать значения, если results $ пуст, в этом случае вы можете добавить of (undefined) в results $ array и после учесть, что элементы будут [undefined]
Ответ №1:
Для отображения другого наблюдаемого вам следует использовать switchMap
function вместо map
So
getElement(id: string): any {
return this.http.get<Element>(this.basePath `/element/${id}`).pipe(
switchMap(element => this.getAllItemsDetail(element))
}
Обновить
Рассмотрим эту статью medium
Комментарии:
1. Хорошо, но в чем разница? После switchMap как я могу использовать в канале элемент, возвращенный на первое место (element), и объекты, возвращенные getAllItemsDetail?? Это моя проблема, мне нужны оба в этом методе, чтобы выполнить слияние и вернуть его, я думаю, с помощью of … вы меня понимаете?
2. Чуть позже я приведу пример на stackblitzz.
3. Спасибо, чувак! Я понял, не волнуйтесь, я использовал switchMap, как и вы, и в методе GetAll … я сопоставил оба объекта, и в switchMap, конечно, есть оба, не тратьте свое время, потому что вы очень помогли, и оно у меня есть; D
4. Рад помочь! Хотелось бы увидеть реализацию, если она случайно есть на github : D
5. приятно, но только одна вещь, здесь
{element: element, items: items}
вы можете опустить вторые элементы, это будет работать без них{ element, items }