Angular2 series – Routing

This post is part of a series of posts about Angular2. You can find them all in the introduction: http://julienrenaux.fr/2015/11/30/angular2-series-introduction/


Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.

All the following code examples are part of a boilerplate I created. It is available on GitHub: https://github.com/shprink/angular2-nobullshit-boilerplate.


If you are used to AngularJS applications you have probably used the ui-router instead of the Angular basic router (ngRoute). The ui-router is more popular because it has more features (such as nested views) and was adopted by big projects such as Ionic Framework.

The Angular2 router is a complete rewrite of the old ngRoute module. It was created keeping the ui-router use cased in mind, but also Angular2 components based architecture (a concept not yet adopted with AngularJS).

If you want to know more details about the Router history I recommend watching this video (beware the API changed a little bit since this video):

If you want to know more about components in Angular2 I suggest you to read this previous article of mine: Angular2 series – Component, Directive, Pipe and Service.

Path location strategies

Using AngularJS

With the ui-router in AngularJS you have the choice between two modes. The default one, aka the Hash mode (#products/id) that is not interpreted by servers or the HTML5 mode (/products/id).

One or the other can be selected using the $locationProvider

$locationProvider.html5Mode(true);

Notice: This HTML5 mode requires your web server to be configured.

Using Angular2

In Angular2 we have the same “modes” but they are called PathLocationStrategy and HashLocationStrategy.

PathLocationStrategy

PathLocationStrategy is the default strategy used by the new router. It is equivalent to the HTML5 mode in AngularJS.

If you want to use this strategy, you must define the APP_BASE_HREF to a string representing the URL prefix that should be preserved when switching pages.

import {ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';

bootstrap(yourApp, [
  ROUTER_PROVIDERS, // includes binding to PathLocationStrategy
  provide(APP_BASE_HREF, {useValue: '/my/prefix/here'})
]);

If you have problems understanding the above example, learn how to create an application with Angular2 first by reading: Angular2 series – Component, Directive, Pipe and Service.

If you do not want any prefix to be kept you can set APP_BASE_HREF to be:

provide(APP_BASE_HREF, {useValue: '/'})

Official docs

HashLocationStrategy

HashLocationStrategy is the strategy equivalent to the default strategy in AngularJS ui-router. This strategy is used to configure the Location service to represent its state with the hash fragment of the browser’s URL.

import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';
bootstrap(yourApp, [
  ROUTER_PROVIDERS,
  provide(LocationStrategy, {useClass: HashLocationStrategy})
]);

Official docs

Define Routes

Using AngularJS

In AngularJS and ui-router here is how to define states (or Routes) during the configuration phase:

$stateProvider.state('home', {
    url: '/',
    templateUrl: 'home.html',
    controller: 'HomeCtrl'
}).state('about', {
    url: '/about',
    templateUrl: 'about.html',
    controller: 'AboutCtrl'
})

Using Angular2

In Angular2 a state is created from a Route class. Using the @RouteConfig annotation you can create your application route definition.

@RouteConfig takes as first argument an Array of Route that have the following properties:

  • path equivalent to url in ui-router states
  • component a component type.
  • name is an optional CamelCase string representing the name of the route.
  • data is an optional property of any type representing arbitrary route metadata for the given route (we talk about it in the Passing data between routes section)

With that in mind let’s create an equivalent of the routes we created in the AngularJS version:

import {RouteConfig, Route} from 'angular2/router';
import {MyComponentHome, MyComponentAbout} from './myComponents';
@Component({
    selector: "app"
})
@RouteConfig([
    new Route({ path: '/', component: MyComponentHome, name: 'Home' }),
    new Route({ path: '/about', component: MyComponentAbout, name: 'About' })
])
export class App {...}

Template update

We have now defined our Routes, the next step is to define where to display the components when switching pages.

Using AngularJS

In AngularJS and ui-router we can use the ui-view directive to insert dynamic content from each state:

<body>
    <ui-view>
        <i>Some content will load here!</i>
    </ui-view>
</body>

Using Angular2

Using Angular2, it is similar, only the name of the directive change!

First we need to import the RouterOutlet directive and inject it into our App component, then we can use it in our template.

import {RouterOutlet} from 'angular2/router';
@Component({
    selector: "app"
})
@View({
    directives: [RouterOutlet]
    template: `
      <router-outlet></router-outlet>
    `
})

Now any location change will load a different component inside the RouterOutlet directive.

Navigate between pages

Using AngularJS

To navigate between pages (or states) in AngularJS and the ui-router we can use the ui-sref directive.

<a ui-sref="home">Home page</a>
<a ui-sref="about">About page</a>

Using Angular2

With Angular2 we can use the RouterLink directive instead.

This directive needs to be injected in your component first:

import {RouterLink} from 'angular2/router';
@Component({
  selector: "menu",
  directives: [RouterLink],
  template: `
     <a [routerLink]="['./Home']">Home page</a>
     <a [routerLink]="['./About']">About page</a>
  `
})
export class Menu {...}

Please note that [routerLink] uses the Route name that we defined earlier in the

Passing data between routes

Using AngularJS

In AngularJS we could defined URL parameters in state definitions:

$stateProvider.state('product.item', {
    url: '/product/:id',
    templateUrl: 'item.html',
    controller: 'ItemCtrl'
})

To pass the id from a state to another we have two choices. We can use the ui-sref directive or the $state service:

<a ui-sref="product.item({id: 4})">Go to item 4</a>
function($state) {
    // Go to item 4
    $state.go('product.item', {id: 4});
}

Then getting this data in our controller is easy using the $stateParams service:

function($stateParams) {
    var id = $stateParams.id;
}

BEWARE: The concept of params (passing data between states but without using URL parameters) in the ui-router does not exist in Angular2 (see my question on stackoverflow). A similar concept exist though and it is called data.

Using Angular2

Similar to AngularJS, we can define URL parameters using path from the Route class:

@RouteConfig([
    new Route({ 
        path: '/product/:id', 
        component: MyProductItemComponent, 
        name: 'ProductItem'
    })
])
export class App {...}

To pass the id from a Route to another we also have two choices. We can use the routerLink directive or the Router service.

In a template:

<a [routerLink]="['./ProductItem', {id: 4}]">Go to item 4</a>

In a Component:

import {Router} from 'angular2/router';
class {
  constructor(private _router: Router) {
    this._router.navigate( ['./ProductItem', { id: 4 }] );
  }
}

Then getting this data in a Component is easy using the RouteParams service:

import {RouteParams} from 'angular2/router';
class {
  id: number;
  constructor(private _params: RouteParams) {
    this.id = _params.get('id');
  }
}

Official docs

You can also retrieve data from a Route using RouteData service. I think this feature would not be used often (I probably will not use it on my applications) but it is good to know that it exists:

@RouteConfig([
    new Route({ 
        path: '/product/:id', 
        component: MyProductItemComponent, 
        name: 'ProductItem',
        data: {
            isAdmin: true
        }
    })
])
export class App {...}

You can now retrieve the isAdmin flag or any other Route metadata in your Components using the RouteData service:

class {
  isAdmin: boolean;
  constructor(private _data: RouteData) {
    this.isAdmin = _data.get('isAdmin');
  }
}

Official docs


Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!

4 thoughts on “Angular2 series – Routing”

Leave a Reply

Your email address will not be published. Required fields are marked *