I have the following code which consists of multiple subscribes. What I need to achieve is like this :
My question : is there any better way to perform these nested subscription? is it a good practice to do like this?
this.activatedRoute.data.pipe(
map((data) => {
this.user = data['user'];
this.product = data['product'];
return this.product;
})
).subscribe(result => {
if (this.product === null) {
this.router.navigate(['/home']);
} else {
this.displayCurrency = this.dataService.getCurrencySymbolById(this.product.currency);
this.userService.getUser(this.product.createdBy).subscribe(seller => {
this.seller = seller;
this.ratingService.getRatingByUserId(seller.id).subscribe(rating => {
this.rating = rating;
})
});
}
});
No it is not good to call a subscribe inside a subscribe. Why? Well because this is not how functional programming is supposed to work. You're not thinking functionally you're thinking procedurally.
Nested subscriptions in use A very common use case is to request a data object from our API to then use some of its properties to request a few more related entities. Finally, we combine the received objects to fill our view. In Angular we could implement it like this: this. route.
Subscribe() is a method in Angular that connects the observer to observable events. Whenever any change is made in these observable, a code is executed and observes the results or changes using the subscribe method. Subscribe() is a method from the rxjs library, used internally by Angular.02-Jan-2022.
If you don't subscribe nothing is going to happen. It's good to know that when you subscribe to an observer, each call of subscribe() will trigger it's own independent execution for that given observer. Subscribe calls are not shared among multiple subscribers to the same observable.
Technically, nesting subscribe works, but there is a more elegant and systematic way of handling this. You should really learn more about your RxJS operators.
First, we use mergeMap to map over the observable values from the activatedRoute into an inner observable.
Then, we use forkJoin to combine the observables into a single value observable, thus returning the value itself on the .subscribe()
this.activatedRoute.pipe(
tap(data => console.log(data)),
mergeMap(data => {
if (data.product === null) {
this.router.navigate(['/home']);
} else {
const getCurrency = this.dataService.getCurrencySymbolById(data.product.currency);
const getUsers= this.userService.getUser(data.product.createdBy);
const getRatings = this.ratingService.getRatingByUserId(seller.id)
return forkJoin(getCurrency, getUsers, getRatings);
}
})
).subscribe(res => {
console.log(res[0]); // currency
console.log(res[1]); // user
console.log(res[2]); // ratings
}
EDIT: Turns out I have misread the original question, as getRatingsByUserId is dependent on getUser. Let me make some changes. Either ways, I will leave the code above as it is, as it is good for OP's reference.
this.activatedRoute.data.pipe(
switchMap(data => {
this.user = data['user'];
this.product = data['product'];
return this.userService.getUser(this.product.createdBy);
}),
switchMap(data => {
if (this.product === null) {
this.router.navigate(['/home']);
} else {
this.seller = seller;
return this.userService.getRatingByUserId(this.product.createdBy);
}
})
).subscribe(res => {
console.log(res)
// handle the rest
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With