Is it correct to call one observable in another?

Viewed 147

I have three services and each of them make a simple API call and return the value to the client, each API call depends of some data get from other.

Like the first Observable i'm subscribed get users data then with the data get from it i can call the Observable which gets the parameters by passing two values got from the first Observable, then the third Observable needs same data from the 1st Observable and one parameter got from the 2nd one.

So my code looks like this:

 ngOnInit(): void {
    this.profiloService
      .profilo(this.idNegozio)
      .subscribe((profilo: Profilo) => {
        this.profilo = profilo;

        this.menuService
          .menu(profilo.idNegozio, profilo.piva, 'IT')
          .subscribe((menu: Menu[]) => {
            this.menu = menu;

            this.pluService
              .plu(profilo.idNegozio, profilo.piva, 'IT')
              .subscribe((plus: Plu[]) => {
                this.plus = plus;
                this.filterPlu(menu.id);
              });
          });
      });
  }

Is it a good approach to subscribe to Observable from another observable? If not what should be the best practice?

3 Answers

You should almost never do a subscribe inside another. Do something like this:

  ngOnInit(): void {
    this.profiloService
      .profilo(this.idNegozio)
      .switchMap((profilo) =>
        forkJoin([
          of(profilo)
          this.menuService.menu(profilo.idNegozio, profilo.piva, 'IT'),
          this.pluService.plu(profilo.idNegozio, profilo.piva, 'IT')
        ])
      )
      .subscribe(([profilo,menu,plus]) => {
        this.profilo = profilo
        this.plus = plus
        this.filterPlu(menu.id)
        this.menu = menu
      })
  }

Since all http calls are sequential and you want to use first http response in 3rd call, you should use ConcateMap as follow,

ngOnInit(): void {
    this.profiloService.profilo(this.idNegozio)
        .pipe(
            concatMap((profilo: Profilo) => this.menuService.menu(profilo.idNegozio, profilo.piva, 'IT')
                .pipe(
                    // you should be able to access profilo here
                    concatMap((menu: Menu[]) => this.pluService.plu(profilo.idNegozio, profilo.piva, 'IT')
                        .map((plus: Plu[]) => {
                            this.plus = plus;
                            this.filterPlu(menu.id);
                        })
                    )
                )
            ).subscribe()

}
  

NOTE: Kindly ignore any parenthesis mistake

no, it is not correct. You can get timing problems.

You can combine the observables with an operator like switchMap or forkeJoin ore something else.

Never ever do a subscribe in an other subscribe. :-)

And dont forget eo unsubscribe in ngOnDestroy.

See examples here: Is it good way to call subscribe inside subscribe?

Related