Let’s say we want to build a employees application. Our employees application shows a list of employees, which is our EmployeeListComponent and when we click on a employee, we navigate to the EmployeeDetailComponent, which gives us a detailed view of the selected employee.

A version of EmployeeListComponent could look something like this:

import { Component, OnInit } from '@angular/core'; import { CapitalizePipe } from '../shared/pipes/capitalize.pipe'; import { TrimPipe } from '../shared/pipes/trim.pipe'; import { RatingComponent } from '../shared/components/rating/rating.component'; import { Sorter } from '../shared/utils/sorter'; import { SortByDirective } from '../shared/directives/sortby.directive'; import { IEmployee } from '../shared/models/interfaces'; import { EmployeeService } from '../shared/services/employee.service'; @Component({ moduleId: module.id, selector: 'employee-list', templateUrl: 'employee-list.component.html', styleUrls: ['employee-list.component.css'], pipes: [CapitalizePipe, TrimPipe], directives: [RatingComponent, SortByDirective] }) export class EmployeeListComponent implements OnInit { private sortReverse: boolean = false; private sortProperty: string = ''; errorMessage: string; employees: IEmployee[] = []; constructor(private sorter: Sorter, private _employeeService: EmployeeService) { } ngOnInit(): void { this._employeeService.getEmployees().subscribe((employees: IEmployee[]) => { this.employees = employees; }, error => this.errorMessage = <any>error ); } sort(prop: string) { this.sortProperty = prop; this.sortReverse = !this.sortReverse; this.sorter.sort(this.employees, prop); } onRating(obj: any):void { var employee = this.employees.filter((item: any) => item.id === obj.employeeId); if (!!employee && employee.length === 1) { this.employees[0].rating = obj.rating; } } }

We also will build a version of EmployeeDetailComponent displays a single employee. We don’t want to worry too much about how this component is implemented yet, but a simplified version could look something like this:

import {Component} from '@angular/core'; import { IEmployee } from '../shared/models/interfaces'; @Component({ moduleId: module.id, selector: 'employee-detail', templateUrl: 'employee-detail.component.html' }) export class EmployeeDetailComponent { employee: IEmployee; }

and here is the template for a single employee:

<div *ngIf="employee"> <div class="row"> <div class="col-md-1"> <img src="/assets/images/{{employee.gender | lowercase}}.png" class="card-image" /> </div> <div class="col-md-11"> <h4> {{ employee.firstName }} {{ employee.lastName }} </h4> <br /> {{ employee.address }} <br /> {{ employee.city }}, {{ employee.state.name }} </div> </div> </div> <div *ngIf="!employee" class="row"> No employee found </div>

How to Build the Router?

Step 1: In app/employees create a new file call employee.routes.ts

Routes are best defined in a separate module to keep our application easy to test and also to make them easier to reuse. Let’s define routes for our components in a new module so we can add them to our application in the next step:

import { EmployeeListComponent } from './employee-list.component'; import { EmployeeDetailComponent } from './employee-detail.component'; export const EmployeesRoutes = [ { path: 'employees', component: EmployeeListComponent }, { path: 'employee/:id', component: EmployeeDetailComponent } ]

You might notice:

The path property on our first Route definition is employees for employee list. The router matches this route’s path to the URL in the browser address bar ( /employees ).

property on our first definition is employees for employee list. The router matches this route’s path to the URL in the browser address bar ( ). The second route has a placeholder in its path called id. This allows us to have some dynamic value in our path which can later be accessed in the component we route to. Think of a employee id in our case, so we can fetch the employee object we want to display the details for.

Step 2: Set the base href value

The Component Router uses the browser’s history.pushState for navigation.

We must add a element tag to the index.html to make pushState routing work. The browser also needs the base href value to prefix relative URLs when downloading and linking to css files, scripts, and images.

Add the base element just after the tag. If the app folder is the application root, as it is for our application, set the href value in index.html exactly as shown here:

<base href="/">

We have to get tricky when we run the live example because the host service sets the application base address dynamically. That’s why we replace the with a script that writes a tag on the fly to match. <script> document.write('<base href="' + document.location + '" />'); </script> We should only need this trick for the live example, not production code.

Step 3: Configure the routes for the Router

We teach our router how to navigate by configuring it with routes. We recommend creating a separate app.routes.ts file dedicated to this purpose.

import { provideRouter, RouterConfig } from '@angular/router'; import { WelcomeComponent } from './home/welcome.component'; import { EmployeeRoutes } from './employees/employee.routes'; export const App_Routes: RouterConfig = [ ...EmployeeRoutes, { path: '**', redirectTo: '/welcome', pathMatch: 'full' }, //catch any unfound routes and redirect to home page { path: 'welcome', component: WelcomeComponent } ]; export const APP_ROUTER_PROVIDERS = [ provideRouter(App_Routes) ];

Step 4: Register routing in bootstrap

The next thing we need to do is to make these routes available to our application. Angular takes advantage of its dependency injection system to make this work. The easiest way to make our routes available via DI is to import a function, which creates providers for us.

import { bootstrap } from '@angular/platform-browser-dynamic'; import { AppComponent } from './app.component'; import { APP_ROUTER_PROVIDERS } from './app.routes'; bootstrap(AppComponent, [ APP_ROUTER_PROVIDERS ]) .then( success => console.log('AppComponent bootstrapped!'), error => console.log(error) );

You might wonder where AppComponent comes from. Well, this is just the root component we use to bootstrap our application. In fact, it doesn’t really know anything about our EmployeeListComponent and EmployeeDetailComponent. We’re going to take a look at AppComponent in the next step though.

Step 5: Displaying loaded components

Okay cool, our application now knows about these routes. The next thing we want to do is to make sure that the component we route to, is also displayed in our application. We still need to tell Angular “Hey, here’s where we want to display the thing that is loaded!”. For that, we take a look at AppComponent:

import { Component } from '@angular/core'; import { HTTP_PROVIDERS } from '@angular/http'; import { EmployeeListComponent } from './employees/employee-list.component'; import {EmployeeService} from './shared/services/employee.service'; import { Sorter } from './shared/utils/sorter'; @Component({ selector: 'my-app', template: `<div> <h1>Employee Manager</h1> <employee-list></employee-list> </div>`, directives: [EmployeeListComponent], providers: [EmployeeService, HTTP_PROVIDERS, Sorter] }) export class AppComponent { }

Nothing special going on there. However, we need to change that. In order to tell Angular where to load the component we route to, we need to use a directive called RouterOutlet. There are different ways to get hold of it, but the easiest is probably to import the ROUTER_DIRECTIVES, which is simply a predefined list of directives we can add to a component’s template like this:

import { ROUTER_DIRECTIVES } from '@angular/router'; @Component({ ... directives: [ROUTER_DIRECTIVES] }) export class AppComponent { ... }

We can now use all the directives that are exposed in that collection. That includes the RouterOutlet directive. Let’s add a tag to our component’s template so that loaded components are displayed accordingly.

@Component({ selector: 'my-app', template: ` <div> <nav class='navbar navbar-default'> <div class='container-fluid'> <a class='navbar-brand'>{{pageTitle}}</a> <ul class='nav navbar-nav'> <li><a [routerLink]="['/welcome']">Home</a></li> <li><a [routerLink]="['/employees']">Employee List</a></li> </ul> </div> </nav> <div class='container'> <router-outlet></router-outlet> </div> </div> `, directives: [ROUTER_DIRECTIVES], providers: [EmployeeService, HTTP_PROVIDERS, Sorter] }) export class AppComponent { pageTitle: string = 'Employees Manager'; }

Bootstrapping that app now displays a list of employees! Awesome!



And when the user click on the Employee List:

The next thing we want to do is to link to EmployeeDetailComponent when someone clicks on a employee.

Step 6: Linking to other routes

With the new router, there are different ways to route to other components and routes. The most straight forward way is to simply use strings, that represent the path we want to route to. We can use a directive called RouterLink for that. For instance, if we want to route to EmployeeDetailComponent and pass the employee id 2, we can do that by simply writing:

<a routerLink="/employee/2">Michelle</a>

We need a way to evaluate something like {{employee.id}} to generate a link in our template. Luckily, RouterLink supports not only strings, but also expressions! As soon as we want to use expressions to generate our links, we have to use an array literal syntax in RouterLink.

Here’s how we could extend EmployeeListComponent to link to EmployeeDetailComponent:

<td><a [routerLink]="['/employee',employee.id]">{{ employee.firstName | capitalize }}</a></td>

We also need to add ROUTER_DIRECTIVES to the employee list component:

import { ROUTER_DIRECTIVES } from '@angular/router'; @Component({ ... directives: [RatingComponent, SortByDirective, ROUTER_DIRECTIVES] }) export class EmployeeListComponent implements OnInit{ ... }

Cool! We can now link to EmployeeDetailComponent. However, this is only half of the story. We still need to teach EmployeeDetailComponent how to access the route parameters so it can use them to load a contact object.

Step 7: Access Route Parameters

A component that we route to has access to something that Angular calls the ActivatedRoute. An ActivatedRoute is an object that contains information about route parameters, query parameters and URL fragments. EmployeeDetailComponent needs exactly that to get the id of a contact. We can inject the ActivatedRoute into EmployeeDetailComponent, by using Angular’s DI like this:

import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; @Component({ selector: 'employee-detail', ... }) export class EmployeeDetailComponent { constructor(private route: ActivatedRoute, private router: Router) { } }

ActivatedRoute comes with a params property which is an Observable. To access the contact id, all we have to do is to subscribe to the parameters Observable changes. Let’s say we have a EmployeeService that takes a number and returns an observable that emits a contact object. Here’s what that could look like:

import { Component, OnInit, OnDestroy } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { EmployeeService } from '../shared/services/employee.service'; import { IEmployee } from '../shared/models/interfaces'; @Component({ selector: 'employee-detail', ... }) export class EmployeeDetailComponent { employee: IEmployee; private sub: any; errorMessage: string; constructor(private route: ActivatedRoute, private router: Router, private _employeeService: EmployeeService) { } ngOnInit(): void { this.sub = this.route.params.subscribe( params => { let id = +params['id']; this.getEmployee(id); }); } getEmployee(id: number) { this._employeeService.getEmployee(id).subscribe( employee => this.employee = employee, error => this.errorMessage = <any>error); } }

We also should have a look at the EmployeeService that its content as follow:

import { Injectable } from '@angular/core'; import { IEmployee, IState } from '../models/interfaces'; import { Http, Response } from '@angular/http'; import { Observable } from 'rxjs/Observable'; import {Observer} from 'rxjs/Observer'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; @Injectable() export class EmployeeService { _baseUrl: string = 'data/employees/'; employees: IEmployee[]; states: IState[]; constructor(private http: Http) { } getEmployees(): Observable<IEmployee[]> { if (!this.employees) { return this.http.get(this._baseUrl + 'employees.json') .map((res: Response) => { this.employees = res.json(); return this.employees; }) .catch(this.handleError); } else { //return cached data return this.createObservable(this.employees); } } getEmployee(id: number): Observable<IEmployee> { if (this.employees) { //filter using cached data return this.findEmployeeObservable(id); } else { //Query the existing customers to find the target customer return Observable.create((observer: Observer<IEmployee>) => { this.getEmployees().subscribe((employees: IEmployee[]) => { this.employees = employees; const cust = this.filterEmployees(id); observer.next(cust); observer.complete(); }) }).catch(this.handleError); } } private findEmployeeObservable(id: number): Observable<IEmployee> { return this.createObservable(this.filterEmployees(id)); } private filterEmployees(id: number): IEmployee { const custs = this.employees.filter((cust) => cust.id === id); return (custs.length) ? custs[0] : null; } private createObservable(data: any): Observable<any> { return Observable.create((observer: Observer<any>) => { observer.next(data); observer.complete(); }); } private handleError(error: any) { console.error(error); return Observable.throw(error.json().error || 'Server error'); } }

Eventually, we’ll navigate somewhere else. The router will remove this component from the DOM and destroy it. We need to clean up after ourselves before that happens. Specifically, we must unsubscribe before Angular destroys the component. Failure to do so could create a memory leak.

We unsubscribe from our Observable in the ngOnDestroy method.

ngOnDestroy() { this.sub.unsubscribe(); }

Using Router Snapshots However, sometimes we’re not interested in future changes of a route parameter. All we need is this contact id and once we have it, we can provide the data we want to provide. In this case, an Observable can bit a bit of an overkill, which is why the router supports snapshots. A snapshot is simply a snapshot representation of the activated route. We can access the id parameter of the route using snapshots like this: ... ngOnInit() { this._employeeService .getEmployee(this.route.snapshot.params.id) .subscribe(employee=> this.employee= employee); } ...

Step 8: Navigating back to the list component

The EmployeeDetailComponent has a “Back” button wired to its gotoEmployees method that navigates imperatively back to the EmployeeListComponent.

The router navigate method takes the same one-item link parameters array that we can bind to a [routerLink] directive. It holds the path to the EmployeeListComponent:

gotoEmployees() { this.router.navigate(['/employees']); }

The employee detail template look like as:

We’ve learned how to

Organize our app into feature areas Navigate imperatively from one component to another Pass information along in route parameters and subscribe to them in our component

After these changes, the folder structure looks like this:

