Search code examples
async-awaitpromisesubscriptionangular11

Angular 11 wait until subscribe finishes getting data


I have a auth.service and data.service. auth.service getting data from data.service but it checks before data arrives. So it returns undefined.

auth.service getting data like this;

get isLoggedIn(): boolean {
  const user = JSON.parse(localStorage.getItem('user'));
  const emailVerify = this.dataservice.userStatService(user.uid);
  console.warn(emailVerify)
  return (user !== null && emailVerify !== false && emailVerify !== undefined ) ? true : false;
}

data.service check user status function like this;

  userStatService(uid: any): any{
    console.error(uid)
    this.get(uid)
      .subscribe(
        data => {
          console.warn('status set', data.status)
          this.statData =  data.status;
        },
        error => {
          console.log(error);
    });
    return this.statData;
  }

and this code works like this now; See console logs

I'm waiting for your code examples, thank you.

Update: auth.guard code;

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if (this.authService.isLoggedIn() !== true) {
      this.router.navigate(['/auth/login'], { queryParams: { returnUrl: 'dashboard' } })
      .then(() => {
        this.authService.SignOut();
      });
    }else{
    return true;
    }
  }

Solution

  • observables execute asynchronously, you need to return the observable and subscribe in the consumer to use it correctly:

     // return observable
     userStatService(uid: any): any{
        console.error(uid)
        return this.get(uid)
     }
    
    
    isLoggedIn() {
      const user = JSON.parse(localStorage.getItem('user'));
      this.dataservice.userStatService(user.uid).subscribe(emailVerify => {
        console.warn(emailVerify)
      })
      // really can't do this while working with async execution. doesn't work.
      //return (user !== null && emailVerify !== false && emailVerify !== undefined ) ? true : false;
    }
    

    if this is for a guard, use the map operator and return the whole observable, angular expects either a boolean or an observable:

    isLoggedIn(): Observable<boolean> {
      const user = JSON.parse(localStorage.getItem('user'));
      if (!user)
        return of(false); // null guard and slight performance improvement
      return this.dataservice.userStatService(user.uid).pipe(map(emailVerify => {
        console.warn(emailVerify)
        return (emailVerify !== false && emailVerify !== undefined ) ? true : false;
      }))
    }
    

    and in your guard you need to again, RETURN THE OBSERVABLE:

      canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        return this.authService.isLoggedIn().pipe(
          map(isLoggedIn => {
            if (!isLoggedIn) {
              this.router.navigate(['/auth/login'], { queryParams: { returnUrl: 'dashboard' } }).then(() => {
                this.authService.SignOut();
              });
            }
            return isLoggedIn;
          })
        )
      }
    

    angular guards will handle the subscribing, but you must return the observable to the guard.