37

This might be a basic question, but in Angular2 is there any way to do conditional routing ? Or, would someone do that outside the router ?

I know ui-router had some ability to do this, but I haven't seen anything similar in Angular2s router

user3884414
  • 373
  • 1
  • 3
  • 4

3 Answers3

54

As mentioned, Angular Route Guards are a good way to implement conditional routes. Since the Angular Tutorial is a bit wordy on the topic, here is a short summary how to use them with an example.

1. There are several types of guards. If you need something of the logic if (loggedIn) {go to "/dashboard"} else { go to "/login"}, then what you are looking for is the CanActivate-Guard. CanActivate can be read as "The new route X can be activated if all of the conditions Y are satisfied". You can also define side-effects like redirects. If this doesn't fit your logic, checkout the Angular Tutorial page to see the other guard types.

2. Create an auth-guard.service.ts.

3. Populate the auth-guard.service.ts with the following code:

import { Injectable } from '@angular/core';
import {CanActivate, Router, RouterStateSnapshot, ActivatedRouteSnapshot} from '@angular/router';

@Injectable()
export class AuthGuardService implements CanActivate {

  constructor(
    private router: Router
  ) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    const isLoggedIn = false; // ... your login logic here
    if (isLoggedIn) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }

}

4. Register the auth-guard.service.ts in your route-module. Also, add the key-value pair canActivate:[AuthGuardService] to all routes you want to guard. It should look somewhat like this:

const appRoutes: Routes = [
  { path: '', component: LandingComponent},
  { path: 'login', component: LoginComponent},
  { path: 'signup', component: SignUpComponent},
  { path: 'home', component: HomeComponent, canActivate: [AuthGuardService]},
  { path: 'admin', component: AdminComponent, canActivate: [AuthGuardService]},
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes)
  ],
  exports: [
    RouterModule
  ],
  providers: [
    AuthGuardService
  ]
})
export class AppRoutingModule { }

That should get you started.

Here's a minimalistic demo: https://stackblitz.com/edit/angular-conditional-routing

bersling
  • 17,851
  • 9
  • 60
  • 74
9

update

In the new router guards can be used instead https://angular.io/guide/router#milestone-5-route-guards

original (for the long gone router)

Implement the CanActivate lifecycle hook like shown here Life cycle hooks in Angular2 router and return false if you want to prevent the navigation. See also https://angular.io/docs/ts/latest/api/router/CanActivate-var.html

René Stalder
  • 2,536
  • 5
  • 31
  • 50
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I'd like to see a neat example of this. I have an extension of the Router outlet, and you can catch the route before being routed, I've added certain user rights in the RouteDefinitions, so I can check if the user is allowed. But I have a subroute, which I want to be different for admins (see all users instead of profile). I think I need to define specific logic in the default page for now but that's not what I really want. – Mathijs Segers Mar 10 '16 at 08:18
9

In case if you need to render a specific component rather then redirect to it, you can do something like that:

const appRoutes: Routes = [
  {
    path: '' ,
    component: (() => {
      return SessionService.isAnonymous() ? LoginComponent : DashboardComponent;
    })()
  } 
]

I used this example for landing page, where user that was not previously logged in would either see the landing page or dashboard dashboard.

Update This code will work in dev environment but it will not build and you will get this error:

ERROR in Error during template compile of 'AppRoutingModule' Function expressions are not supported in decorators in 'ɵ0' 'ɵ0' contains the error at src/app/app.routing-module.ts(14,25) Consider changing the function expression into an exported function.

In order to fix it I created a separate module that looks as following

import {LandingPageComponent} from '../landing-page/landing-page.component';
import {DashboardComponent} from "../dashboard/dashboard.component";
import {SessionService} from "../core/services/session.service";

const exportedComponent = SessionService.isAnonymous() ? LandingPageComponent : DashboardComponent;

export default exportedComponent;

and then you just need to import module provided by that "factory"

import LandingPageComponent from './factories/landing-factory.component';
const appRoutes: Routes = [
  {
    path: '' ,
    component: LandingPageComponent
  },
]
  • I like the idea. But in this case, everytime Session Service will have to be reinstantiated. how would one be able to use the service and retaining the state at the same time? Because, i need to reply the historical data that helps me to toggle b/w components. – Alan Chang Mar 29 '19 at 06:32