Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Subscribe within Subscribe

Tags:

angular

rxjs

I have the following code which consists of multiple subscribes. What I need to achieve is like this :

  1. Subscribe to activatedRoute to get User and Product data.
  2. With the product data returned, subscribe to getSeller service by using the product data.
  3. Subscribe to getRating service by using the seller data returned.

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;
      })

    });
  }
});
like image 258
scholarwithfire Avatar asked Apr 01 '19 03:04

scholarwithfire


People also ask

Is it good way to call subscribe inside subscribe?

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.

What is nested subscription?

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.

What is .subscribe in Angular?

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.

What happens if you don't subscribe to an observable?

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.


1 Answers

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
})
like image 130
wentjun Avatar answered Sep 30 '22 13:09

wentjun