angularxmlhttprequestsubscribeauth-guardcanactivate

How to process data from api response then return a boolean value synchronously in angular?


I have a simple function in my service:

  /**
   * Funtion to check if the user logged in has admin rights
   */
  isAdmin(user_id: string) {
    var adminTemp: boolean;
    this.httpClient
        .get(`${this.urk}/${user_id}`)
        .subscribe((data: any) => {
          if (data.includes('Admin')) {
            adminTemp = true;
          } else {
            adminTemp = false;
          }
        });
    return adminTemp;
  }

This function is called in a canActivate function which needs a bool value to determine if the user is an admin or not.

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if(this.loginService.isAdmin('123')){
      return true;
    }
    else{
      return this.router.parseUrl("/admin/logout");
    }
  }

The problem is that before the api call is made, it takes a value of undefined and marks the user as non-admin. I understand this happens because subscribe itself is an async call. I could not find any other way to figure out how to do this, as the api response has to be processed before it can be known if they are a user or not, else I would have used a simple return statement. How should I proceed?


Solution

  • your problem is that you are not taking advantage of Reactive programming (which is one of the best advantage that Angular brings with help of Rxjs).

    In your function isAdmin() it call http which is async, you are not making sure when you return adminTemp , it has been assigned with the value from http result.

    Instead, you should not subscribe the http call from asAdmin, just return it as observable, and let canActive handle it. So try not to subscribe if you can avoid it, will help you improve the efficiency.

          isAdmin(user_id: string): Observable<boolean> {
            
            return this.httpClient
                .get(`${this.urk}/${user_id}`)
                .pipe(
                   switchMap((data) => {
                     if (data.includes('Admin')) {
                       return of(true);
                     } else {
                      return of(false);
                     }
                    })
                 );
            
          }
    

    The advantage is that canActive() can also return Observable, so you can easily use it in canActive() as following:

        canActivate(
            next: ActivatedRouteSnapshot,
            state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
            return this.loginService.isAdmin('123').pipe(
         map((res) => {
          if (res) {
             return true;
          } else {
             return  this.router.parseUrl("/admin/logout");   
          }
         })
     );
    
          }