Search code examples
angularangular2-routing

Angular2 CanActivate Navigate


I have following problem. I have made a CanActivate Guard where if you are logged in you can "go" to Debts Component. My problem is when I am logged in and i want to redirect User to Debts Component ( because RegistrationComponent is default ), but it's not working ( actually my page is blocking.. And i cannot do anything ). My CanActivate function

export class AuthGuardService implements CanActivate {

constructor(private router: Router) { }

canActivate(): Promise<boolean>{
    return checkIfAuth().then(() => {
        setLoggedIn(true);
        this.router.navigate(['/debts']); // <- broken :(
        return true;
    }).catch(() => {
        setLoggedIn(false);
        this.router.navigate(['/login']); // <- broken :(
        return false;
    })
  }
}


export function checkIfAuth () {
return new Promise((resolve, reject) => {
    firebase.auth().onAuthStateChanged((user) => {
        if(user){
            return resolve(true);
        }
        else{
            return reject(false);
        }
    })
  })
}

any my app.routing

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/registration', pathMatch: 'full' },
    {  path: 'registration', component: RegistrationComponent },
    { path: 'login', component: LoginComponent },
    { path: 'myaccount', component: AccountComponent, canActivate: [AuthGuardService]},
    { path: 'debts', component: DebtsComponent, canActivate: [AuthGuardService]}
];

Solution

  • What I did was kind of a hack but it works flawlessly :

    First, I did setup a Guard on my LoginCompoment route.

    { path: 'login', component: LoginComponent, canActivate: [AuthGuard] }
    

    And then I use the RouterStateSnapshot to get a single instance of my URL state, indicating me what the user tried to reach.

    I can then manage the cases in the Guard :

    import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
    
    ...
    
    /**
     *  Protects the routes to reach with authentication
     */
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        // Set user authentication state depending on the token's existance
        this.authService.setLoggedInState();
        // Check user authentication state
        if (this.authService.isAuthenticated) {
            // Explicit navigation to '/login' while the user is already authenticated
            if (state.url === '/login') {
                this.router.navigate(['/dashboard']); // Debts for you
            }
            return true;
        } else {
            // Allow route to './login' to get authenticated
            if (state.url === '/login') {
                return true;
            }
            // Explicit navigation to any URL while not being authenticated
            this.router.navigate(['/login']);
            return false;
        }
    }
    

    Documentation link about Snapshots : https://angular.io/docs/ts/latest/guide/router.html#!#sts=Snapshot:%20the%20no-observable%20alternative

    To make it work in your case, you just have to adapt the setLoggedInState() to your case which it seems you already have.

    N.B : I call this solution a HACK because you actually set a guard on the Login while it will still allow the user to reach it even if he is not authenticated. Still works well tho.