Angular 2 - Routing - CanActivate work with Observable

I have an AuthGuard (used for routing) that implements CanActivate.

canActivate() {
    return this.loginService.isLoggedIn();
}

My problem is, that the CanActivate-result depends on a http-get-result - the LoginService returns an Observable.

isLoggedIn():Observable<boolean> {
    return this.http.get(ApiResources.LOGON).map(response => response.ok);
}

How can i bring those together - make CanActivate depend on a backend state?

# # # # # #

EDIT: Please note, that this question is from 2016 - a very early stage of angular/router has been used.

# # # # # #


You should upgrade "@angular/router" to the latest . e.g."3.0.0-alpha.8"

modify AuthGuard.ts

@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private loginService: LoginService, private router: Router) {}

    canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        return this.loginService
            .isLoggedIn()
            .map((e) => {
                if (e) {
                    return true;
                }
            })
            .catch(() => {
                this.router.navigate(['/login']);
                return Observable.of(false);
            });
    }
}

If you have any questions, ask me!


Updating Kery Hu's answer for Angular 5+ and RxJS 5.5 where the catch operator is deprecated. You should now use the catchError operator in conjunction with pipe and lettable operators.

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { catchError, map} from 'rxjs/operators';
import { of } from 'rxjs/observable/of';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private loginService: LoginService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>  {
    return this.loginService.isLoggedIn().pipe(
      map(e => {
        if (e) {
          return true;
        } else {
          ...
        }
      }),
      catchError((err) => {
        this.router.navigate(['/login']);
        return of(false);
      })
    );
  }   
  
}

canActivate() accepts Observable<boolean> as returned value. The guard will wait for the Observable to resolve and look at the value. If 'true' it will pass the check, else ( any other data or thrown error ) will reject the route.

You can use the .map operator to transform the Observable<Response> to Observable<boolean> like so:

canActivate(){
    return this.http.login().map((res: Response)=>{
       if ( res.status === 200 ) return true;
       return false;
    });
}

I've done it in this way:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.userService.auth(() => this.router.navigate(['/user/sign-in']));}

As you can see I'm sending a fallback function to userService.auth what to do if http call fails.

And in userService I have:

import 'rxjs/add/observable/of';

auth(fallback): Observable<boolean> {
return this.http.get(environment.API_URL + '/user/profile', { withCredentials: true })
  .map(() => true).catch(() => {
    fallback();
    return Observable.of(false);
  });}