Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 Router - Anyone know how to use canActivate in app.ts so that I can redirect to home page if not logged in

Angular2 Router - Anyone know how to use canActivate in app.ts so that I can redirect to home page if not logged in

I'm using typescript and angular 2.

Current attempt under my constructor in my app.ts file:

   canActivate(instruction) {           
               console.log("here - canActivate");
               console.log(instruction);

               this.router.navigate(['Home']);  
   }

It currently doesnt get hit. Any idea why?

like image 548
AngularM Avatar asked Jan 12 '16 21:01

AngularM


3 Answers

So the documentation looks like this is what it exports.

export CanActivate(options : CanActivateAnnotation) : (hook: (next: ComponentInstruction, prev: ComponentInstruction) =>
                     Promise<boolean>| boolean) => ClassDecorator

@CanActivate((next, prev) => {
      // This must prove to be true for the component @ this route to load
      if(next.urlPath != '/Login'){ 
         return Promise.resolve(this._authService.getIsAuth() 
         && localStorage.getItem('authToken')
      }
      /*
       If CanActivate returns or resolves to false, the navigation is 
       cancelled. If CanActivate throws or rejects, the navigation is also
       cancelled. If CanActivate returns or resolves to true, navigation 
       continues, the component is instantiated, and the OnActivate hook of 
       that component is called if implemented.
      */
   }
);

At the bottom of the Angular2 documentation they add this snippet : exported from angular2/router https://angular.io/docs/ts/latest/api/router/CanActivate-decorator.html

So if you are looking to do redirection from a higher level. You would not use the CanActivate decorator you would do the following.

import {Directive, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
import {Router, RouterOutlet, ComponentInstruction} from 'angular2/router';
import {Login} from '../login/login';
import {UserService} from '../../Services/userService'; // a service to handle auth

@Directive({
  selector: 'router-outlet'
})
export class AuthRouterOutlet extends RouterOutlet {
  publicRoutes: any;
  private parentRouter: Router;

  constructor(private _userService:UserService, _elementRef: ElementRef, _loader: DynamicComponentLoader,
              _parentRouter: Router, @Attribute('name') nameAttr: string) {
    super(_elementRef, _loader, _parentRouter, nameAttr);

    this.parentRouter = _parentRouter;
    this.publicRoutes = {
      '/login': true,
      '/signup': true
    };
    // publicRoutes will be the routes auth is not needed for.
  }

  activate(instruction: ComponentInstruction) {
    var url = this.parentRouter.lastNavigationAttempt;
    if (!this.publicRoutes[url] && this._userService.getAuth()) {
      // todo: redirect to Login, may be there a better way?
      this.parentRouter.navigateByUrl('/login');
    }
    return super.activate(instruction);
    // we return super.activate(instruction) here so the router can activate the requested route and it's components.
  }
}

This implementation handles any new request to a directive and runs the activate function where your route authentication logic will be. The code above would be called something like AuthRouterOutlet. and you would have to add it to your app.ts via the

directives: [ AuthRouterOutlet]
like image 166
inoabrian Avatar answered Oct 21 '22 06:10

inoabrian


With the new beta release of the router, you can also see my answer here on how to use the CanActivate interface:

https://stackoverflow.com/a/38369948/1944351

Using the decorator as mentioned in other answer is fine too.

like image 32
Nilz11 Avatar answered Oct 21 '22 06:10

Nilz11


These answers are no longer valid in the RC candidate as of 22/6/16.

There is a lot of talk a new solution for @CanActivate annotation but you can revert back to using the angular-2/router-deprecated version in the interim.

If you want to follow the updates to this area if you want to use the newer router implementation please check out these two github issues:

  • Router OnActivate does not delay render until promise settles #6611
  • Equivalent to resolve in Component Router? #4015

Sorry there is no complete answer right now, if I see any further progress on this I'll update this reply. I'm searching for an elegant solution as well.

For the interim I just used a ngIf='fooObject' in a div to check for object being used in a child directive is populated/truthy and then render the rest of the components html. It's not ideal but it does work consistently right now. May help you or not depending on your use case. I don't need to redirect, only check my data has resolved for the display of my component.

like image 35
MJB Avatar answered Oct 21 '22 06:10

MJB