0

I have a nested subscription in angular component. I can't share the code with you, but I'll try to explain the situation I'm facing. The situation is like this

ParentComponentA

result:any;
mystatus: boolean = false;
@ViewChild(ChildComponentA): childComponentA;

this.myService.getResult().subscribe(res =>{
    
   this.result = res;

   // in the first subscribe there will be a lot of calculations based on res
   /*the second service  will take one of the 
    values as an argument which will be there in res, let's say a flag*/

   this.mySecondService.getStatus(this.result.flag).subscribe(flagSatus => {

    this.myStatus = flagStatus; //flagStatus will return true value

  /*now here I have a function named myFunction, which will use this.results
    values and flagStatus to do some calculation*/

    myFunction(this.res.profile, this.myStatus)
             });
      });

  myFunction(profile, status) {
  /* here childComponentA is coming undefined 
     when I'm printing in it console therefore it is not going in if condition*/
  if(this.childComponentA) {
   }
 }


HTML template A
<div *ngIf="myStatus">
  <! -- child-comp is selector of ChildComponentA -->
   <child-comp> </child-comp>
</div>

Now, this is all working fine, but the flagStatus which I'm getting from inner subscription, I'm using it in html template. The childComponentA is being displayed, but when I do console.log(this.childComponentA) it is coming undefined. This is what my exact problem is, this may be because my initially value of myStatus is false. But when I'm putting whole innersubscription in setTimeOut, everything is working fine, it's going in if condition of myFunction also.

To avoid using setTimeOut, I would like to use rxjs to achieve what I'm trying to do in an efficient manner. I looked up everywhere but couldn't find a example which is similar to mine. From what I found is, we can use switchMap to do what I want. My question is how exactly can I use it or are there any other operators which I can use? Please help me with this.

  • 4
    As a general rule of thumb you should never have a subscribe inside another subscribe in rxjs. Instead you should use a flattening operator to jump from one observable to another. The four flattening operators are switchMap, mergeMap, concatMap and exhaustMap. Usually switchMap or mergeMap will do the job. It can be hard to learn how to use them, but it is definetly worth it. There are several articles on rxjs flattening operators / strategies if you Google it. – SnorreDan Jun 26 '20 at 18:11
  • I have a recent talk about this topic that may help. You can find the slides here: https://docs.google.com/presentation/d/1cv9j9EdHrlN8GPMqZaqAXOmIDQ3Nh5l_vZmHETEIaq8/edit?usp=sharing (It doesn't look like they've posted the recording of the talk yet.) – DeborahK Jun 26 '20 at 23:14

3 Answers3

1

You can use mergeMap for subscribing multiple Observable.

const result1$ = this.myService.getResult();
result1$.pipe(
  mergeMap(res => this.mySecondService.getStatus(res.flag).pipe(flagSatus => {
    this.myFunction(res, status);
  })));
Durgesh Pal
  • 695
  • 5
  • 13
  • Thanks for the help, but would you be able to elaborate your answer please. and where would I put all my calucations which is happening in first subscription? –  Jun 26 '20 at 19:23
  • 1
    Instead of `res => this.mySecondService.getStatus(...)...` you can make the callback function multiple lines like this: `res => { // your calculations here; return this.mySecondService.getStatus(...)...}` – DeborahK Jun 26 '20 at 23:24
0

you can use switchMap because you are trying to get a result from an observable based on another result from another observable. you can read more about switchMap here. https://www.learnrxjs.io/learn-rxjs/operators/transformation/switchmap

Muhannad
  • 168
  • 1
  • 1
  • 8
0

I've solved this using Rxjs subject, it acts as an event emitter when the observable finishes. If it makes sense to have the last value saved (like if you have an id that will be used in other services) you can use a behaviourSubject. What is the difference between Subject and BehaviorSubject?

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

 mySubject = new BehaviorSubject(null);

// This would be the first request that loads data
getData() {
return this.http.get<any>(Services, options).map(
  res => {
    console.log('res from service', res);
    this.mySubject.next(res});        
  });
}

Now if you have another component that needs this data and was previously loaded, it will still be available

this.service.mySubject.subscribe( (res:any) => {
    this.http.get<any>(res.someParam , options).map(
    ....
  });
}
Jaime FH
  • 138
  • 3
  • 13