Angular 2 Component Router 

by Gerard Sans (@gerardsans)

shield-large Created with Sketch.

Google Developer Expert

Master of Ceremonies

International Speaker

Angular 2 Trainer

Community Leader

800

500

Component Router

Main Contributor

Main Features

  • Based on components
  • Flexible routing
    • Nested views, auxiliary routes
  • Router Lifecycle Hooks
  • Lazy loading

Some days before the conference...

/home

/users

/about

/users/34

Setup Router

Dependencies

  • Include bundle: router.js
  • Choose Location Strategy
  • Include providers
    • ROUTER_PROVIDERS
  • Include directives
    • ROUTER_DIRECTIVES

Location Strategies

  • HashLocationStrategy
    • Eg: #/home, #/users/34
  • PathLocationStrategy (default)

Defining Routes

import {RouteConfig} from 'angular2/router';
import {Home} from './home';
import {Users} from './users';
import {AboutLazyLoader} from './aboutLazyLoader';

@RouteConfig([
  { path: '/home', component: Home, name: 'Home', data: {level:0} },
  { path: '/users/...', component: Users, name: 'Users' },
  { path: '/about', loader: AboutLazyLoader , name: 'AboutLazyLoad' },
  { path: '/**', redirectTo: ['Users'] }
])
export class App { }

Outlets

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';

@Component({
  selector: 'my-app',
  template: `
    <nav>...</nav>
    <div>
      <router-outlet></router-outlet>
    </div>`,
  directives: [ROUTER_DIRECTIVES]
})
@RouteConfig(...)
export class App { }

Flexible Routing

Child Routes

  • Parent uses special mark
    • /users/...
  • Child defines its own routes
  • Always define a default route
    • useAsDefault: true

Child Routes

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {UsersList} from './usersList';
import {UserDetails} from './userDetails';

@Component({
  selector: 'users',
  template: `<router-outlet></router-outlet>`,
  directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
  { path: '/', component: UsersList, name: 'UsersList', useAsDefault: true },
  { path: ':id', component: UserDetails, name: 'UserDetails'  },
])
export class Users { }

/

UsersList

#/users, #/users/

:id

UserDetails

#/users/34

Navigation

  • Using regular links with hash
    • #/home
  • Using routerLink directive uses link DSL
    • ['Home']
    • ['/Users/UserDetails', {id: 34}]
  • Programatically
    • router.navigate(['Home']);
    • router.navigateByUrl('/home');

routerLink

<!-- Top Routes -->
<a [routerLink]="['Home']">Home</a>
<a [routerLink]="['Users']">Users</a>
<a [routerLink]="['AboutLazyLoad']">About</a>

<!-- Nested Routes -->
<a [routerLink]="['/Users/UsersList']">Users</a>
<a [routerLink]="['/Users/UserDetails', {id: 34}]">Spiderman</a>
<a [routerLink]="['/Users/UserDetails', {id: 34, flag: true}]">Spiderman</a>

<!-- Relative Routes -->
<a [routerLink]="['./UsersList']">Users</a>
<a [routerLink]="['./UserDetails', {id: 34}]">Spiderman</a>
<a [routerLink]="['./UserDetails', {id: 34, flag: true}]">Spiderman</a>

Auxiliary routes

@Component({
  selector: 'my-app',
  template: `
    <router-outlet></router-outlet>
    <router-outlet name="modal"></router-outlet>`,
})
@RouteConfig([
  {path: '/hello', component: HelloCmp, name: 'Hello'}),
  {aux:  '/modal', component: ModalCmp, name: 'Modal'})
])
export class App { }

<a [routerLink]="['/Hello', ['Modal']]">both</a>
router.navigateByUrl('/hello(modal)'))
<a [routerLink]="['/', ['Modal']]">only modal</a>
router.navigateByUrl('/(modal)'))

Accessing Parameters

/* 
  { path: ':id', component: UserDetails, name: 'UserDetails' }
*/

import {RouteParams} from 'angular2/router';

@Component({
  selector: 'user-details'
})
export class UserDetails { 
  constructor(private params: RouteParams){
    let id = params.get('id');
  }
}

Accessing Data

/* 
  { path: '/home', component: Home, name: 'Home', data: {level:0} }
*/

import {RouteData} from 'angular2/router';

@Component({
  selector: 'home'
})
export class Home { 
  constructor(private data: RouteData){
    console.log(data.get("level"));
  }
}

Router Lifecycle Hooks

 

CanDeactivate
 
CanDeactivate
@CanActivate
@CanActivate
OnDeactivate
OnDeactivate
OnActivate
OnActivate

 

  Navigation from users list to user details

  1. UsersList.routerCanDeactivate()
  2. UserDetails.@CanActivate()
  3. UsersList.routerOnDeactivate()
  4. UserDetails.routerOnActivate()

Save changes

@Component({
  selector: 'user-details'
})
export class UserDetails implements CanDeactivate { 

  routerCanDeactivate() {
    return new Promise(resolve => 
      resolve(window.confirm('Do you want to continue?'))
    );
  }
}

Block Access

@Component({
  selector: 'user-details'
})
@CanActivate(next => {
  let injector = appInjector();
  let service = injector.get(LoginService);
    return new Promise(resolve => { 
      resolve(service.authorised);
    });
})
export class UserDetails { }

Lazy Loading

Setup

@RouteConfig([
  { path: '/about', loader: AboutLazyLoader , name: 'AboutLazyLoad' }
])
export class App { }

//aboutLazyLoader.ts
export function AboutLazyLoader(){
  return System.import('./src/aboutLazyLoad.ts')
    .then(module => module.AboutLazyLoad);
}

//aboutLazyLoad.ts
@Component({
  selector: 'about',
  template: `<h1>About</h1>`
})
export class AboutLazyLoad { }

Demo

Features

  • PathLocationStrategy setup
  • Nested routes with parameters
  • Block leaving route
  • Block route access
  • SVG loading spinner
  • Active menu css style fix

ng-conf - May 4-6th

@ngconf​

AngularConnect - Sept 27-28th

@AngularConnect

twit latest ng2 release full name to @gerardsans #rigadevday

Paldies!