I want to call the first service to query for some data (returns an array of results), and then make another call to a second service to get more data for each of those results. The results from each service call should be combined and returned and displayed in a single list. I think I understand how that part works.
The part I was less sure of was the requirement to be able to display the results from the first service call immediately when available. The UI should display loading indicators for the fields which come from the second service call before that data is available.
The only thing I can think of is to add "tap" rxjs operators after the first service call and the second service call which emit events on a new subject and the UI could listen to the _documents$ Subject to show the data after the first call, and show the combined data after the second call.
Are there any best practices for handling this scenario? Am I missing another pattern or rxjs operator that would make this simpler?
_documents$: BehaviorSubject<DocumentSearchSomething[]> = new BehaviorSubject([]);
private documentSearchQuery$ = new Subject<string>();
constructor(private store: Store, private http: HttpClient) {
this.documentSearchQuery$.pipe(
switchMap((query) => {
return this.http.get<any[]>(`https://my_api.com/service_1?q=${encodeURIComponent(query)}`)
.pipe(
tap(service_1_results => this._documents$.next(service_1_results)),
switchMap(service_1_results => {
// make call to service 2 to get more data for each result, pass in id of every result
return this.http.post<any[]>(`https://my_api.com/service_2`, {
ids: service_1_results.map(r => r.id)
}).pipe(
map(service_2_results => {
// combine service_1_results with service_2_results
const combined = service_1_results.map(r1 => {
const r2 = service_2_results.find(c => c.id === r1.id);
return {...r1, ...r2};
});
return combined;
}),
tap(combined_results => this._documents$.next(combined_results))
);
})
);
}),
).subscribe();
}