Basically I'm trying to poll data from 2 endpoints for a collection of participants in a race. I have 2 methods in my service that make api requests using angular http-client and return Observables. The first method takes an array of Ids and gets back an array of the basic participant data (name, elapsed time, current checkpoint) for each Id that was passed and the second method takes a single Id and returns an array of results from each checkpoint for that participant
I have an Observable that is the result of the first service call. I then pipe and map this so that I can work with the array and then do a standard javascript array map to iterate the elements. The bit that I'm really stuck on is for each 'Participant' in the array that matches a condition, I need to make a further http call to the second endpoint and assign the value of that resulting observable to a property of the Participant. Ideally the original Observable would return as soon as it's available and then each participant in that resulting array would update with the checkpoint results as the api calls complete.
I'm only just starting learning rxjs, angular and ngrx and I'm still struggling a fair bit with Observable streams, however I've got an ngrx effect that looks like this
@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 })))
);
})
);
This successfully gets the Array of participants and projects to each participant but, unsurprisingly, does nothing to assign results to the participant.
Update to include working solution
many thanks to @user2216584 for his solution
@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 }))
)
);