Search code examples
angularrxjsauth-guard

Wait for two observables to finish in order in an Angular auth guard


Here's my Angular auth guard. It checks for a logged in status, then gets an id from it if it exists and checks for a profile assigned to that id. I'm trying to resolve the guard waiting for this two observables to finish in order with the zip method, but checkProfileOnline is returning an error because the uid is undefined, therefore is not waiting for the first observable to finish.

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(
    private authService: AuthService,
    private userService: UserService,
    private router: Router
  ) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

    let obsArray: Observable<boolean>[] = [];
    obsArray.push(this.checkAuthOnline(), this.checkProfileOnline());

    // CHECK FOR AUTH AND PROFILE ONLINE
    return Observable.zip(obsArray).map(res => {
      if (res[0] && res[1]) {
        return true;
      }
      return false;
    });
  }

  checkProfileOnline(): Observable<boolean> {
    return this.userService.userCheck(this.authService.uid).map(profile => {
      if (profile) {
        this.userService.user = profile;
        return true;
      }
      this.router.navigate(['/']);
      return false;
    });
  }

  checkAuthOnline(): Observable<boolean> {
    return this.authService.authStatus().map(loggedIn => {
      if (loggedIn) {
        this.authService.uid = loggedIn.uid;
        return true;
      }
      return false;
    });
  }

}

Solution

  • Instead of zip you can wait until the first observable is finished with concatMap and then run the second on. Then the second result will be mapped to && operation on both of them.

    return checkAuthOnline()
      .concatMap(res1 => checkProfileOnline()
        .map(res2 => res1 && res2)
    )