diff --git a/public/docs/_examples/router/ts/app/app.component.2.ts b/public/docs/_examples/router/ts/app/app.component.2.ts
index 4ab0f7aaf2..ce4f3c1c53 100644
--- a/public/docs/_examples/router/ts/app/app.component.2.ts
+++ b/public/docs/_examples/router/ts/app/app.component.2.ts
@@ -6,11 +6,22 @@ import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {CrisisListComponent} from './crisis-list.component';
+// #enddocregion
+/*
+// Apparent Milestone 2 imports
+// #docregion
// #docregion hero-import
import {HeroListComponent} from './heroes/hero-list.component';
import {HeroDetailComponent} from './heroes/hero-detail.component';
import {HeroService} from './heroes/hero.service';
// #enddocregion hero-import
+// #enddocregion
+*/
+// Actual Milestone 2 imports
+import {HeroListComponent} from './heroes/hero-list.component.1';
+import {HeroDetailComponent} from './heroes/hero-detail.component.1';
+import {HeroService} from './heroes/hero.service';
+// #docregion
@Component({
selector: 'my-app',
@@ -45,6 +56,3 @@ import {HeroService} from './heroes/hero.service';
export class AppComponent { }
// #enddocregion route-config
// #enddocregion
-
-// #docregion child-router-link
-// #enddocregion child-router-link
diff --git a/public/docs/_examples/router/ts/app/app.component.3.ts b/public/docs/_examples/router/ts/app/app.component.3.ts
index f57a57f351..9129e383bc 100644
--- a/public/docs/_examples/router/ts/app/app.component.3.ts
+++ b/public/docs/_examples/router/ts/app/app.component.3.ts
@@ -1,11 +1,10 @@
// #docplaster
-// #docregion
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
-import {CrisisCenterComponent} from './crisis-center/crisis-center.component';
-import {HeroListComponent} from './heroes/hero-list.component';
-import {HeroDetailComponent} from './heroes/hero-detail.component';
+import {CrisisCenterComponent} from './crisis-center/crisis-center.component.1';
+import {HeroListComponent} from './heroes/hero-list.component.1';
+import {HeroDetailComponent} from './heroes/hero-detail.component.1';
import {DialogService} from './dialog.service';
import {HeroService} from './heroes/hero.service';
@@ -36,7 +35,6 @@ import {HeroService} from './heroes/hero.service';
Princess Crisis
// #enddocregion princess-anchor
*/
-// #docregion
// #docregion template
template: `
Component Router
diff --git a/public/docs/_examples/router/ts/app/boot.2.ts b/public/docs/_examples/router/ts/app/boot.2.ts
index 1451041616..244050a36a 100644
--- a/public/docs/_examples/router/ts/app/boot.2.ts
+++ b/public/docs/_examples/router/ts/app/boot.2.ts
@@ -3,36 +3,30 @@
// Also includes digression on HashPathStrategy (not used in the final app)
// #docplaster
-// #docregion v2
+// #docregion
import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {AppComponent} from './app.component';
-// #enddocregion v2
-// Add these symbols to register a `LocationStrategy`
+// Add these symbols to override the `LocationStrategy`
import {provide} from 'angular2/core';
import {LocationStrategy,
HashLocationStrategy} from 'angular2/router';
-// #enddocregion hash-strategy
-
+// #enddocregion
/* Can't use AppComponent ... but display as if we can
-// #docregion v2, hash-strategy
+// #docregion
bootstrap(AppComponent, [
-// #enddocregion v2, hash-strategy
+// #enddocregion
*/
// Actually use the v.2 component
import {AppComponent as ac} from './app.component.2';
bootstrap(ac, [
-// #docregion v2, hash-strategy
+// #docregion
ROUTER_PROVIDERS,
-// #enddocregion v2, hash-strategy
-// #docregion hash-strategy
provide(LocationStrategy,
- {useClass: HashLocationStrategy}) // ~/#/crisis-center/
-// #enddocregion hash-strategy
-// #docregion v2, hash-strategy
+ {useClass: HashLocationStrategy}) // .../#/crisis-center/
]);
-// #enddocregion v2, hash-strategy
+// #enddocregion
diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.1.ts
new file mode 100644
index 0000000000..8efe443bc0
--- /dev/null
+++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.1.ts
@@ -0,0 +1,28 @@
+import {Component} from 'angular2/core';
+import {RouteConfig, RouterOutlet} from 'angular2/router';
+
+import {CrisisListComponent} from './crisis-list.component.1';
+import {CrisisDetailComponent} from './crisis-detail.component.1';
+import {CrisisService} from './crisis.service';
+
+// #docregion minus-imports
+@Component({
+ template: `
+ CRISIS CENTER
+
+ `,
+ directives: [RouterOutlet],
+// #docregion providers
+ providers: [CrisisService]
+// #enddocregion providers
+})
+// #docregion route-config
+@RouteConfig([
+ // #docregion default-route
+ {path:'/', name: 'CrisisCenter', component: CrisisListComponent, useAsDefault: true},
+ // #enddocregion default-route
+ {path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent}
+])
+// #enddocregion route-config
+export class CrisisCenterComponent { }
+// #enddocregion minus-imports
diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts
index 897d573d2d..77f30e1a28 100644
--- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts
+++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts
@@ -6,25 +6,17 @@ import {CrisisListComponent} from './crisis-list.component';
import {CrisisDetailComponent} from './crisis-detail.component';
import {CrisisService} from './crisis.service';
-// #docregion minus-imports
@Component({
template: `
CRISIS CENTER
`,
directives: [RouterOutlet],
-// #docregion providers
providers: [CrisisService]
-// #enddocregion providers
})
-// #docregion route-config
@RouteConfig([
- // #docregion default-route
{path:'/', name: 'CrisisCenter', component: CrisisListComponent, useAsDefault: true},
- // #enddocregion default-route
{path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent}
])
-// #enddocregion route-config
export class CrisisCenterComponent { }
-// #enddocregion minus-imports
// #enddocregion
diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts
new file mode 100644
index 0000000000..210563df59
--- /dev/null
+++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts
@@ -0,0 +1,92 @@
+// #docplaster
+
+// #docregion
+import {Component, OnInit} from 'angular2/core';
+import {Crisis, CrisisService} from './crisis.service';
+import {RouteParams, Router} from 'angular2/router';
+// #docregion routerCanDeactivate
+import {CanDeactivate, ComponentInstruction} from 'angular2/router';
+import {DialogService} from '../dialog.service';
+
+// #enddocregion routerCanDeactivate
+
+@Component({
+ // #docregion template
+ template: `
+
+
"{{editName}}"
+
+ Id: {{crisis.id}}
+
+ Name:
+
+
+
Save
+
Cancel
+
+ `,
+ // #enddocregion template
+ styles: ['input {width: 20em}']
+})
+// #docregion routerCanDeactivate, cancel-save
+export class CrisisDetailComponent implements OnInit, CanDeactivate {
+
+ crisis: Crisis;
+ editName: string;
+
+// #enddocregion routerCanDeactivate, cancel-save
+ constructor(
+ private _service: CrisisService,
+ private _router: Router,
+ private _routeParams: RouteParams,
+ private _dialog: DialogService
+ ) { }
+
+ // #docregion ngOnInit
+ ngOnInit() {
+ let id = +this._routeParams.get('id');
+ this._service.getCrisis(id).then(crisis => {
+ if (crisis) {
+ this.editName = crisis.name;
+ this.crisis = crisis;
+ } else { // id not found
+ this.gotoCrises();
+ }
+ });
+ }
+ // #enddocregion ngOnInit
+
+ // #docregion routerCanDeactivate
+ routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : any {
+ // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged.
+ if (!this.crisis || this.crisis.name === this.editName) {
+ return true;
+ }
+ // Otherwise ask the user with the dialog service and return its
+ // promise which resolves to true or false when the user decides
+ return this._dialog.confirm('Discard changes?');
+ }
+ // #enddocregion routerCanDeactivate
+
+ // #docregion cancel-save
+ cancel() {
+ this.editName = this.crisis.name;
+ this.gotoCrises();
+ }
+
+ save() {
+ this.crisis.name = this.editName;
+ this.gotoCrises();
+ }
+ // #enddocregion cancel-save
+
+ // #docregion gotoCrises
+ gotoCrises() {
+ // Like Crisis Center
"{{editName}}"
@@ -25,16 +21,14 @@ import {DialogService} from '../dialog.service';
Cancel
`,
- // #enddocregion template
styles: ['input {width: 20em}']
})
-// #docregion routerCanDeactivate, cancel-save
+
export class CrisisDetailComponent implements OnInit, CanDeactivate {
crisis: Crisis;
editName: string;
-// #enddocregion routerCanDeactivate, cancel-save
constructor(
private _service: CrisisService,
private _router: Router,
@@ -42,7 +36,6 @@ export class CrisisDetailComponent implements OnInit, CanDeactivate {
private _dialog: DialogService
) { }
- // #docregion ngOnInit
ngOnInit() {
let id = +this._routeParams.get('id');
this._service.getCrisis(id).then(crisis => {
@@ -54,9 +47,7 @@ export class CrisisDetailComponent implements OnInit, CanDeactivate {
}
});
}
- // #enddocregion ngOnInit
- // #docregion routerCanDeactivate
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : any {
// Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged.
if (!this.crisis || this.crisis.name === this.editName) {
@@ -66,9 +57,7 @@ export class CrisisDetailComponent implements OnInit, CanDeactivate {
// promise which resolves to true or false when the user decides
return this._dialog.confirm('Discard changes?');
}
- // #enddocregion routerCanDeactivate
- // #docregion cancel-save
cancel() {
this.editName = this.crisis.name;
this.gotoCrises();
@@ -78,19 +67,16 @@ export class CrisisDetailComponent implements OnInit, CanDeactivate {
this.crisis.name = this.editName;
this.gotoCrises();
}
- // #enddocregion cancel-save
// #docregion gotoCrises
gotoCrises() {
- let route =
- // pass along the crisis id if available
- // so that the CrisisList component can select that crisis
- ['CrisisCenter', {id: this.crisis ? this.crisis.id : null} ]
-
- this._router.navigate(route);
+ let crisisId = this.crisis ? this.crisis.id : null;
+ // Pass along the hero id if available
+ // so that the CrisisListComponent can select that hero.
+ // Add a totally useless `foo` parameter for kicks.
+ // #docregion gotoCrises-navigate
+ this._router.navigate(['CrisisCenter', {id: crisisId, foo: 'foo'} ]);
+ // #enddocregion gotoCrises-navigate
}
// #enddocregion gotoCrises
-// #docregion routerCanDeactivate, cancel-save
}
-// #enddocregion routerCanDeactivate, cancel-save
-// #enddocregion
diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts
new file mode 100644
index 0000000000..5338092184
--- /dev/null
+++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts
@@ -0,0 +1,36 @@
+// #docplaster
+
+// #docregion
+import {Component, OnInit} from 'angular2/core';
+import {Crisis, CrisisService} from './crisis.service';
+import {Router} from 'angular2/router';
+
+@Component({
+ // #docregion template
+ template: `
+
+
+ {{crisis.id}} {{crisis.name}}
+
+
+ `,
+ // #enddocregion template
+})
+export class CrisisListComponent implements OnInit {
+ crises: Crisis[];
+
+ constructor(
+ private _service: CrisisService,
+ private _router: Router) {}
+
+ ngOnInit() {
+ this._service.getCrises().then(crises => this.crises = crises);
+ }
+
+ // #docregion select
+ onSelect(crisis: Crisis) {
+ this._router.navigate(['CrisisDetail', { id: crisis.id }] );
+ }
+ // #enddocregion select
+}
diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts
index dc08f1e747..d4ac1a040c 100644
--- a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts
+++ b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts
@@ -18,7 +18,7 @@ import {Router, RouteParams} from 'angular2/router';
})
export class CrisisListComponent implements OnInit {
crises: Crisis[];
- // #docregion isSelected
+
private _selectedId: number;
constructor(
@@ -27,19 +27,14 @@ export class CrisisListComponent implements OnInit {
routeParams: RouteParams) {
this._selectedId = +routeParams.get('id');
}
- // #enddocregion isSelected
+
+ isSelected(crisis: Crisis) { return crisis.id === this._selectedId; }
ngOnInit() {
this._service.getCrises().then(crises => this.crises = crises);
}
- // #docregion isSelected
- isSelected(crisis: Crisis) { return crisis.id === this._selectedId; }
- // #enddocregion isSelected
-
- // #docregion select
onSelect(crisis: Crisis) {
this._router.navigate( ['CrisisDetail', { id: crisis.id }] );
}
- // #enddocregion select
}
diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts
new file mode 100644
index 0000000000..96627686d5
--- /dev/null
+++ b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts
@@ -0,0 +1,44 @@
+// #docregion
+import {Component, OnInit} from 'angular2/core';
+import {Hero, HeroService} from './hero.service';
+import {RouteParams, Router} from 'angular2/router';
+
+@Component({
+ template: `
+ HEROES
+
+
"{{hero.name}}"
+
+ Id: {{hero.id}}
+
+ Name:
+
+
+
Back
+
+ `,
+})
+export class HeroDetailComponent implements OnInit {
+ hero: Hero;
+
+ // #docregion ctor
+ constructor(
+ private _router:Router,
+ private _routeParams:RouteParams,
+ private _service:HeroService){}
+ // #enddocregion ctor
+
+ // #docregion ngOnInit
+ ngOnInit() {
+ let id = this._routeParams.get('id');
+ this._service.getHero(id).then(hero => this.hero = hero);
+ }
+ // #enddocregion ngOnInit
+
+ // #docregion gotoHeroes
+ gotoHeroes() {
+ // Like Heroes
+ this._router.navigate(['Heroes']);
+ }
+ // #enddocregion gotoHeroes
+}
diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts
index 7d26ddafe7..eeccb1836b 100644
--- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts
+++ b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts
@@ -37,8 +37,13 @@ export class HeroDetailComponent implements OnInit {
// #docregion gotoHeroes
gotoHeroes() {
- // Heroes
- this._router.navigate(['Heroes']);
+ let heroId = this.hero ? this.hero.id : null;
+ // Pass along the hero id if available
+ // so that the HeroList component can select that hero.
+ // Add a totally useless `foo` parameter for kicks.
+ // #docregion gotoHeroes-navigate
+ this._router.navigate(['Heroes', {id: heroId, foo: 'foo'} ]);
+ // #enddocregion gotoHeroes-navigate
}
// #enddocregion gotoHeroes
}
diff --git a/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts b/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts
new file mode 100644
index 0000000000..78f5ad4cd4
--- /dev/null
+++ b/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts
@@ -0,0 +1,49 @@
+// #docplaster
+
+// #docregion
+// TODO SOMEDAY: Feature Componetized like HeroCenter
+import {Component, OnInit} from 'angular2/core';
+import {Hero, HeroService} from './hero.service';
+import {Router} from 'angular2/router';
+
+@Component({
+ // #docregion template
+ template: `
+ HEROES
+
+
+ {{hero.id}} {{hero.name}}
+
+
+ `
+ // #enddocregion template
+})
+export class HeroListComponent implements OnInit {
+ heroes: Hero[];
+
+ // #docregion ctor
+ constructor(
+ private _router: Router,
+ private _service: HeroService) { }
+ // #enddocregion ctor
+
+ ngOnInit() {
+ this._service.getHeroes().then(heroes => this.heroes = heroes)
+ }
+
+ // #docregion select
+ onSelect(hero: Hero) {
+ // #docregion nav-to-detail
+ this._router.navigate( ['HeroDetail', { id: hero.id }] );
+ // #enddocregion nav-to-detail
+ }
+ // #enddocregion select
+}
+// #enddocregion
+
+/* A link parameters array
+// #docregion link-parameters-array
+['HeroDetail', { id: hero.id }] // {id: 15}
+// #enddocregion link-parameters-array
+*/
\ No newline at end of file
diff --git a/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts
index 3a8de0408f..7957d8702c 100644
--- a/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts
+++ b/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts
@@ -1,10 +1,12 @@
// #docplaster
+// TODO SOMEDAY: Feature Componetized like CrisisCenter
// #docregion
-// TODO SOMEDAY: Feature Componetized like HeroCenter
import {Component, OnInit} from 'angular2/core';
import {Hero, HeroService} from './hero.service';
-import {Router} from 'angular2/router';
+// #docregion import-route-params
+import {Router, RouteParams} from 'angular2/router';
+// #enddocregion import-route-params
@Component({
// #docregion template
@@ -12,6 +14,7 @@ import {Router} from 'angular2/router';
HEROES
{{hero.id}} {{hero.name}}
@@ -21,29 +24,30 @@ import {Router} from 'angular2/router';
})
export class HeroListComponent implements OnInit {
heroes: Hero[];
- selectedHero: Hero;
// #docregion ctor
+ private _selectedId: number;
+
constructor(
+ private _service: HeroService,
private _router: Router,
- private _service: HeroService) { }
+ routeParams: RouteParams) {
+ this._selectedId = +routeParams.get('id');
+ }
// #enddocregion ctor
+ // #docregion isSelected
+ isSelected(hero: Hero) { return hero.id === this._selectedId; }
+ // #enddocregion isSelected
+
+ // #docregion select
+ onSelect(hero: Hero) {
+ this._router.navigate( ['HeroDetail', { id: hero.id }] );
+ }
+ // #enddocregion select
+
ngOnInit() {
this._service.getHeroes().then(heroes => this.heroes = heroes)
}
- // #docregion select
- onSelect(hero: Hero) {
- // #docregion nav-to-detail
- this._router.navigate( ['HeroDetail', { id: hero.id }] );
- // #enddocregion nav-to-detail
- }
- // #enddocregion select
}
// #enddocregion
-
-/* A link parameters array
-// #docregion link-parameters-array
-['HeroDetail', { id: hero.id }] // {id: 15}
-// #enddocregion link-parameters-array
-*/
\ No newline at end of file
diff --git a/public/docs/_examples/router/ts/index.1.html b/public/docs/_examples/router/ts/index.1.html
index 6d80ebdf84..d3deed5504 100644
--- a/public/docs/_examples/router/ts/index.1.html
+++ b/public/docs/_examples/router/ts/index.1.html
@@ -1,7 +1,4 @@
-
@@ -19,26 +16,20 @@
-
+ Milestone 1
loading...
diff --git a/public/docs/_examples/router/ts/index.2.html b/public/docs/_examples/router/ts/index.2.html
new file mode 100644
index 0000000000..e53a4725ce
--- /dev/null
+++ b/public/docs/_examples/router/ts/index.2.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+ Router Sample
+
+
+
+
+
+
+
+
+
+
+
+
+ Milestone 2
+ loading...
+
+
+
+
diff --git a/public/docs/_examples/router/ts/index.3.html b/public/docs/_examples/router/ts/index.3.html
new file mode 100644
index 0000000000..1c5e9c58ee
--- /dev/null
+++ b/public/docs/_examples/router/ts/index.3.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+ Router Sample
+
+
+
+
+
+
+
+
+
+
+
+
+ Milestone 3
+ loading...
+
+
+
+
diff --git a/public/docs/_examples/router/ts/styles.css b/public/docs/_examples/router/ts/styles.css
index bb2b2c9cd9..38d0ff595f 100644
--- a/public/docs/_examples/router/ts/styles.css
+++ b/public/docs/_examples/router/ts/styles.css
@@ -20,7 +20,9 @@ a:hover {color: white; background-color: #1171a3; }
a.router-link-active {color: white; background-color: #52b9e9; }
/* #enddocregion starter */
+/* #docregion selected */
.selected { background-color: #EEE; color: #369; }
+/* #enddocregion selected */
.badge {
font-size: small;
diff --git a/public/docs/ts/latest/guide/router.jade b/public/docs/ts/latest/guide/router.jade
index 92c9fb41f4..4def53e0cf 100644
--- a/public/docs/ts/latest/guide/router.jade
+++ b/public/docs/ts/latest/guide/router.jade
@@ -19,15 +19,52 @@ include ../../../../_includes/_util-fns
We can navigate imperatively when the user clicks a button, selects from a drop box,
or in response to some other stimulus from any source. And the router logs activity
in the browser's history journal so the back and forward buttons work as well.
+
+ We'll learn many router details in this chapter which covers
+
+ * [configuring a router](#route-config)
+ * the [link parameter arrays](#link-parameters-array) that propel router navigation
+ * navigating when the user clicks a data-bound [RouterLink](#router-link)
+ * navigating under [program control](#navigate)
+ * embedding critical information in the URL with [route parameters](#route-parameters)
+ * creating a [child router](#child-router) with its own routes
+ * setting a [default route](#default)
+ * confirming or canceling navigation with [router lifecycle hooks](#lifecycle-hooks)
+ * passing optional information in [query parameters](#query-parameters)
+
+ We proceed in phases marked by milestones building rom a simple two-pager with placeholder views
+ up to a modular, multi-view design with child routes.
+
+ Try that [live final version](/resources/live-examples/router/ts/plnkr.html).
+
+ But first, an overview of router basics.
- [Live Example](/resources/live-examples/router/ts/plnkr.html).
.l-main-section
:marked
## The Basics
Let's begin with a few core concepts of the Component Router.
Then we can explore the details through a sequence of examples.
+ ### Setup
+ The Component Router is an optional service that presents a particular component view for a given URL.
+ It is not part of the Angular 2 core. It is in its own library
+ within the Angular npm bundle.
+ We make it available by loading its script in our `index.html`, after
+ the Angular core script.
++makeExample('router/ts/index.html','router-lib')(format=".")
+:marked
+ ### *<base href>*
+ Most routing applications should add a ` ` element just after the `` tag
+ to tell the router how to compose navigation URLs.
- The **`Router`** is a service that presents a particular Component view for a given URL.
+ If the `app` folder is the application root, as it is for our sample application,
+ set the `href` value *exactly* as shown here.
+
++makeExample('router/ts/index.html','base-href')(format=".")
+.l-sub-section
+ :marked
+ We cover other options in the [details below](#browser-url-styles).
+:marked
+ ### Configuration
When the browser's URL changes, the router looks for a corresponding **`RouteDefinition`**
from which it can determine the Component to display.
@@ -51,6 +88,7 @@ include ../../../../_includes/_util-fns
will use that value to find and present the hero whose `id` is 42.
We'll learn more about route parameters later in this chapter.
:marked
+ ### Router Outlet
Now we know how the router gets its configuration.
When the browser URL for this application becomes `/heroes`,
the router matches that URL to the `RouteDefintion` named *Heroes* and displays the `HeroListComponent`
@@ -59,6 +97,7 @@ code-example(format="", language="html").
<!-- Routed views go here -->
<router-outlet></router-outlet>
:marked
+ ### Router Links
Now we have routes configured and a place to render them, but
how do we navigate? The URL could arrive directly from the browser address bar.
But most of the time we navigate as a result of some user action such as the click of
@@ -77,7 +116,7 @@ code-example(format="", language="html").
'CrisisCenter' and 'Heroes' are the names of the `Routes` we configured above.
We'll learn to write more complex link expressions — and why they are arrays —
- [later](#link-parameter-array) in the chapter.
+ [later](#link-parameters-array) in the chapter.
:marked
### Let's summarize
@@ -131,38 +170,25 @@ table
td.
An Angular component with an attached router.
:marked
- We'll learn many more details in this chapter which covers
-
- * [configuring a router](#route-config)
- * the [link parameter arrays](#link-parameters-array) that propel router navigation
- * navigating when the user clicks a data-bound [RouterLink](#router-link)
- * navigating under [program control](#navigate)
- * passing information in [route parameters](#route-parameter)
- * creating a [child router](#child-router) with its own routes
- * setting a [default route](#default)
- * pausing, confirming and/or canceling a navigation with the the `routerCanDeactivate` [router lifecycle hook](#lifecycle-hooks)
-
- We proceed in phases marked by milestones.
- Our first milestone is the ability to navigate between two placeholder views.
- At our last milestone, we'll have a modular, multi-view design with child routes.
-
- We assume that you're already comfortable with the basic Angular 2 tools and concepts
- we introduced in the [QuickStart](../quickstart.html) and
- the [Tour of Heroes](../tutorial/) tutorial.
-.l-sub-section
- :marked
- While we make incremental progress on a sample application, this chapter is not a tutorial.
- We discuss code and design decisions pertinent to routing and application design.
- We gloss over everything in between.
-
- The full source is available in the [live example](/resources/live-examples/router/ts/plnkr.html).
-:marked
-
+ We've barely touched the surface of the router and its capabilities.
+
+ The following detail sections describe a sample routing application
+ as it evolves over a sequence of milestones.
+ We strongly recommend taking the time to read and understand this story.
.l-main-section
:marked
## The Sample Application
We have an application in mind as we move from milestone to milestone.
+
+.l-sub-section
+ :marked
+ While we make incremental progress toward the ultimate sample application, this chapter is not a tutorial.
+ We discuss code and design decisions pertinent to routing and application design.
+ We gloss over everything in between.
+
+ The full source is available in the [live example](/resources/live-examples/router/ts/plnkr.html).
+:marked
Our client is the Hero Employment Agency.
Heroes need work and The Agency finds Crises for them to solve.
@@ -245,6 +271,7 @@ figure.image-display
The Component Router library is part of the Angular npm bundle.
We make it available by loading its script in our `index.html`, right after
the Angular core script.
+
+makeExample('router/ts/index.html','router-lib')(format=".")
:marked
### Set the *<base href>*
@@ -503,13 +530,13 @@ figure.image-display
Notice the `:id` token in the the path. That creates a slot in the path for a **Route Parameter**.
In this case, we're expecting the router to insert the `id` of a hero into that slot.
- If we tell the router to navigate to the detail component and display "Magenta", we expect hero `id` (15) to appear in the
+ If we tell the router to navigate to the detail component and display "Magneta", we expect hero `id` (15) to appear in the
browser URL like this:
code-example(format="." language="bash").
localhost:3000/hero/15
:marked
If a user enters that URL into the browser address bar, the router should recognize the
- pattern and go to the same "Magenta" detail view.
+ pattern and go to the same "Magneta" detail view.
### Navigate to the detail imperatively
@@ -522,28 +549,29 @@ code-example(format="." language="bash").
We'll adjust the `HeroListComponent` to implement these tasks, beginning with its constructor
which acquires the router service and the `HeroService` by dependency injection:
-+makeExample('router/ts/app/heroes/hero-list.component.ts','ctor')(format=".")
++makeExample('router/ts/app/heroes/hero-list.component.1.ts','ctor')(format=".")
:marked
We make a few changes to the template:
-+makeExample('router/ts/app/heroes/hero-list.component.ts','template')(format=".")
++makeExample('router/ts/app/heroes/hero-list.component.1.ts','template')(format=".")
:marked
The template defines an `*ngFor` repeater such as [we've seen before](displaying-data.html#ngFor).
There's a `(click)` [EventBinding](template-syntax.html#event-binding) to the component's `onSelect` method
which we implement as follows:
-+makeExample('router/ts/app/heroes/hero-list.component.ts','select')(format=".")
++makeExample('router/ts/app/heroes/hero-list.component.1.ts','select')(format=".")
:marked
It calls the router's **`navigate`** method with a **Link Parameters Array**.
This array is similar to the *link parameters array* we met [earlier](#shell-template) in an anchor tag while
binding to the `RouterLink` directive. This time we see it in code rather than in HTML.
-
- ### Setting the route parameter
+
+
+ ### Setting the route parameters object
We're navigating to the `HeroDetailComponent` where we expect to see the details of the selected hero.
We'll need *two* pieces of information: the destination and the hero's `id`.
Accordingly, the *link parameters array* has *two* items: the **name** of the destination route and a **route parameters object** that specifies the
`id` of the selected hero.
-+makeExample('router/ts/app/heroes/hero-list.component.ts','link-parameters-array')(format=".")
++makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".")
:marked
The router composes the appropriate two-part destination URL from this array:
code-example(format="." language="bash").
@@ -560,12 +588,12 @@ code-example(format="." language="bash").
As usual, we write a constructor that asks Angular to inject that service among the other services
that the component require and reference them as private variables.
-+makeExample('router/ts/app/heroes/hero-detail.component.ts','ctor')(format=".")
++makeExample('router/ts/app/heroes/hero-detail.component.1.ts','ctor')(format=".")
:marked
Later, in the `ngOnInit` method,
we ask the `RouteParams` service for the `id` parameter by name and
tell the `HeroService` to fetch the hero with that `id`.
-+makeExample('router/ts/app/heroes/hero-detail.component.ts','ngOnInit')(format=".")
++makeExample('router/ts/app/heroes/hero-detail.component.1.ts','ngOnInit')(format=".")
.l-sub-section
:marked
@@ -582,7 +610,7 @@ code-example(format="." language="bash").
The router `navigate` method takes the same one-item *link parameters array*
that we wrote for the `[routerLink]` directive binding.
It holds the **name of the `HeroListComponent` route**:
-+makeExample('router/ts/app/heroes/hero-detail.component.ts','gotoHeroes')(format=".")
++makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".")
:marked
### Heroes App Wrap-up
@@ -618,13 +646,11 @@ code-example(format="." language="bash").
Here are the relevant files for this version of the sample application.
+makeTabs(
`router/ts/app/app.component.2.ts,
- router/ts/app/boot.2.ts,
- router/ts/app/heroes/hero-list.component.ts,
- router/ts/app/heroes/hero-detail.component.ts,
+ router/ts/app/heroes/hero-list.component.1.ts,
+ router/ts/app/heroes/hero-detail.component.1.ts,
router/ts/app/heroes/hero.service.ts`,
- `,v2,,,`,
+ null,
`app.component.ts,
- boot.ts,
hero-list.component.ts,
hero-detail.component.ts,
hero.service.ts`)
@@ -714,7 +740,7 @@ code-example(format="." language="bash").
### Child Routing Component
We create a new `app/crisis-center` folder and add `crisis-center-component.ts` to it with the following contents:
-+makeExample('router/ts/app/crisis-center/crisis-center.component.ts', 'minus-imports', 'crisis-center/crisis-center.component.ts (minus imports)')
++makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'minus-imports', 'crisis-center/crisis-center.component.ts (minus imports)')
:marked
The `CrisisCenterComponent` parallels the `AppComponent`.
@@ -736,7 +762,7 @@ code-example(format="." language="bash").
### Service isolation
We add the `CrisisService` to the component's providers array
instead of registering it with the `bootstrap` function in `boot.ts`.
-+makeExample('router/ts/app/crisis-center/crisis-center.component.ts', 'providers')
++makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'providers')
:marked
This step limits the scope of that service to the *Crisis Center* component and its sub-component tree.
No component outside of the *Crisis Center* needs access to the `CrisisService`.
@@ -748,7 +774,7 @@ code-example(format="." language="bash").
The `@RouteConfig` decorator that adorns the `CrisisCenterComponent` class defines routes in much the same way
that we did earlier.
-+makeExample('router/ts/app/crisis-center/crisis-center.component.ts', 'route-config', 'app/crisis-center/crisis-center.component.ts (routes only)' )(format=".")
++makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'route-config', 'app/crisis-center/crisis-center.component.ts (routes only)' )(format=".")
:marked
There is an *important difference in the paths*. They both begin at `/`.
Normally such paths would refer to the root of the application.
@@ -807,7 +833,7 @@ code-example(format="").
We've tried the sample application and it didn't fail. We must have done something right.
Scroll to the end of the child `CrisisCenterComponent`s first route.
-+makeExample('router/ts/app/crisis-center/crisis-center.component.ts', 'default-route', 'app/crisis-center/crisis-center.component.ts (default route)')(format=".")
++makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'default-route', 'app/crisis-center/crisis-center.component.ts (default route)')(format=".")
:marked
There is `useAsDefault: true` again. That tells the router to compose the final URL using the path from the default child route.
Concatenate the base URL with `/crisis-center/` and `/`, remove extraneous slashes, and we get:
@@ -872,7 +898,7 @@ code-example(format="").
We discard the changes if the user presses he *Cancel* button.
Both buttons navigate back to the crisis list after save or cancel.
-+makeExample('router/ts/app/crisis-center/crisis-detail.component.ts', 'cancel-save', 'crisis-detail.component.ts (excerpt)')(format=".")
++makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'cancel-save', 'crisis-detail.component.ts (excerpt)')(format=".")
:marked
What if the user tries to navigate away without saving or canceling?
The user could push the browser back button or click the heroes link.
@@ -899,7 +925,7 @@ code-example(format="").
:marked
We execute the dialog inside the router's `routerCanDeactivate` lifecycle hook method.
-+makeExample('router/ts/app/crisis-center/crisis-detail.component.ts', 'routerCanDeactivate', 'crisis-detail.component.ts (excerpt)')
++makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'routerCanDeactivate', 'crisis-detail.component.ts (excerpt)')
:marked
Notice that the `routerCanDeactivate` method *can* return synchronously;
it returns `true` immediately if there is no crisis or there are no pending changes.
@@ -912,8 +938,196 @@ code-example(format="").
could navigate away. That's the router's job.
We simply write this method and let the router take it from there.
- The final code for the *Crisis Center* feature is [here](#crisis-center-structure-and-code).
+ The relevant *Crisis Center* code for this milestone is
+
++makeTabs(
+ `router/ts/app/crisis-center/crisis-center.component.ts,
+ router/ts/app/crisis-center/crisis-list.component.1.ts,
+ router/ts/app/crisis-center/crisis-detail.component.1.ts,
+ router/ts/app/crisis-center/crisis.service.ts
+ `,
+ null,
+ `crisis-center.component.ts,
+ crisis-list.component.ts,
+ crisis-detail.component.ts,
+ crisis.service.ts,
+ `)
+
+
+.l-main-section
+:marked
+ ## Milestone #4: Query Parameters
+
+ We use [*route parameters*](#route-parameters) to specify a parameterized value *within* the route URL
+ as we do when navigating to the `HeroDetailComponent` in order to view-and-edit the hero with *id:15*.
+code-example(format="." language="bash").
+ localhost:3000/hero/15
+:marked
+ Sometimes we wish to add optional information to a route request.
+ For example, the `HeroListComponent` doesn't need help to display a list of heroes.
+ But it might be nice if the previously-viewed hero were pre-selected when returning from the `HeroDetailComponent`.
+figure.image-display
+ img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero" width="175")
+:marked
+ That becomes possible if we can include hero Magneta's `id` in the URL when we
+ return from the `HeroDetailComponent`, a scenario we'll pursue in a moment.
+
+ Optional information takes other forms. Search criteria are often loosely structured, e.g., `name='wind*'`.
+ Multiple values are common — `after='12/31/2015' & before='1/1/2017'` — in no particular order —
+ `before='1/1/2017' & after='12/31/2015'` — in a variety of formats — `during='currentYear'` .
+
+ These kinds of parameters don't fit easily in a URL *path*. Even if we could define a suitable URL token scheme,
+ doing so greatly complicates the pattern matching required to translate an incoming URL to a named route.
+
+ The **URL query string** is the ideal vehicle for conveying arbitrarily complex information during navigation.
+ The query string isn't involved in pattern matching and affords enormous flexiblity of expression.
+ Almost anything serializable can appear in a query string.
+
+ The Component Router supports navigation with query strings as well as route parameters.
+ We define query string parameters in the *route parameters object* just like we do with route parameters.
+
+
+ ### Route parameters object
+ When navigating to the `HeroDetailComponent` we specified the `id` of the hero-to-edit in the
+ *route parameters object* and made it the second item of the [*link parameters array*](link-parameters-array).
+
++makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".")
+:marked
+ The router embedded the `id` value in the navigation URL because we had defined it
+ as a route parameter with an `:id` placeholder token in the route `path`:
++makeExample('router/ts/app/app.component.2.ts','hero-detail-route')(format=".")
+:marked
+ When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array*
+ which it uses to navigate back to the `HeroListComponent`.
++makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".")
+:marked
+ This array lacks a route parameters object because we had no reason to send information to the `HeroListComponent`.
+
+ Now we have a reason. We'd like to send the id of the current hero with the navigation request so that the
+ `HeroListComponent` can highlight that hero in its list.
+
+ We do that with a route parameters object in the same manner as before.
+ We also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore.
+ Here's the revised navigation statement:
++makeExample('router/ts/app/heroes/hero-detail.component.ts','gotoHeroes-navigate')(format=".")
+:marked
+ The application still works. Clicking "back" returns to the hero list view.
+
+ Look at the browser address bar. It should look something like this:
+code-example(format="." language="bash").
+ localhost:3000/heroes?id=15&foo=foo
+.l-sub-section
+ :marked
+ Unfortunately, the browser address bar does not change when running the live example in plunker.
+
+ You can take our word for it or
+ download the sample from within plunker, unzip it, and browse to `index.html`.
+ You may have to launch it in a local server such as
+ [http-server](https://www.npmjs.com/package/http-server) or [lite-server](https://github.com/johnpapa/lite-server).
+:marked
+ The `id` value appears in the query string (`?id=15&foo=foo`), not in the URL path.
+ The path for the "Heroes" route doesn't have an `:id` token.
+
+.alert.is-helpful
+ :marked
+ The router replaces route path tokens with corresponding values from the route parameters object.
+ **Every parameter _not_ consumed by a route path goes in the query string.**
+:marked
+ ### Query parameters in the *RouteParams* service
+
+ The list of heroes is unchanged. No hero row is highlighted.
+
+.l-sub-section
+ :marked
+ The [live example](/resources/live-examples/router/ts/plnkr.html) *does* highlight the selected
+ row because it demonstrates the final state of the application which includes the steps we're *about* to cover.
+ At the moment we're describing the state of affairs *prior* to those steps.
+:marked
+ The `HeroListComponent` isn't expecting any parameters at all and wouldn't know what to do with them.
+ Let's change that.
+
+ When navigating from the `HeroListComponent` to the `HeroDetailComponent`
+ the router picked up the route parameter object and made it available to the `HeroDetailComponent`
+ in the `RouteParams` service. We injected that service in the constructor of the `HeroDetailComponent`.
+
+ This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`.
+ This time we'll inject the `RouteParams` service in the constructor of the `HeroListComponent`.
+
+ First we extend the router import statement to include the `RouteParams` service symbol;
++makeExample('router/ts/app/heroes/hero-list.component.ts','import-route-params', 'hero-list.component.ts (import)')(format=".")
+:marked
+ Then we extend the constructor to inject the `RouteParams` service and extract the `id` parameter as the `_selectedId`:
++makeExample('router/ts/app/heroes/hero-list.component.ts','ctor', 'hero-list.component.ts (constructor)')(format=".")
+.l-sub-section
+ :marked
+ All route parameters are strings.
+ The (+) in front of the `routeParameters.get` expression is a JavaScript trick to convert the string to an integer.
+:marked
+ We add an `isSelected` method that returns true when a hero's id matches the selected id.
++makeExample('router/ts/app/heroes/hero-list.component.ts','isSelected', 'hero-list.component.ts (constructor)')(format=".")
+:marked
+ We update our template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method.
+ The binding adds the `selected` CSS class when the method returns `true` and removes it when `false`.
+ Look for it within the repeated `` tag as shown here:
++makeExample('router/ts/app/heroes/hero-list.component.ts','template', 'hero-list.component.ts (template)')(format=".")
+:marked
+ Finally, we add the `selected` class to our CSS styles
++makeExample('router/ts/styles.css','selected', 'styles.css (selected class)')(format=".")
+:marked
+ When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
+figure.image-display
+ img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected List" width="250")
+:marked
+ The `foo` query string parameter is harmless and continues to be ignored.
+
+ ### Child Routers and Query Parameters
+
+ We can define query parameters for child routers too.
+
+ The technique is precisely the same.
+ In fact, we made exactly the same changes to the *Crisis Center* feature.
+ Confirm the similarities in these *Hero* and *CrisisCenter* components,
+ arranged side-by-side for easy comparison:
++makeTabs(
+ `router/ts/app/heroes/hero-list.component.ts,
+ router/ts/app/crisis-center/crisis-list.component.ts,
+ router/ts/app/heroes/hero-detail.component.ts,
+ router/ts/app/crisis-center/crisis-detail.component.ts
+ `,
+ null,
+ `hero-list.component.ts,
+ crisis-list.component.ts,
+ hero-detail.component.ts,
+ crisis-detail.component.ts
+ `)
+:marked
+ When we navigate back from a `CrisisDetailComponent` that is showing the *Asteroid* crisis,
+ we see that crisis properly selected in the list like this:
+figure.image-display
+ img(src='/resources/images/devguide/router/selected-crisis.png' alt="Selected crisis" )
+:marked
+ **Look at the browser address bar again**. It's *different*. It looks something like this:
+code-example(format="." language="bash").
+ localhost:3000/crisis-center/;id=3;foo=foo
+:marked
+ The query string parameters are no longer separated by "?" and "&".
+ They are **separated by semicolons (;)**
+ This is *matrix URL* notation — something we may not have seen before.
+.l-sub-section
+ :marked
+ *Matrix URL* notation is an idea first floated
+ in a [1996 proposal](http://www.w3.org/DesignIssues/MatrixURIs.html) by the founder of the web, Tim Berners-Lee.
+
+ Although matrix notation never made it into the HTML standard, it is legal and
+ it became popular among browser routing systems as a way to isolate parameters
+ belonging to parent and child routes. The Angular Component Router is such a system.
+
+ The syntax may seem strange to us but users are unlikely to notice or care
+ as long as the URL can be emailed and pasted into a browser address bar
+ as this one can.
+
+
.l-main-section
:marked
@@ -1016,7 +1230,7 @@ code-example(format="").
.l-main-section
-
+
:marked
## Link Parameters Array
We've mentioned the *Link Parameters Array* several times. We've used it several times.
@@ -1025,7 +1239,7 @@ code-example(format="").
+makeExample('router/ts/app/app.component.3.ts', 'h-anchor')(format=".")
:marked
We've written a two element array when specifying a route parameter like this
-+makeExample('router/ts/app/heroes/hero-list.component.ts', 'nav-to-detail')(format=".")
++makeExample('router/ts/app/heroes/hero-list.component.1.ts', 'nav-to-detail')(format=".")
:marked
These two examples cover our needs for an app with one level routing.
The moment we add a child router, such as the *Crisis Center*, we create new link array possibilities.
@@ -1121,15 +1335,9 @@ code-example(format="").
When the router navigates to a new component view, it updates the browser's location and history
with a URL for that view.
- This is a strictly local URL. The browser shouldn't send a request to the server
+ This is a strictly local URL. The browser shouldn't send this URL to the server
and should not reload the page.
-.l-sub-section
- :marked
- We're talking now about the ***browser*** URL
- **not** the *route* URL that we record in a `RouteDefinition`.
- The browser URL is what we paste into the browser's **address bar**
- and email to folks so they can deep-link into an application page.
-:marked
+
Modern HTML 5 browsers support
[history.pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries),
a technique that changes a browser's location and history without triggering a server page request.
@@ -1142,13 +1350,18 @@ code-example(format=".", language="bash").
:marked
Older browsers send page requests to the server when the location URL changes ...
unless the change occurs after a "#" (called the "hash").
- Routers take advantage of this exception by composing in-application route
+ Routers can take advantage of this exception by composing in-application route
URLs with hashes. Here's a "hash URL" that routes to the *Crisis Center*
code-example(format=".", language="bash").
localhost:3002/src/#/crisis-center/
:marked
- The Angular Component Router supports both styles.
- We set our preference by providing a `LocationStrategy` during the bootstrapping process.
+ The Angular Component Router supports both styles with two `LocationStrategy` providers:
+ 1. `PathLocationStrategy` - the default "HTML 5 pushState" style.
+ 1. `HashLocationStrategy` - the "hash URL" style.
+
+ The router's `ROUTER_PROVIDERS` array sets the `LocationStrategy` to the `PathLocationStrategy`,
+ making it the default strategy.
+ We can switch to the `HashLocationStrategy` with an override during the bootstrapping process if we prefer it.
.l-sub-section
:marked
Learn about "providers" and the bootstrap process in the
@@ -1176,11 +1389,10 @@ code-example(format=".", language="bash").
resort to hash routes.
### HTML 5 URLs and the *<base href>*
- The router use the "[HTML 5 pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries)"
- style by default.
- We don't have to provide the router's `PathLocationStrategy` because it's loaded automatically.
-
- We *must* add a
+ While the router use the "[HTML 5 pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries)"
+ style by default, we *must* configure that strategy with a **base href**
+
+ The preferred way to configure the strategy is to add a
[<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag
in the `` of the `index.html`.
+makeExample('router/ts/index.html','base-href')(format=".")
@@ -1200,14 +1412,16 @@ code-example(format=".", language="bash").
.l-sub-section
:marked
- Learn about the [APP_BASE_HREF](https://angular.io/docs/ts/latest/api/router/APP_BASE_HREF-const.html)
+ Learn about the [APP_BASE_HREF](https://angular.io/docs/ts/latest/api/router/APP_BASE_HREF-let.html)
in the API Guide.
:marked
### *HashLocationStrategy*
We can go old-school with the `HashLocationStrategy` by
providing it as the router's `LocationStrategy` during application bootstrapping.
- That means importing `provide` for Dependency Injection and the
- `Location` and `HashLocationStrategy` symbols from the router,
- then providing that strategy in the call to `bootstrap`:
-+makeExample('router/ts/app/boot.2.ts', 'hash-strategy')
+ First, import the `provide` symbol for Dependency Injection and the
+ `Location` and `HashLocationStrategy` symbols from the router.
+
+ Then *override* the default strategy defined in `ROUTE_PROVIDERS` by
+ providing the `HashLocationStrategy` later in the `bootstrap` providers array argument:
++makeExample('router/ts/app/boot.2.ts','', 'boot.ts (hash URL strategy)')
diff --git a/public/resources/images/devguide/router/selected-crisis.png b/public/resources/images/devguide/router/selected-crisis.png
new file mode 100644
index 0000000000..8b625c31c8
Binary files /dev/null and b/public/resources/images/devguide/router/selected-crisis.png differ
diff --git a/public/resources/images/devguide/router/selected-hero.png b/public/resources/images/devguide/router/selected-hero.png
new file mode 100644
index 0000000000..d4ebd0aaed
Binary files /dev/null and b/public/resources/images/devguide/router/selected-hero.png differ