I have a piece of code that looks like this
getInformations().subscribe(
informations => {
let subs = [];
for (const information of informations) {
subs.push(getOtherDetails(information.id));
}
forkJoin(subs).subscribe(response => {
//How can I Associate Information Id With The Response
howToAssociateIdWithResponse();
}}
);
Situation – I want to tie the responses of my second call with the ids of my first call, but I am running into issues.
Attempted – I tried the following but that seems to be throwing error
let subs: {[x:number]: Observable<any>}[] = [];
subs.push({information.id: getOtherDetails(info.id)})
but when I subscribed I got an error stating You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
Update – 1 After following @BizzyBob suggestion, the code looks like the following but my other logic is running before the subscription completes it’s job. Here is what I mean
async ngOnChanges(){
await getData(); //How to make sure below method only executes when this is really done.
await useInformationReceivedFromgetData();
}
async getData(){
getInformations().subscribe(
informations => {
let subs = [];
for (const information of informations) {
subs.push(getOtherDetails(information.id).pipe(
map(data => ({ id: information.id, data })) // <---
));
}
forkJoin(subs).subscribe(objects => {
objects.forEach(({id, data}) => { /* saved to an arrray */ });
});
}
);
}
2
Answers
You can make each "getOtherDetails observable" emit an object with the
id
and responsedata
:Note, you can simplify your code by using .map() instead of creating a
subs
array and pusing to it:Also, putting subscribes inside of subscribes is bad news. You’d be better off to use a Higher Order Mapping Operator that will handle an "inner subscription" for you. In this case, we can use
switchMap
to handle subscribing / unsubscribing to your forkJoin observable:You can lean way harder on
rxjs
and its pipe operators.Consider following code:
It might look a bit crazy on first glance, but it reflects what you want to do in an "rxjs way".
detail
observablesdetail
response with the original response using themap
pipeThis way enables you to easily display the result in an angular template using the
async
pipe. So if your goal is to display the combined values, you don’t have to subscribe in your component logic at all, which is a gain because you don’t have to think about performance or memory leaks. Read this for more info