I have a fetchDrives method which will return an observable which on subscription will return a list of drives
this.fetchDrives(points).subscribe(drives => {
console.log(drives);
});
Assume The drives array which I got on subscription look some what like this
[ {driveId: 1}, {driveId: 2}, {driveId: 3} ]
Now I need to use the driveId one by one and make three calls ( three because length of the drives array is 3 ) by passing driveId to each api call.I need to pass driveId to the below method one at a time and get the lat and lon and store the result of three calls in an array.
this.getLatLong(driveId).subscribe( res => console.log(res))
The res will contain an object like { lat: 12, lon: 54 }
I don't want to do two subscriptions, is there a way I can use the Rxjs operators and achieve this with one subscription using the result of previous observable, loop through the drives array and make three calls to getLatLong
method using mergeMap
as the sequence of the calls doesn't matter and store the result of those three calls in an array?
I tried using scan operator to loop through but failed to use it to get the desired output
Thanks for the help in advance :)
If the order of the requests doesn't matter, you could use RxJS forkJoin
method to make the calls simultaneously. I've also used switchMap
operator to switch the observable once the source observable (this.fetchDrives(points)
) emits. Try the following
locations: any;
this.fetchDrives(points).pipe(
switchMap((drives) => {
let source = Object.create(null);
for (let i = 0; i < drives.length; i++) {
source[drives[i]['driveId']] = this.getLatLong(drives[i]['driveId']);
}
return forkJoin(source);
})
).subscribe(
response => {
this.locations = response;
},
error => {
// handle error
}
);
Variable locations
will be of the form
// 'driveId': { lat: 12, lon: 54 }
{
'1': { lat: 12, lon: 54 },
'2': { lat: 12, lon: 54 },
'3': { lat: 12, lon: 54 }
}
To return an array of objects from forkJoin
you could send in an array of observables as the argument. For eg. forkJoin([obs1, obs2, ...])
. In the previous case we were sending an object as the argument (forkJoin({'name1': obs1, 'name2': obs2, ...})
, so the output will also be an object.
locations: any = [];
this.fetchDrives(points).pipe(
switchMap((drives) => {
return forkJoin(drives.map(drive => this.getLatLong(drive['driveId'])));
})
).subscribe(
response => {
this.locations = response;
},
error => {
// handle error
}
);
locations
will be of the form
[
{ lat: 12, lon: 54 },
{ lat: 12, lon: 54 },
{ lat: 12, lon: 54 }
]