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 */ });
});
}
);
}
You can make each "getOtherDetails observable" emit an object with the id
and response data
:
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}) => { /* use id and data here */ });
});
}
);
Note, you can simplify your code by using .map() instead of creating a subs
array and pusing to it:
getInformations().subscribe(
informations => {
const subs = informations.map(
({id}) => getOtherDetails(id).pipe(map(data => ({ id, data })))
);
forkJoin(subs).subscribe(responses => {
responses.forEach(({id, data}) => { /* use id and data here */ });
});
}
);
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:
getInformations().pipe(
map(informations => informations.map(
({id}) => getOtherDetails(id).pipe(map(response => ({ id, data })))
),
switchMap(requests => forkJoin(requests))
).subscribe(
responses => responses.forEach(({id, data}) => { ... })
);