Search code examples
angulartypescriptangular-router-guards

Angular guard not redirecting to specific page due to exception


So I'm trying to implement a basic guard:

canActivate(route: ActivatedRouteSnapshot,
          state: RouterStateSnapshot): Observable<boolean> {
return this.userService.isBoardMember().pipe(
  map(data => {
    if (data === false) {
      this.router.navigate(['main']);
      return false;
    }
    return true;
  })
);
}

The isBoardMember method looks like this:

getUserDetails(): Observable<User> {
this.requestUrl = `${configs.bgwssApi}v1/bics/${this.bic}/tcifs/${this.tcif}/users`;
return this.http.get<User>(this.requestUrl).pipe(catchError(this.handleError));
}

isBoardMember(): Observable<boolean> {
return this.getUserDetails().pipe(map(data => {
  return (data.userRole === 'BOARD_MEMBER');
}));
}

handleError method:

  private handleError(e: HttpErrorResponse) {
let errorMessage = '';
if (e.error instanceof ErrorEvent) {
  // Client side error received
  errorMessage = `Error getting user occurred: ${e.error.message}`;
} else {
  // Server side error received
  errorMessage = `Error getting user from server, code: ${e.status}, message: ${e.message}`;
}
console.error(errorMessage);
return throwError(errorMessage);

}

The problem is that when getUserDetails http request returns 404 error(doesn't find the specific user), isBoardMember method doesn't return anything so my guard is not properly redirecting to main page as it should - instead it just loads an empty page with no url. Need some help solving this issue.


Solution

  • You should add another catchError, because you are throwing an error on 404 in your handleError method.

    It feels like the isBoardMember is the right place for that. If you feel like it should be in the guard, you can add the logic there:

    So either in the Service:

    isBoardMember(): Observable<boolean> {
      return this.getUserDetails().pipe(
        map(data => data.userRole === 'BOARD_MEMBER'),
        catchError(() => of(false))
      );
    }
    

    Or in the guard:

    constructor(private userService: UserService, private router: Router) {}
    
    canActivate(): Observable<boolean | UrlTree> {
      return this.userService.isBoardMember().pipe(
        catchError(() => of(false)),
        map(data => data || this.router.createUrlTree(['main']))
      );
    }
    

    I'm using createUrlTree because that's the recommended way to do a redirect from a guard