Angular2 conditional routing

Solution 1:

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

Solution 2:

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

Solution 3:

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
  },
]