2

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?

Kasper Juner
  • 832
  • 3
  • 15
  • 34

3 Answers3

2

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
      })
  }
delashum
  • 801
  • 7
  • 16
2

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

micronyks
  • 54,797
  • 15
  • 112
  • 146
  • is there any main difference between concatMap and switchMap with forkJoin? as by testing @delsashum solution it's working as well and whole data is load properly at the same time – Kasper Juner Jul 28 '20 at 06:34
  • I've just read that concatMap is good to do things in sequence while waiting for completion and if i need cancellation logic i should go for switchMap, but in my case where even switchMap is working well should i anyway switch to concatMap? – Kasper Juner Jul 28 '20 at 06:46
  • 1
    It depends on the Use case. `switchMap` is also fine. But since your calls are in sequential order, it is preferred to use `concateMap` – micronyks Jul 28 '20 at 09:12
1

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?