1

Currently I am making 3 different API calls which are below like this:-

//API Call1
getUserById(id){
return this.http
      .get(`${environment.userAPI}/user/${Id}`, { headers: this.headers })
      .pipe(
        catchError(err => {
          return throwError(this.errorHandler.handleError(err));
        }),
      );
}
//API Call 2:-
getTeamById(id){
return this.http
      .get(`${environment.TEAM_API}/team/${Id}`, { headers: this.headers })
      .pipe(
        catchError(err => {
          return throwError(this.errorHandler.handleError(err));
        }),
      );
};
////API Call 3:-
getGroupById(id){
return this.http
      .get(`${environment.GROUP_API}/group/${Id}`, { headers: this.headers })
      .pipe(
        catchError(err => {
          return throwError(this.errorHandler.handleError(err));
        }),
      );
};

//Now I am making all the Three API calls at once using forkJoin in the below way:-
forkJoin([getUserById(1), getTeamById(1),getGroupById(1)]).pipe(
      catchError(this.getCatchError)
    )
.subscribe([res1,res2,res3]=>{
  console.log(res1,res2,res3)
})

Now I am having a requirment where using res1 i need to check one condition and make another API call and combine with the above 3 results and my condition is on API call 1 when we get user details i need to check one field team-leader which contains one Id and based on that Id i need to make another API call which is like below:-

////API Call 3:-
getLeaderById(id){
return this.http
      .get(`${environment.Leader_API}/leader/${Id}`, { headers: this.headers })
      .pipe(
        catchError(err => {
          return throwError(this.errorHandler.handleError(err));
        }),
      );
};

I am achieving the above requirement in the below way:-

forkJoin([getUserById(1), getTeamById(1),getGroupById(1)]).pipe(
      catchError(this.getCatchError)
    )
.pipe(
mergeMap(res => 
if(res[0]?.teamLeaderId){
   return getLeaderById(res[0]?.teamLeaderId).//Here I am getting res as undefined
} else{
  return res;
}
)
)
.subscribe([res1,res2,res3,res4]=>{
  console.log(res1,res2,res3,res4);//I am never ever reaching this line of code
})

Is there any mistake I am doing? By the end when all API calls are done I need to have 3 results as mandatory and 4th one is optional based on condition. I am new to RXJS. Note:- I am using the above code in Angular9 using typescrip

2 Answers2

1

The issue here is most likely in the response of the mergeMap, the thing that merge map is doing is to return one value to the source observable each time the source emits. In your case with the forkJoin operator the source observable emits only once, so you will go just once in the mergeMap and as an input argument inside the mergeMap you will have the array of 3 responses that are coming from the forkJoin.

After that when you go in the if/else block there are two options:

1 If res[0]?.teamLeaderId == true We will return new observable that is the 4-th request and inside the subscribe you will receive only the response from the 4-th request 2 If res[0]?.teamLeaderId == false you will return res which is not an observable so the source stream will break and throw error.

Here is a working Stackblitz that solves your case with switchMap and combineLatest

import { combineLatest, forkJoin, of } from "rxjs";
import { delay, switchMap } from "rxjs/operators";

const observable1 = of(1).pipe(delay(1000));
const observable2 = of(2).pipe(delay(1000));
const observable3 = of(3).pipe(delay(1000));
const observable4 = of(4).pipe(delay(1000));

const condition = true;

const observablen = forkJoin([observable1, observable2, observable3]);
observablen
  .pipe(
    switchMap(x =>
      combineLatest([...x.map(o => of(o)), ...(condition ? [observable4] : [])])
    )
  )
  .subscribe({
    next: value => console.log(value, "True condition"),
    complete: () => console.log("This is how it ends!")
  });

const observablef = forkJoin([observable1, observable2, observable3]);
observablef
  .pipe(
    switchMap(x =>
      combineLatest([
        ...x.map(o => of(o)),
        ...(!condition ? [observable4] : [])
      ])
    )
  )
  .subscribe({
    next: value => console.log(value, "False condition"),
    complete: () => console.log("This is how it ends!")
  });

1

Your arrow function isn't implemented correctly. Adding braces solves that issue. It may solve the issue you were having ( I haven't bothered replicating the entire issue, so I can't say, leave a comment if it helped out ).

failing code

mergeMap(res => 
  if(res[0]?.teamLeaderId){
    return getLeaderById(res[0]?.teamLeaderId).//Here I am getting res as undefined
  } else{
    return res;
  }
)

working code

mergeMap(res => {
  if(res[0]?.teamLeaderId){
    return getLeaderById(res[0]?.teamLeaderId).//Here I am getting res as undefined
  } else{
    return res;
  }
})
Rob Monhemius
  • 4,822
  • 2
  • 17
  • 49