Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I want to call two observables with the second called after the first one in Angular2

I want to call two observables with the second called after the first one.

I have one observable that is subscribed too first. Then I want the second observable nested within the first observable.

I want to combine these two subscribes below:

this.serviceA.getData()
.takeUntil(destroyed$)
.subscribe(item => {

});

this.serviceB.getData()
.takeUntil(destroyed$)
.subscribe(item => {

});

This is my attempt showing what I want to do (Updated)

  destroyed$: Subject<any> = new Subject<any>();

  ngOnInit(): void {
    this.serviceA.getData
      .takeUntil(this.destroyed$)
      .concatMap(dataA => {
        this.myDataA= dataA;    

        return this.serviceB.getData;
      })
      .takeUntil(this.destroyed$)
      .subscribe(dataB => {            

         this.myDataA.forEach(item => {
             item.visible = dataB.find(o => o.id === item.label).isVisible;
         }); 

      });
  };

  ngOnDestroy(): void {
    this.destroyed$.next(true);
    this.destroyed$.complete();
  };

The aim is to have the nested subscribe called second after the first subscribe because the data is needed from the first subscriber in the second subscribe

like image 225
AngularM Avatar asked Jan 30 '23 09:01

AngularM


2 Answers

The accepted answer is incorrect. The forkJoin will subscribe to both Observables at the same time while you want to first subscribe to the first one and after it completes subscribe to the second one.

This is typically done using the concatMap operator:

this.serviceA.getData()
  .concatMap(response => this.serviceB.getData())
  .subscribe(...)

If you want to combine the two responses use can use map after serviceB.getData().

this.serviceA.getData()
  .concatMap(responseA => this.serviceB.getData()
    .map(responseB => /* combine responseA and responseB */ ))
  .subscribe(...)
like image 136
martin Avatar answered Feb 05 '23 17:02

martin


Good Question (Y),

You need to use forkJoin docs

Runs all observable sequences in (parallel) and collect their last elements.

Example:

let character = this.http.get('https://swapi.co/api/people/1').map(res => res.json());
let characterHomeworld = this.http.get('http://swapi.co/api/planets/1').map(res => res.json());

Observable.forkJoin([character, characterHomeworld]).subscribe(results => {
  // results[0] is our character
  // results[1] is our character homeworld
  results[0].homeworld = results[1];
  this.loadedCharacter = results[0];
});

Refrence: https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs

So for your specific case you can do something like:

let obs1 = this.serviceA.getData()
let obs2 = this.serviceB.getData()

Observable.forkJoin([obs1, obs2]).subscribe(results => {
  // results[0] is our obs1
  // results[1] is our obs2
  // show the bigger array
  this.items = results[0] > results[1] ? results[0] : results[1]
});

But if you need some data dependent on the other you can do something like

showData() {
  let firstData;
  this.serviceA.getData()
    .map((firstNeededData) => {
      firstData = firstNeededData
      return this.serviceB.getData()
    })
    .subscribe(secondNeededData => {
      // I need to show the bigger 
      this.theBigger = secondNeededData > firstData ? secondNeededData : firstData
    })

}
like image 45
Microsmsm Avatar answered Feb 05 '23 17:02

Microsmsm