parent
872064e12e
commit
8e3e0834b5
|
@ -13,8 +13,10 @@ import {HeroListComponent} from './hero-list.component';
|
||||||
// #docregion template
|
// #docregion template
|
||||||
template: `
|
template: `
|
||||||
<h1>Component Router</h1>
|
<h1>Component Router</h1>
|
||||||
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
|
<nav>
|
||||||
<a [routerLink]="['Heroes']">Heroes</a>
|
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
|
||||||
|
<a [routerLink]="['Heroes']">Heroes</a>
|
||||||
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
`,
|
`,
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
|
|
|
@ -9,16 +9,20 @@ import {CrisisListComponent} from './crisis-list.component';
|
||||||
// #docregion hero-import
|
// #docregion hero-import
|
||||||
import {HeroListComponent} from './heroes/hero-list.component';
|
import {HeroListComponent} from './heroes/hero-list.component';
|
||||||
import {HeroDetailComponent} from './heroes/hero-detail.component';
|
import {HeroDetailComponent} from './heroes/hero-detail.component';
|
||||||
|
import {HeroService} from './heroes/hero.service';
|
||||||
// #enddocregion hero-import
|
// #enddocregion hero-import
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
template: `
|
template: `
|
||||||
<h1>Component Router</h1>
|
<h1>Component Router</h1>
|
||||||
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
|
<nav>
|
||||||
<a [routerLink]="['Heroes']">Heroes</a>
|
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
|
||||||
|
<a [routerLink]="['Heroes']">Heroes</a>
|
||||||
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
`,
|
`,
|
||||||
|
providers: [HeroService],
|
||||||
directives: [ROUTER_DIRECTIVES]
|
directives: [ROUTER_DIRECTIVES]
|
||||||
})
|
})
|
||||||
// #enddocregion
|
// #enddocregion
|
||||||
|
|
|
@ -7,6 +7,8 @@ import {CrisisCenterComponent} from './crisis-center/crisis-center.component';
|
||||||
import {HeroListComponent} from './heroes/hero-list.component';
|
import {HeroListComponent} from './heroes/hero-list.component';
|
||||||
import {HeroDetailComponent} from './heroes/hero-detail.component';
|
import {HeroDetailComponent} from './heroes/hero-detail.component';
|
||||||
|
|
||||||
|
import {DialogService} from './dialog.service';
|
||||||
|
import {HeroService} from './heroes/hero.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
|
@ -38,12 +40,15 @@ import {HeroDetailComponent} from './heroes/hero-detail.component';
|
||||||
// #docregion template
|
// #docregion template
|
||||||
template: `
|
template: `
|
||||||
<h1 class="title">Component Router</h1>
|
<h1 class="title">Component Router</h1>
|
||||||
<a [routerLink]="['CrisisCenter', 'CrisisCenter']">Crisis Center</a>
|
<nav>
|
||||||
<a [routerLink]="['CrisisCenter', 'CrisisDetail', {id:1}]">Princess Crisis</a>
|
<a [routerLink]="['CrisisCenter', 'CrisisCenter']">Crisis Center</a>
|
||||||
<a [routerLink]="['CrisisCenter', 'CrisisDetail', {id:2}]">Dragon Crisis</a>
|
<a [routerLink]="['CrisisCenter', 'CrisisDetail', {id:1}]">Princess Crisis</a>
|
||||||
|
<a [routerLink]="['CrisisCenter', 'CrisisDetail', {id:2}]">Dragon Crisis</a>
|
||||||
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
`,
|
`,
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
|
providers: [DialogService, HeroService],
|
||||||
directives: [ROUTER_DIRECTIVES]
|
directives: [ROUTER_DIRECTIVES]
|
||||||
})
|
})
|
||||||
@RouteConfig([
|
@RouteConfig([
|
||||||
|
|
|
@ -7,16 +7,22 @@ import {CrisisCenterComponent} from './crisis-center/crisis-center.component';
|
||||||
import {HeroListComponent} from './heroes/hero-list.component';
|
import {HeroListComponent} from './heroes/hero-list.component';
|
||||||
import {HeroDetailComponent} from './heroes/hero-detail.component';
|
import {HeroDetailComponent} from './heroes/hero-detail.component';
|
||||||
|
|
||||||
|
import {DialogService} from './dialog.service';
|
||||||
|
import {HeroService} from './heroes/hero.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-app',
|
selector: 'my-app',
|
||||||
// #docregion template
|
// #docregion template
|
||||||
template: `
|
template: `
|
||||||
<h1 class="title">Component Router</h1>
|
<h1 class="title">Component Router</h1>
|
||||||
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
|
<nav>
|
||||||
<a [routerLink]="['Heroes']">Heroes</a>
|
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
|
||||||
|
<a [routerLink]="['Heroes']">Heroes</a>
|
||||||
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
`,
|
`,
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
|
providers: [DialogService, HeroService],
|
||||||
directives: [ROUTER_DIRECTIVES]
|
directives: [ROUTER_DIRECTIVES]
|
||||||
})
|
})
|
||||||
// #docregion route-config
|
// #docregion route-config
|
||||||
|
|
|
@ -18,6 +18,6 @@ bootstrap(AppComponent, [
|
||||||
import {AppComponent as ac} from './app.component.1';
|
import {AppComponent as ac} from './app.component.1';
|
||||||
bootstrap(ac, [
|
bootstrap(ac, [
|
||||||
// #docregion all
|
// #docregion all
|
||||||
ROUTER_PROVIDERS,
|
ROUTER_PROVIDERS
|
||||||
]);
|
]);
|
||||||
// #enddocregion all
|
// #enddocregion all
|
|
@ -4,16 +4,11 @@
|
||||||
// #docplaster
|
// #docplaster
|
||||||
|
|
||||||
// #docregion v2
|
// #docregion v2
|
||||||
// #docregion hash-strategy
|
|
||||||
import {bootstrap} from 'angular2/platform/browser';
|
import {bootstrap} from 'angular2/platform/browser';
|
||||||
import {ROUTER_PROVIDERS} from 'angular2/router';
|
import {ROUTER_PROVIDERS} from 'angular2/router';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
// #enddocregion hash-strategy
|
|
||||||
import {HeroService} from './heroes/hero.service';
|
|
||||||
// #enddocregion v2
|
// #enddocregion v2
|
||||||
|
|
||||||
// #docregion hash-strategy
|
|
||||||
|
|
||||||
// Add these symbols to register a `LocationStrategy`
|
// Add these symbols to register a `LocationStrategy`
|
||||||
import {provide} from 'angular2/core';
|
import {provide} from 'angular2/core';
|
||||||
import {LocationStrategy,
|
import {LocationStrategy,
|
||||||
|
@ -21,27 +16,23 @@ import {LocationStrategy,
|
||||||
// #enddocregion hash-strategy
|
// #enddocregion hash-strategy
|
||||||
|
|
||||||
/* Can't use AppComponent ... but display as if we can
|
/* Can't use AppComponent ... but display as if we can
|
||||||
// #docregion v2,hash-strategy
|
// #docregion v2, hash-strategy
|
||||||
|
|
||||||
bootstrap(AppComponent, [
|
bootstrap(AppComponent, [
|
||||||
// #enddocregion v2,hash-strategy
|
// #enddocregion v2, hash-strategy
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Actually use the v.2 component
|
// Actually use the v.2 component
|
||||||
import {AppComponent as ac} from './app.component.2';
|
import {AppComponent as ac} from './app.component.2';
|
||||||
|
|
||||||
bootstrap(ac, [
|
bootstrap(ac, [
|
||||||
|
// #docregion v2, hash-strategy
|
||||||
|
ROUTER_PROVIDERS,
|
||||||
|
// #enddocregion v2, hash-strategy
|
||||||
// #docregion hash-strategy
|
// #docregion hash-strategy
|
||||||
|
|
||||||
provide(LocationStrategy,
|
provide(LocationStrategy,
|
||||||
{useClass: HashLocationStrategy}), // ~/src/#/crisis-center/
|
{useClass: HashLocationStrategy}) // ~/#/crisis-center/
|
||||||
|
|
||||||
// #enddocregion hash-strategy
|
// #enddocregion hash-strategy
|
||||||
// #docregion v2
|
// #docregion v2, hash-strategy
|
||||||
HeroService,
|
|
||||||
// #docregion hash-strategy
|
|
||||||
ROUTER_PROVIDERS
|
|
||||||
]);
|
]);
|
||||||
// #enddocregion hash-strategy
|
// #enddocregion v2, hash-strategy
|
||||||
// #enddocregion v2
|
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,5 @@ import {bootstrap} from 'angular2/platform/browser';
|
||||||
import {ROUTER_PROVIDERS} from 'angular2/router';
|
import {ROUTER_PROVIDERS} from 'angular2/router';
|
||||||
|
|
||||||
import {AppComponent} from './app.component.3';
|
import {AppComponent} from './app.component.3';
|
||||||
import {DialogService} from './dialog.service';
|
|
||||||
|
|
||||||
bootstrap(AppComponent, [
|
bootstrap(AppComponent, [ROUTER_PROVIDERS]);
|
||||||
ROUTER_PROVIDERS,
|
|
||||||
DialogService
|
|
||||||
]);
|
|
||||||
|
|
|
@ -3,11 +3,5 @@ import {bootstrap} from 'angular2/platform/browser';
|
||||||
import {ROUTER_PROVIDERS} from 'angular2/router';
|
import {ROUTER_PROVIDERS} from 'angular2/router';
|
||||||
|
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
import {DialogService} from './dialog.service';
|
|
||||||
import {HeroService} from './heroes/hero.service';
|
|
||||||
|
|
||||||
bootstrap(AppComponent, [
|
bootstrap(AppComponent, [ROUTER_PROVIDERS]);
|
||||||
ROUTER_PROVIDERS,
|
|
||||||
DialogService,
|
|
||||||
HeroService
|
|
||||||
]);
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {CanDeactivate, ComponentInstruction, Router} from 'angular2/router';
|
||||||
styles: ['input {width: 20em}']
|
styles: ['input {width: 20em}']
|
||||||
})
|
})
|
||||||
export class AddCrisisComponent implements CanDeactivate {
|
export class AddCrisisComponent implements CanDeactivate {
|
||||||
public editName: string;
|
editName: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _service: CrisisService,
|
private _service: CrisisService,
|
||||||
|
|
|
@ -22,8 +22,7 @@ import {CrisisService} from './crisis.service';
|
||||||
// #docregion default-route
|
// #docregion default-route
|
||||||
{path:'/', name: 'CrisisCenter', component: CrisisListComponent, useAsDefault: true},
|
{path:'/', name: 'CrisisCenter', component: CrisisListComponent, useAsDefault: true},
|
||||||
// #enddocregion default-route
|
// #enddocregion default-route
|
||||||
{path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent},
|
{path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent}
|
||||||
{path:'/list/:id', name: 'CrisisList', component: CrisisListComponent}
|
|
||||||
])
|
])
|
||||||
// #enddocregion route-config
|
// #enddocregion route-config
|
||||||
export class CrisisCenterComponent { }
|
export class CrisisCenterComponent { }
|
||||||
|
|
|
@ -31,8 +31,8 @@ import {DialogService} from '../dialog.service';
|
||||||
// #docregion routerCanDeactivate, cancel-save
|
// #docregion routerCanDeactivate, cancel-save
|
||||||
export class CrisisDetailComponent implements OnInit, CanDeactivate {
|
export class CrisisDetailComponent implements OnInit, CanDeactivate {
|
||||||
|
|
||||||
public crisis: Crisis;
|
crisis: Crisis;
|
||||||
public editName: string;
|
editName: string;
|
||||||
|
|
||||||
// #enddocregion routerCanDeactivate, cancel-save
|
// #enddocregion routerCanDeactivate, cancel-save
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -56,16 +56,17 @@ export class CrisisDetailComponent implements OnInit, CanDeactivate {
|
||||||
}
|
}
|
||||||
// #enddocregion ngOnInit
|
// #enddocregion ngOnInit
|
||||||
|
|
||||||
// #docregion canDeactivate
|
// #docregion routerCanDeactivate
|
||||||
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
|
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : any {
|
||||||
// Allow navigation (`true`) if no crisis or the crisis is unchanged.
|
// 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
|
// Otherwise ask the user with the dialog service and return its
|
||||||
// promise which resolves true-or-false when the user decides
|
// promise which resolves to true or false when the user decides
|
||||||
return !this.crisis ||
|
return this._dialog.confirm('Discard changes?');
|
||||||
this.crisis.name === this.editName ||
|
|
||||||
this._dialog.confirm('Discard changes?');
|
|
||||||
}
|
}
|
||||||
// #enddocregion canDeactivate
|
// #enddocregion routerCanDeactivate
|
||||||
|
|
||||||
// #docregion cancel-save
|
// #docregion cancel-save
|
||||||
cancel() {
|
cancel() {
|
||||||
|
@ -82,7 +83,9 @@ export class CrisisDetailComponent implements OnInit, CanDeactivate {
|
||||||
// #docregion gotoCrises
|
// #docregion gotoCrises
|
||||||
gotoCrises() {
|
gotoCrises() {
|
||||||
let route =
|
let route =
|
||||||
['CrisisList', {id: this.crisis ? this.crisis.id : null} ]
|
// 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);
|
this._router.navigate(route);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {Router, RouteParams} from 'angular2/router';
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class CrisisListComponent implements OnInit {
|
export class CrisisListComponent implements OnInit {
|
||||||
public crises: Crisis[];
|
crises: Crisis[];
|
||||||
// #docregion isSelected
|
// #docregion isSelected
|
||||||
private _selectedId: number;
|
private _selectedId: number;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {RouteParams, Router} from 'angular2/router';
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class HeroDetailComponent implements OnInit {
|
export class HeroDetailComponent implements OnInit {
|
||||||
public hero: Hero;
|
hero: Hero;
|
||||||
|
|
||||||
// #docregion ctor
|
// #docregion ctor
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -20,8 +20,8 @@ import {Router} from 'angular2/router';
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
})
|
})
|
||||||
export class HeroListComponent implements OnInit {
|
export class HeroListComponent implements OnInit {
|
||||||
public heroes: Hero[];
|
heroes: Hero[];
|
||||||
public selectedHero: Hero;
|
selectedHero: Hero;
|
||||||
|
|
||||||
// #docregion ctor
|
// #docregion ctor
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -202,7 +202,7 @@ figure.image-display
|
||||||
Both buttons navigate back to the *Crisis Center* and its list of crises.
|
Both buttons navigate back to the *Crisis Center* and its list of crises.
|
||||||
|
|
||||||
Suppose we click a crisis, make a change, but ***do not click either button***.
|
Suppose we click a crisis, make a change, but ***do not click either button***.
|
||||||
Maye we click the browser back button instead. Maybe we click the "Heroes" link.
|
Maybe we click the browser back button instead. Maybe we click the "Heroes" link.
|
||||||
|
|
||||||
Do either. Up pops a dialog box.
|
Do either. Up pops a dialog box.
|
||||||
figure.image-display
|
figure.image-display
|
||||||
|
@ -285,7 +285,7 @@ figure.image-display
|
||||||
We should only need this trick for the live example, not production code.
|
We should only need this trick for the live example, not production code.
|
||||||
:marked
|
:marked
|
||||||
### Booting with the router service providers
|
### Booting with the router service providers
|
||||||
Our app launches from the `boot.ts` file in the `~/app` folder so let's start there.
|
Our app launches from the `boot.ts` file in the `/app` folder so let's start there.
|
||||||
It's short and all of it is relevant to routing.
|
It's short and all of it is relevant to routing.
|
||||||
+makeExample('router/ts/app/boot.1.ts','all', 'boot.ts')(format=".")
|
+makeExample('router/ts/app/boot.1.ts','all', 'boot.ts')(format=".")
|
||||||
:marked
|
:marked
|
||||||
|
@ -438,7 +438,7 @@ figure.image-display
|
||||||
That's unrealistic and ultimately not maintainable.
|
That's unrealistic and ultimately not maintainable.
|
||||||
We think it's better to put each feature area in its own folder.
|
We think it's better to put each feature area in its own folder.
|
||||||
|
|
||||||
Our first step is to **create a separate `app/heroes/` folder**.
|
Our first step is to **create a separate `app/heroes/` folder**
|
||||||
and add *Hero Management* feature files there.
|
and add *Hero Management* feature files there.
|
||||||
|
|
||||||
We won't be creative about it. Our example is pretty much a
|
We won't be creative about it. Our example is pretty much a
|
||||||
|
@ -467,8 +467,8 @@ figure.image-display
|
||||||
.file hero-list.component.ts
|
.file hero-list.component.ts
|
||||||
.file hero.service.ts
|
.file hero.service.ts
|
||||||
:marked
|
:marked
|
||||||
We'll provide the `HeroService` during bootstrapping
|
We provide the `HeroService` in the application root `AppComponent`
|
||||||
so that is available everywhere in the app (see `boot.ts`) .
|
so that is available everywhere in the app.
|
||||||
|
|
||||||
Now it's time for some surgery to bring these files and the rest of the app
|
Now it's time for some surgery to bring these files and the rest of the app
|
||||||
into alignment with our application router.
|
into alignment with our application router.
|
||||||
|
@ -663,8 +663,8 @@ code-example(format="." language="bash").
|
||||||
`AppComponent` route configuration. If we rename a *Crisis Center* component or change a route definition,
|
`AppComponent` route configuration. If we rename a *Crisis Center* component or change a route definition,
|
||||||
we'll be changing the `AppComponent` too.
|
we'll be changing the `AppComponent` too.
|
||||||
|
|
||||||
* If we followed *Heroes* lead, we'd be adding the `CrisisService` to the providers in `boot.ts`.
|
* If we followed *Heroes* lead, we'd be adding the `CrisisService` to the providers in `app.component.ts`.
|
||||||
Now both `HeroService` and `CrisisService` would be available everywhere although
|
Then both `HeroService` and `CrisisService` would be available everywhere although
|
||||||
they're only needed in their respective feature modules. That stinks.
|
they're only needed in their respective feature modules. That stinks.
|
||||||
|
|
||||||
Changes to a sub-module such as *Crisis Center* shouldn't provoke changes to the `AppComponent` or `boot.ts`.
|
Changes to a sub-module such as *Crisis Center* shouldn't provoke changes to the `AppComponent` or `boot.ts`.
|
||||||
|
@ -746,19 +746,28 @@ code-example(format="." language="bash").
|
||||||
### Child Route Configuration
|
### Child Route Configuration
|
||||||
The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`.
|
The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`.
|
||||||
|
|
||||||
The `@RouteConfig` decorator that adorns the `CrisisCenterComponent` class defines routes in the same way
|
The `@RouteConfig` decorator that adorns the `CrisisCenterComponent` class defines routes in much the same way
|
||||||
that we did earlier.
|
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.ts', 'route-config', 'app/crisis-center/crisis-center.component.ts (routes only)' )(format=".")
|
||||||
:marked
|
:marked
|
||||||
There are three *Crisis Center* routes, two of them with an `id` parameter.
|
There is an *important difference in the paths*. They both begin at `/`.
|
||||||
They refer to components we haven't talked about yet but whose purpose we
|
Normally such paths would refer to the root of the application.
|
||||||
can guess by their names.
|
Here they refer to the **root of the child component!**.
|
||||||
|
|
||||||
We cannot tell by looking at the `CrisisCenterComponent` that it is a child component
|
The Component Router composes the final route by concatenating route paths beginning with the ancestor paths to this child router.
|
||||||
of an application. We can't tell that its routes are child routes.
|
In our example, there is one ancestor path: "crisis-center".
|
||||||
|
The final route to the `HeroDetailComponent` displaying hero 11 would be something like:
|
||||||
|
code-example(format="").
|
||||||
|
localhost:3000//crisis-center/11
|
||||||
|
:marked
|
||||||
|
We cannot know this simply by looking at the `CrisisCenterComponent` alone.
|
||||||
|
We can't tell that it is a *child* routing component.
|
||||||
|
We can't tell that its routes are child routes; they are indistinguiable from top level application routes.
|
||||||
|
|
||||||
That's intentional. The *Crisis Center* shouldn't know that it is the child of anything.
|
Such ignorance is intentional. The *Crisis Center* shouldn't know that it is the child of anything.
|
||||||
It might be the top level component of its own application. It might be repurposed in a different application.
|
Today it is a child component one level down.
|
||||||
|
Tomorrow it might be the top level component of its own application.
|
||||||
|
Next month it might be re-purposed in a different application.
|
||||||
The *Crisis Center* itself is indifferent to these possibilities.
|
The *Crisis Center* itself is indifferent to these possibilities.
|
||||||
|
|
||||||
*We* make it a child component of our application by reconfiguring the routes of the top level `AppComponent`.
|
*We* make it a child component of our application by reconfiguring the routes of the top level `AppComponent`.
|
||||||
|
@ -767,8 +776,9 @@ code-example(format="." language="bash").
|
||||||
Here is is the revised route configuration for the parent `AppComponent`:
|
Here is is the revised route configuration for the parent `AppComponent`:
|
||||||
+makeExample('router/ts/app/app.component.ts', 'route-config', 'app/app.component.ts (routes only)' )
|
+makeExample('router/ts/app/app.component.ts', 'route-config', 'app/app.component.ts (routes only)' )
|
||||||
:marked
|
:marked
|
||||||
The second and third *Hero* routes haven't changed.
|
The last two *Hero* routes haven't changed.
|
||||||
The first *Crisis Center* route has changed — *signficantly* — and we've formatted it to draw attention to the differences:
|
|
||||||
|
The first *Crisis Center* route has changed — *significantly* — and we've formatted it to draw attention to the differences:
|
||||||
+makeExample('router/ts/app/app.component.ts', 'route-config-cc')(format=".")
|
+makeExample('router/ts/app/app.component.ts', 'route-config-cc')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Notice that the **path ends with a slash and three trailing periods (`/...`)**.
|
Notice that the **path ends with a slash and three trailing periods (`/...`)**.
|
||||||
|
@ -794,7 +804,7 @@ code-example(format="." language="bash").
|
||||||
|
|
||||||
It could be any of the three. In the absence of additional information, the router can't decide and must throw an error.
|
It could be any of the three. In the absence of additional information, the router can't decide and must throw an error.
|
||||||
|
|
||||||
We've tried the sample application and it didn't fail. We must have done something.
|
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.
|
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.ts', 'default-route', 'app/crisis-center/crisis-center.component.ts (default route)')(format=".")
|
||||||
|
@ -879,9 +889,11 @@ code-example(format="").
|
||||||
by waiting for the user's answer asynchronously. Waiting for the user asynchronously
|
by waiting for the user's answer asynchronously. Waiting for the user asynchronously
|
||||||
is like waiting for the server asynchronously.
|
is like waiting for the server asynchronously.
|
||||||
:marked
|
:marked
|
||||||
The dialog service returns a [promise](http://www.html5rocks.com/en/tutorials/es6/promises/).
|
The `DialogService` (injected in the `AppComponent` for app-wide use) does the asking.
|
||||||
The promise *resolves* when the user eventually decides
|
|
||||||
to discard changes and navigate away (`true`) or keep the pending changes and stay in the crisis editor (`false`).
|
It returns a [promise](http://www.html5rocks.com/en/tutorials/es6/promises/) that
|
||||||
|
*resolves* when the user eventually decides what to do: either
|
||||||
|
to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`).
|
||||||
|
|
||||||
<a id="CanDeactivate"></a>
|
<a id="CanDeactivate"></a>
|
||||||
<a id="routerCanDeactivate"></a>
|
<a id="routerCanDeactivate"></a>
|
||||||
|
@ -890,17 +902,18 @@ code-example(format="").
|
||||||
+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.ts', 'routerCanDeactivate', 'crisis-detail.component.ts (excerpt)')
|
||||||
:marked
|
:marked
|
||||||
Notice that the `routerCanDeactivate` method *can* return synchronously;
|
Notice that the `routerCanDeactivate` method *can* return synchronously;
|
||||||
it returns `true` immediately if there are no pending changes.
|
it returns `true` immediately if there is no crisis or there are no pending changes.
|
||||||
But it can also return a promise and the router will wait for that promise
|
But it can also return a promise and the router will wait for that promise to resolve to truthy (navigate) or falsey (stay put).
|
||||||
to resolve before navigating away or staying put.
|
|
||||||
|
|
||||||
**Two critical points**
|
**Two critical points**
|
||||||
1. The router hook is optional. We don't inherit from a base class. We simply implement the method or not.
|
1. The router hook is optional. We don't inherit from a base class. We simply implement the interface method or not.
|
||||||
|
|
||||||
1. We rely on the router to call the hook. We don't worry about all the ways that the user
|
1. We rely on the router to call the hook. We don't worry about all the ways that the user
|
||||||
could navigate away. That's the router's job.
|
could navigate away. That's the router's job.
|
||||||
We simply write this method and let the router take it from there.
|
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).
|
||||||
|
|
||||||
<a id="final-app"></a>
|
<a id="final-app"></a>
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
|
|
Loading…
Reference in New Issue