Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.0k views
in Technique[技术] by (71.8m points)

rxjs - Angular Subscribe within Subscribe

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

    });
  }
});
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...