In this post I will give an introduction to the new Angular router.
Angular really pushes the concept of components, so it's not surprising that routing is configured based on components. I really like the concept of component based routing since it promotes a modular design where the components themselves are agnostic of the routes.
Routes
The setup of the router is pretty intuitive and it's really easy to add a few simple routes to your application. All you really need is a configuration section pointing to some components that will be loaded by specific routes. In my sample I have put the routes in a separate app.routes.ts file as shown below:
import {provideRouter, RouterConfig} from '@angular/router';
import {DemoPage} from './demo-page';
import {About} from './components/about/about';
import {TreeViewDemo} from './components/tree-view/tree-view-demo';
import {ContactList} from './components/contact-list/contact-list';
import {BoundTextbox} from './components/bound-textbox/bound-textbox';
import {Directory} from './components/tree-view/directory';
import {GridDemo} from './components/grid/grid-demo';
import {Column} from './components/grid/column';
import {IgnoreBindings} from './components/non-bindable/non-bindable';
import {HttpSample} from './components/http/http';
import {Spreadsheet} from './components/spreadsheet/spreadsheet';
import {Algorithms} from './components/algorithms/algorithms';
import {Angular2Host} from './components/react-integration/angular-2-host';
import {JqueryIntegration} from './components/jquery-integration/jquery-integration';
import {InputControls} from './components/input-controls/input-controls';
import {AddressBook} from './components/dependency-injection/address-book';
import {AddressForm} from './components/address-form/address-form';
import {Graph} from './components/algorithms/graph/graph';
import {PubSub} from './components/pub-sub/pub-sub';
import {TextEditor} from './components/text-editor/text-editor';
import {CommentDemo} from './components/change-detection/comment-demo';
import {Parent} from './components/access-child-components/parent';
import {SurveyDemo} from './components/survey/survey-demo';
import {LogDemo} from './components/log-tail/log-demo';
import {InputOutputDemo} from './components/input-output/input-output-demo';
import {CountryDemo} from './components/lazy-loaded-tree-view/country-demo';
import {RxJsStreams} from './components/rxjs-streams/rxjs-streams';
import {CachingDemo} from './components/rxjs-caching/caching-demo';
import {RxJsBuffering} from './components/rxjs-buffering/rxjs-buffering';
export const routes: RouterConfig = [
{
path: '',
redirectTo: '/about',
terminal: true
},
{ path: 'about', component: About},
{ path: 'about/:id', component: About},
{
path: 'demo',
component: DemoPage,
children: [
{ path: 'spreadsheet', component: Spreadsheet},
{ path: 'jquery', component: JqueryIntegration},
{ path: 'react', component:Angular2Host},
{ path: 'algorithms', component:Algorithms},
{ path: 'graph', component:Graph},
{ path: 'pub-sub', component:PubSub},
{ path: 'text-editor', component:TextEditor},
{ path: 'address', component:AddressBook},
{ path: 'http', component:HttpSample},
{ path: 'treeview', component:TreeViewDemo},
{ path: 'grid', component:GridDemo},
{ path: 'input', component:InputControls},
{ path: 'contact', component:ContactList},
{ path: 'textbox', component:BoundTextbox},
{ path: 'non-bindable', component:IgnoreBindings},
{ path: 'form', component:AddressForm},
{ path: 'change', component:CommentDemo},
{ path: 'parent-child', component:Parent},
{ path: 'survey', component:SurveyDemo},
{ path: 'redux', component:LogDemo},
{ path: 'iodemo', component:InputOutputDemo},
{ path: 'rxjs', component:RxJsStreams},
{ path: 'friends', component:CachingDemo},
{ path: 'buffering', component:RxJsBuffering},
{ path: 'countries', component:CountryDemo}
]
}
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(routes)
];
During bootstrap we will import these routes and add them to the provider array of the bootstrap function. The next code sample shows how to bootstrap the application with the routes.
import {Component} from '@angular/core';
import {bootstrap} from '@angular/platform-browser-dynamic';
import {ROUTER_DIRECTIVES} from '@angular/router';
import {HashLocationStrategy, LocationStrategy, Location} from '@angular/common';
import { APP_ROUTER_PROVIDERS } from './app.routes';
@Component(
{
selector: 'demo-app',
templateUrl: './demo-app.html',
directives:[ROUTER_DIRECTIVES]
})
export class MyDemoApp {
}
bootstrap(MyDemoApp,[
APP_ROUTER_PROVIDERS,
{provide: LocationStrategy, useClass: HashLocationStrategy}
In this sample I am using the HashLocationStrategy for my routes since I have a lot of exiting links with the # character in them. You may want to consider Html5 push state routes instead for your application. All you have to do to enable that is remove the LocationStrategy from the bootstrap function and add a base tag with your base url to index.html.
Root routes
The simplest case is a root level route with no dependents.
In the following example we see a simple root level route, pointing to a component.
{ path: 'about', component: About}
The next natural step is to define a root route with a parameter using the :/[paramterName] syntax
{ path: 'details/:id', component: Details},
Deep linking and child routes
Single level routes as described above are very common in Single Page Applications, but the next level of this is to wire up deep linking where the routes have child routes.
The way to do deep linking in Angular is via the children array on the root route
{path: 'demo', component: DemoPage, children: [{ path: 'spreadsheet', component: Spreadsheet}]
The spreadsheet route is a child of the demo route. Here is a test of the route we just defined.
router-outlet and routerLink
The new router is different from UI-router, but some of the concepts will still be familiar. Instead of ui-sref and ui-view – we now have new counterparts in routerLink and router-outlet. I have added a simple sample below:
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div>
<ul class="nav navbar-nav">
<li><a [routerLink]="['/demo/spreadsheet']" class="link">Demos</a></li>
</ul>
</div>
</div>
</nav>
</div>
<router-outlet></router-outlet>
Router-outlet is where a component is injected into the DOM when the associated route is visited.
As always – the full example with a live demo can be found here. The code is available on Github.