angularroutesangular-router-guardscanactivate

Angular How to implement CanActivate guard with HTTP Get call


For my Angular 6 project, we want to use CanActivate guard to check authorization. To implement this, I need to call getSummary() http get call from app.service and perform some logic from its response to provide authorization.

The Logic goes as follows

Get the summary. If summary items length is more than one, iterate and verify its activation status. If activation status is not Active and no summary items are returned then navigate the user to the login page

I have below service app.service.ts

@Injectable({
  providedIn: 'root'
})
export class ApiService {
 
 getSummary(url) {
    return this.http.get(url).pipe(
      retry(this.retryAttempts),
      map(data => {
        return data;
      }),
      catchError(err => {
        return this.handleError(err, url);
      })
    );
  } 
}

I have below Auth Guard auth.guard.ts.I have tried to implement authorization logic like below but am not sure how to return Observable.

export class AuthGuard implements CanActivate {
 
canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<boolean>
{
    return this.checkAuthorization();
}

checkAuthorization():Observable<boolean>{

   let hasActiveSummary:boolean=false;
   this.apiService.getSummary(url)
      .subscribe( (data:any) => {

       console.log("Summary list:", data);
        if(data.length > 0){
          for (let i=0; i< data.length; i++) {
            if(data[i].activationStatus ==='ACTIVE') {
              hasActiveSummary=true;
              break;
            }
          }
        }
        console.log("STATUS",hasActiveSummary);
        if(!hasActiveSummary){
          this.router.navigate(['/login']);
        }
      },error => {
          console.log("Auth Guard error!", error);
        }
      );
} }

I am very new to routing guards. Can anyone guide how to implement this scenario in a correct way?


Solution

  • You are not returning the observable.

    canActivate(): Observable<boolean> expects a return value of an Observable (other options are possible - but in your example an Observable is fine).

    const a = this.apiService.getSummary(url) 'a' is an Observable

    const b = this.apiService.getSummary(url).subscribe() 'b' is a Subscription, not an Observable.

    What you need to do is return the observable as below. Adding the pipe( map() ) will keep is as an Observable, but 'map' the contents to be a boolean (in your case), so you will be returning Observable<boolean>

    return this.apiService.getSummary(url)
          .pipe( 
              map(data:any) => {
                 return true; // or false depending on your logic
              })
           )