Возвращает объединенный объект, состоящий из двух разных наблюдаемых объектов с зависимостями с помощью RxJS

#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 }