Redirect to a different component inside @CanActivate in Angular2
As of today, with latest @angular/router 3.0.0-rc.1, here are a couple of references on how to do that through CanActivate
guards on routes:
- angular 2 reference
- Two answers to this SO question, by Nilz11 and by Jason
The main gist of logic looks like:
// ...
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.authService.isLoggedIn) {
// all ok, proceed navigation to routed component
return true;
}
else {
// start a new navigation to redirect to login page
this.router.navigate(['/login']);
// abort current navigation
return false;
}
}
Your guard can easily just be an injectable which, as such, can include its own injectables. So we can simply inject the router, in order to redirect. Don't forget to add the service as a provider in your app module.
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router, private authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
if (!authService.isAuthenticated()) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
export const ROUTES: Routes = [
{path: 'login', component: LoginComponent},
{path: 'protected', loadChildren: 'DashboardComponent', canActivate: [AuthGuard]}
];
Yes, you can! Doing this will prevent your component from instantiating for nothing.
First, make a new file src/app-injector.ts
let appInjectorRef;
export const appInjector:any = (injector = false) => {
if (!injector) {
return appInjectorRef;
}
appInjectorRef = injector;
return appInjectorRef;
};
Then, get the reference from bootstrap
// ...
import {appInjector} from './app-injector';
// ...
bootstrap(App, [
ROUTER_PROVIDERS
]).then((appRef) => appInjector(appRef.injector));
Finally in your function
// ...
import {appInjector} from './app-injector';
// ...
@CanActivate((next, prev) => {
let injector = appInjector();
let router = injector.get(Router);
if (42 != 4 + 2) {
router.navigate(['You', 'Shall', 'Not', 'Pass']);
return false;
}
return true;
})
Et voilà !
It was discussed here https://github.com/angular/angular/issues/4112
You can find a complete example here http://plnkr.co/edit/siMNH53PCuvUBRLk6suc?p=preview by @brandonroberts
As of Angular 7.1, you can return UrlTree
instead of boolean
:
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) { }
canActivate(): boolean | UrlTree {
return this.authService.isAuthenticated() || this.router.createUrlTree(['/login']);
}
}