The Angular 2 router is strictly connected to the component. It’s also called the Component Router (which is about to come to Angular 1.x as well). The main purpose of it is to have routable components. They are often smart components that are fetching resources from the API.

Configuration

Let’s start with adding a router to the app. The very beginning is to add the general URL to that app which is accessible. This usually ends up with / as the entrance point, but you may need to change it such as when you are trying to connect Angular 2 with an existing app.

The base href is achieved by adding the element base (in index.html):

<base href="/">

This is the only step you have to make in HTML. Next it’s time to configure providers. We move to the place where the app is being bootstrapped and import ROUTER_PROVIDERS:

import { bootstrap } from '@angular/platform-browser-dynamic';
import { ROUTER_PROVIDERS } from '@angular/router';

import { AppComponent } from './app.component';

bootstrap(AppComponent, [
  ROUTER_PROVIDERS
]);

This way we are able to inject router providers anywhere in the app and they will be singletons.

Router Outlet

Now it’s time to add the first routable component. First of all, let’s recap the most basic component that App could be:

import { Component } from '@angular/core';

@Component({
  selector: 'app',
  template: 'Hello App'
})
class AppComponent {};

To add some routes we can start with their definitions:

import { Component } from '@angular/core';
import { Routes } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
import { SignupComponent } from './pages/signup/signup.component';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import { UserStoreService } from './common/services/userStore.service';
import { HomeComponent } from './pages/home/home.component';

@Component({
  selector: 'app',
  template: 'Hello App'
})
@Routes([
  { path: '/', component: HomeComponent },
  { path: '/login', component: LoginComponent },
  { path: '/signup', component: SignupComponent },
  { path: '/dashboard', component: DashboardComponent },

  // Catch route
  { path: '*', component: HomeComponent }   
])
class AppComponent {};

Now we do have configuration for this particular component, but routes won’t be visible. It’s happening because of the lack of a place where the router should render its content. So we’re importing ROUTER_DIRECTIVES:

import { ROUTER_DIRECTIVES, Routes } from '@angular/router';
...

@Component({
  selector: 'app',
  directives: ROUTER_DIRECTIVES,
  template: `
    <router-outlet></router-outlet>
  `
})
...

This time, instead of a simple string, we’re using RouterOutlet to make a placeholder for routable components. If you change the URL to match some path it should render the proper component.

Router Link

It works perfectly but lacks a very important feature – links to other routes. This one is achieved by the RouterLink directive. With the appropriate parameters it can route to named routes. Look at the template:

import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES, Routes } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
import { SignupComponent } from './pages/signup/signup.component';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import { UserStoreService } from './common/services/userStore.service';
import { HomeComponent } from './pages/home/home.component';

@Component({
  selector: 'app',
  directives: ROUTER_DIRECTIVES,
  template: `
    <nav>
      <ul>
        <li><a [routerLink]="['/home']">Home</a></li>
        <li><a [routerLink]="['/dashboard']">Dashboard</a></li>
        <li><a [routerLink]="['/login']">Log In</a></li>
        <li><a [routerLink]="['/signup']">Sign Up</a></li>
      </ul>
    </nav>
    <router-outlet></router-outlet>
  `
})
@Routes([
  { path: '/', component: HomeComponent },
  { path: '/login', component: LoginComponent },
  { path: '/signup', component: SignupComponent },
  { path: '/dashboard', component: DashboardComponent },

  // Catch route
  { path: '*', component: HomeComponent }   
])
class AppComponent {};

The configuration and code up to this point should give a working rout to the proper components basing on the routing table provided for the component.

Route Parameters

We’re able to route to the static URL path, but now it’s time to make it more dynamic. The first thing you meet when trying to solve real problems is to add a dynamic id to the URL. It’s quite easy in Angular 2. Let’s consider following the dashboard component:

@Component({
    selector: 'dashboard',
    template: `
      <router-outlet></router-outlet>      
      <a [routerLink]="['./', 'room1']">Go to room1</a>
    `.
    directives: ROUTER_DIRECTIVES
})
@Routes([
    { path: '/', component: DashboardMainComponent },
    { path: '/:name', component: RoomComponent },

    // Catch All route
    { path: '*', component: DashboardMainComponent }
])

In the routes you’ll see:

{ path: '/:name', component: RoomComponent },

It indicates a path with a parameter. This path can be supplied either by entering with the proper URL, or by adding a router link with a second parameter in the array:

<a [routerLink]="['./', 'room1']">Go to room1</a>

The router link gets a DSL path as the first item in the array. It can be either absolute or relative. The second one is part of the URL. In our case it passes the name to the component, which is accessible by /:name. The first is the map of query string parameters.

Lifecycle hooks

On the other hand, in the component we just routed to it would be nice to get the params there. Like Angular component hooks, the router adds its own. Angular fires the onInit hook when it initializes the component. In the same way we can implement router interfaces inside the class that has the @Routes annotation. We are able to use following hooks:

  • OnActivate – fired upon a successfully activated route
  • CanDeactivate – defines whether a component can be deactivated

The one that is especially useful here is OnActivate. It let’s you define code that has to be invoked right after successful redirection. Moreover, it gives us information about current and previous routes. We’ll incorporate that in the following manner:

import {
  OnActivate,
  Router,
  RouteSegment,
  RouteTree
} from '@angular/router';
...

class RoomComponent implements OnActivate {
  private selectedName: number;

  routerOnActivate(curr: RouteSegment, prev?: RouteSegment, currTree?: RouteTree, prevTree?: RouteTree): void {
    this.selectedName = curr.getParam('name');
  }
}

Now we were able to get the param passed by the URL directly to the code.