Issue
I have these 3 Observables from 3 different Services (3 API calls):
this.gs.getLocationName().subscribe((loc) => this.locationName = loc);
this.gs.getLocationInfo(this.locationName).subscribe((data) => {
this.lat = data.results.geometry.location.lat;
this.lon = data.results.geometry.location.lng;
});
this.ws.getWeatherByCoordinates(this.lat, this.lon).subscribe((data) => ...);
As you can see it depends on the previous Observable, so I want to run them one by one.
I know how to "combine" 2 Observable with a pipe and mergeMap for example but have a problem with 3
My solution is like this:
this.gs
.getLocationName()
.pipe(
tap((loc) => {
this.locationName = loc;
}),
mergeMap((loc) => {
return this.gs.getLocationInfo(this.locationName);
})
)
.pipe(
tap((data) => {
this.lat = data.results[0].geometry.location.lat;
this.lon = data.results[0].geometry.location.lng;
})
)
.subscribe((data) => {
this.ws.getWeatherByCoordinates(this.lat, this.lon).subscribe((data) => ...);
});
It works though I am not sure if it is good practice to have a Subscription in a Subscription?
So my next solution would be this:
this.gs
.getLocationName()
.pipe(
tap((loc) => {
this.locationName = loc;
}),
mergeMap((loc) => {
return this.gs.getLocationInfo(this.locationName);
})
)
.pipe(
tap((data) => {
this.lat = data.results[0].geometry.location.lat;
this.lon = data.results[0].geometry.location.lng;
}),
concatMap((data) => {
return this.ws.getWeatherByCoordinates(this.lat, this.lon);
})
)
.subscribe((data: WeatherModel) => {
...
});
This also works but I am also not sure if I did it correctly. Not sure if concatMap is the way to goo but it works for me at least.
Any tips how I can improve my code quality?
Solution
You were doing well, continue with mergeMap
. You can mergeMap
more than one Observable
this.gs.getLocationName().pipe(
tap(loc => this.locationName = loc),
mergeMap(locationName => this.gs.getLocationInfo(locationName)),
tap(data => {
this.lat = data.results.geometry.location.lat;
this.lon = data.results.geometry.location.lng;
}),
mergeMap(data => this.ws.getWeatherByCoordinates(this.lat, this.lon))
).subscribe((data) => {
...
});
Furthermore, if you will not be using the properties locationName
, lat
and lon
, you can reduce the above to
this.gs.getLocationName().pipe(
mergeMap(loc => this.gs.getLocationInfo(locationName)),
map(data => ({
lat : data.results.geometry.location.lat,
lon : data.results.geometry.location.lng;
})),
mergeMap(({lat, lon}) => this.ws.getWeatherByCoordinates(lat, lon))
).subscribe((data) => {
...
});