Как обрабатывать вложенные HTTP-запросы в Angular 7?

У меня есть общий сервис для получения данных с сервера. Когда ответ получен, я использую функцию сопоставления для сопоставления чистых данных JSON с требуемой моделью. Для некоторого типа класса в функции сопоставления мне нужно получить дополнительные данные с сервера. Как я могу заставить функцию картографа ждать второго запроса?

Это моя функция получения:

 getChildren(params: ITreeQueryParams): Observable<Optional<T[]>> {
    params.id = isPresent(params.id) ? params.id : 0;
    params.parentId = isPresent(params.parentId) ? params.parentId : 0;
    params.isRoot = isPresent(params.isRoot) ? params.isRoot : false;
    params.additionalId = isPresent(params.additionalId) ? 
    params.additionalId : 0;
    return this.http.get<IListResponse<T>>
(`${this.resourceUrl}/getChildren/${params.id}/${params.parentId}/${params.isRoot}/${params.additionalId}`,
      {
        observe: 'response'
      }).pipe(map((resp) => this.mapResponse(resp,this.model)));
  }

Это моя функция сопоставления:

 protected mapResponse(resp: any, model: IAsset): void {
    if (resp) {
      this.anotherTreeService.getNodeDetail(resp.id, resp.isRoot).subscribe(res => {
        model.additionalData = {canEdit: res.length > 0 ? true : false};
      });
      if (resp.name) {
        model.title = resp.name;
      }
    }
  }

person Mostafa Farhani    schedule 31.07.2019    source источник
comment
используйте mergeMap   -  person Austaras    schedule 31.07.2019
comment
Observable.combineLatest или Observable.forkJoin в RXJS лучше   -  person Shohel    schedule 31.07.2019


Ответы (2)


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

this.myFirstService.getById(id).pipe(
   map(data => jsonToMyModel(data)),
   tap(model => this.data = model),
   switchMap(model => {
      return this.mySecondService.getListById(model.id)
   }),
   tap(secondData => this.data.list = secondData)
).subscribe()

Это меняет то, чего вы точно пытаетесь достичь, поскольку все данные могут оказаться в одной модели, возвращаемой Observable, с помощью forkJoin() или mergeMap(). Любой из этих операторов используется в подобных ситуациях.

Надеюсь это поможет. Более четкий и прямой пример того, что вы хотите, потребует более полного вопроса с некоторыми примерами того, что вы хотите и что вы пробовали.

person Bjorn 'Bjeaurn' S    schedule 31.07.2019

Если я вас правильно понимаю, вы просто хотите сделать один запрос и сделать для него подзапросы.

Для этой цели вы можете использовать switchMap и forkJoin, если вам нужно выполнить много подзапросов.

Вот как вы можете переписать свой код (я напишу упрощенную версию)

getChildren() {
  this.http.someRequest.pipe(
    tap(response => {
        if (resp.name) {
          model.title = resp.name;
        }
    }),
    switchMap(response =>
        forkJoin(
            response.map(r => this.http.someRequest(r))
        )
    )
  )
}

Что делает switchMap, так это то, что после каждого исходного выброса (вашего первого наблюдаемого) он подписывается на возвращаемый наблюдаемый в обратном вызове (если он уже был подписан, он сначала отписывается от наблюдаемого обратного вызова).

forkJoin работает как Promise.all. Вы можете передать туда массив, объект или несколько наблюдаемых (теперь устарели), а при подписке вы получите либо массив, либо объект.

Обратите внимание, что forkJoin выдает последнее значение, выдаваемое каждым наблюдаемым объектом только после завершения всех наблюдаемых. Кроме того, если какой-либо наблюдаемый объект завершается без выдачи значения, forkJoin также завершается без выдачи значения. Поскольку все http.whatever являются наблюдаемыми с одним next и непосредственным complete после этого, вам не нужно об этом беспокоиться.

Также, если какие-либо наблюдаемые ошибки forkJoin ошибок.

person Sergey    schedule 31.07.2019