С rxjs Observable <Array <T>, как я могу сделать вызов службы http для каждого элемента массива и присвоить результат этого наблюдаемого свойству? - PullRequest
0 голосов
/ 09 июня 2019

В основном я пытаюсь опросить данные с 2 конечных точек для сбора участников гонки. У меня есть 2 метода в моем сервисе, которые делают запросы API, используя угловой http-клиент, и возвращают Observables. Первый метод принимает массив идентификаторов и возвращает массив основных данных участника (имя, прошедшее время, текущая контрольная точка) для каждого переданного идентификатора, а второй метод принимает один идентификатор и возвращает массив результатов из каждой контрольной точки. для этого участника

У меня есть наблюдаемая, которая является результатом первого вызова службы. Затем я передаю и отображаю это так, чтобы я мог работать с массивом, а затем делаю стандартную карту массива javascript для итерации элементов. Бит, на котором я действительно застрял, - для каждого «участника» в массиве, который соответствует условию, мне нужно сделать еще один http-вызов ко второй конечной точке и присвоить значение этого результата, наблюдаемого, свойству участника. В идеале исходная Observable должна возвращаться, как только она станет доступной, и тогда каждый участник в этом результирующем массиве будет обновлять результаты контрольной точки по завершении вызовов API.

Я только начинаю изучать rxjs, angular и ngrx, и я все еще борюсь с наблюдаемыми потоками, однако у меня есть эффект ngrx, который выглядит следующим образом

  @Effect()
  pollDataForCollection$ = this.collectionEventsActions$.pipe(
    ofType(CollectionActions.onCountdownRestarted.type),
    withLatestFrom(
      this.featuresStore$.select(collectionSelectors.selectAllFavourites),
      this.featuresStore$.select(collectionSelectors.selectExpandedFavourites)
    ),
    switchMap(([action, faves, expandedDetailIds]) => {
      const ids: number[] = faves.map(fave => fave.id);
      return this.apiService.getParticipantsById(ids).pipe(
        map((participants: Participants[]) => {
          return participants.map(participant => {
            if (expandedDetailIds.includes(participant.id)) {
              this.apiService.getParticipantDetailResults(participant.id).pipe(
                map((results: ParticipantResults[]) => {
                  return (participant.results = results);
                })
              );
            }
            return participant;
          });
        }),
        map(updates => {
          debugger;
          return CollectionActions.pollingDataSucceeded({ items: updates });
        }),
        catchError(error => of(CollectionActions.pollingDataErrored({ error })))
      );
    })
  );

Это успешно получает массив участников и проектов для каждого участника, но, что неудивительно, ничего не делает для назначения результатов участнику.

Обновление для включения рабочего решения

большое спасибо @ user2216584 за его решение

  @Effect()
  pollDataForCollection$ = this.collectionEventsActions$.pipe(
    ofType(
      CollectionActions.onCountdownRestarted.type
    )
    , withLatestFrom(
      this.featuresStore$.select(collectionSelectors.selectAllFavourites)
    )
    , switchMap(([action, faves]) => {
      const ids: number[] = faves.map(fave => fave.id);
      return this.apiService.getParticipantsById(ids);
    })
    , withLatestFrom(
      this.featuresStore$.select(collectionSelectors.selectExpandedFavourites)
    )
    , switchMap(([participants, expandedFaves]) => {
      const favesWithDetailedResults = participants.map(participant => {
        if(expandedFaves.includes(participant.id)){
            return this.apiService.getParticipantCheckpointResults(participant.id).pipe(
              map((checkpointResults: ParticipantCheckpoint[]) => {
                const participantDetail: Participant = {
                  ...participant,
                  checkpoints: checkpointResults
                }
                return participantDetail;
              })
            )
        }else{
            return of(participant)
        }
      });

      return forkJoin(favesWithDetailedResults)
    })
    , map((updates) => {
      return CollectionActions.pollingDataSucceeded({ items: updates })
    })
    , catchError(error =>
      of(CollectionActions.pollingDataErrored({ error }))
    )
  );

1 Ответ

0 голосов
/ 09 июня 2019

Это то, что вам нужно сделать - для каждого участника вам нужно собрать наблюдаемое из API данных и отправить его в массив.Этот массив должен быть набором наблюдаемых.Затем используйте этот массив в forJoin функции rxjs.Смотрите следующий код

- 

  @Effect()
  pollDataForCollection$ = this.collectionEventsActions$.pipe(
    ofType(
      CollectionActions.onCountdownRestarted.type
    )
    , withLatestFrom(
this.featuresStore$.select(collectionSelectors.selectAllFavourites)
,this.featuresStore$.select(collectionSelectors.selectExpandedFavourites)
    )
    , switchMap(([action, faves, expandedDetailIds]) => {
      const ids: number[] = faves.map(fave => fave.id);
      return this.apiService.getParticipantsById(ids);
),
switchMap(participants => {
 //for each participant map the detail api observable in an array
 const obs = participants.map(p => this.apiService.getParticipantDetailResults(participant.id));
return forkJoin(obs);
}),
map(joined => {
  // result from forkJoin will be an array of the api response in the order you added the observables. Also forkJoin only emit the value once for each of the observable it has the response; so it will wait for the response to comeback for the details for each participant 
 //now you can do whatever you want to do with this array
// may be parse it and send the success action to the store
})
...