Home > Net >  How to wait for API response in the nested subscription before executing next line of code
How to wait for API response in the nested subscription before executing next line of code

Time:06-10

I have a method that should return me a boolean value, the problem is that this is asynchronus and I want to avoid race condition..

So I have some method for example:

someMethod(data: any): boolean{
 let isOccupied = false;
 firstValueFrom(this.checkIfOccupied('102')).then(toilet=> isOccupied = toilet.name === data.name);
 this.someObject.isOccupied = isOccupied;
 return isOccupied;
}

So before I proceed to the line with this.someObject... I want to wait for things that are happening inside of then( )

And the checkIfOccupied looks like this:

  checkIfOccupied(toiletName: string): Observable<Toilet> {
    return this.store$
      .select(selectAlarmsForToilet(toiletName))
      .pipe(
        filter(res => !!res),
        take(1),
        switchMap((alarms: AlarmsObject[]) => {
          alarms.forEach(alarm => {
            if (Object.keys(alarm)[0].includes('occupied')) {
              const toiletId  = this.getToiletIdFromAlarm(toiletName, alarm); <= this method only finds needed ID
              if (toiletId ) {
                return this.toiletService.getToiletForId(toiletId ); <= this is API call
              }
            }
          });
          return of({} as SomeObject);
        }));
  }

I have tried to make it async and then use await in the someMethod but it doesn't work. Probably I made some mistake in the code (I dont want to make someMethod async - is it even possible?)

CodePudding user response:

You are very close in your thinking.

Consider the words you stated, which I will paraphase:

"Before I proceed to the next line, I want to wait for something"

So change your code like so:

async someMethod(data: any): Promise<boolean>{
 let isOccupied = false;
 data = await firstValueFrom(this.checkIfOccupied('102'));
 this.someObject.isOccupied = toilet.name === data.name;
 return toilet.name === data.name;
}

CodePudding user response:

You are using the Arrays.prototype.forEach inside your switchMap, which does not know anything about asynchronousity.

To keep up with race conditions, you can use the forkJoin Operator, which waits for Observables in arrays to complete such as:

someMethod(data: any): boolean {
    let isOccupied = false;
    firstValueFrom(this.checkIfOccupied('102')).then(toilet => isOccupied = 
       toilet.name === data.name);
    this.someObject.isOccupied = isOccupied;
    return isOccupied;
  }

  checkIfOccupied(toiletName: string): Observable<any> {
    return this.store$
      .select(selectAlarmsForToilet(toiletName))
      .pipe(
        filter(res => !!res),
        take(1),
        switchMap((alarms: AlarmsObject[]) => {
          return alarms.length ? forkJoin(alarms
          .filter(alarm => Object.keys(alarm)[0].includes('occupied'))
          .map((alarm: any) => this.getToiletIdFromAlarm(toiletName, alarm))
          .filter(toiletId => !!toiledId)
          .map((toiletId: any) => {
           return this.toiletService.getToiletForId(toiletId); // api call
            })) : of([]);
        }));
  }
  • Related