docs(router): new chapter

Ward and Jeremy
Todo: EXCLUDE Old router doc for reference while re-writing
This commit is contained in:
Ward Bell 2015-12-10 09:40:54 -08:00 committed by Naomi Black
parent b05acd3b47
commit 0c1d7ca3cb
41 changed files with 2684 additions and 9 deletions

View File

@ -0,0 +1 @@
**/*.js

View File

@ -0,0 +1,39 @@
/* First version */
// #docplaster
// #docregion
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {CrisisListComponent} from './crisis-list.component';
import {HeroListComponent} from './hero-list.component';
@Component({
selector: 'my-app',
// #docregion template
template: `
<h1>Component Router</h1>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
<router-outlet></router-outlet>
`,
// #enddocregion template
directives: [ROUTER_DIRECTIVES]
})
// #enddocregion
/*
// #docregion route-config
@Component({ ... })
// #enddocregion route-config
*/
// #docregion
// #docregion route-config
@RouteConfig([
// #docregion route-defs
{path:'/crisis-center', name: 'CrisisCenter', component: CrisisListComponent},
{path:'/heroes', name: 'Heroes', component: HeroListComponent}
// #enddocregion route-defs
])
export class AppComponent { }
// #enddocregion route-config
// #enddocregion

View File

@ -0,0 +1,43 @@
/* Second Heroes version */
// #docplaster
// #docregion
import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {CrisisListComponent} from './crisis-list.component';
// #docregion hero-import
import {HeroListComponent} from './heroes/hero-list.component';
import {HeroDetailComponent} from './heroes/hero-detail.component';
// #enddocregion hero-import
@Component({
selector: 'my-app',
template: `
<h1>Component Router</h1>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
})
// #enddocregion
/*
// #docregion route-config
@Component({ ... })
// #enddocregion route-config
*/
// #docregion
// #docregion route-config
@RouteConfig([
// #docregion route-defs
{path:'/crisis-center', name: 'CrisisCenter', component: CrisisListComponent},
{path:'/heroes', name: 'Heroes', component: HeroListComponent},
// #docregion hero-detail-route
{path:'/hero/:id', name: 'HeroDetail', component: HeroDetailComponent}
// #enddocregion hero-detail-route
// #enddocregion route-defs
])
export class AppComponent { }
// #enddocregion route-config
// #enddocregion

View File

@ -0,0 +1,39 @@
// #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';
@Component({
selector: 'my-app',
// #docregion template
template: `
<h1 class="title">Component Router</h1>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
<router-outlet></router-outlet>
`,
// #enddocregion template
directives: [ROUTER_DIRECTIVES]
})
// #docregion route-config
@RouteConfig([
// #docregion route-config-cc
{ // Crisis Center child route
path: '/crisis-center/...',
name: 'CrisisCenter',
component: CrisisCenterComponent,
useAsDefault: true
},
// #enddocregion route-config-cc
{path: '/heroes', name: 'Heroes', component: HeroListComponent},
{path: '/hero/:id', name: 'HeroDetail', component: HeroDetailComponent},
{path: '/*other', redirectTo: ['Heroes']},
])
// #enddocregion route-config
export class AppComponent { }

View File

@ -0,0 +1,23 @@
/* First version */
// #docplaster
// #docregion all
import {AppComponent} from './app.component';
import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
// #enddocregion all
/* Can't use AppComponent ... but display as if we can
// #docregion all
bootstrap(AppComponent, [
// #enddocregion all
*/
// Actually use the v.1 component
import {AppComponent as ac} from './app.component.1';
bootstrap(ac, [
// #docregion all
ROUTER_PROVIDERS,
]);
// #enddocregion all

View File

@ -0,0 +1,47 @@
/* Second version */
// For Milestone #2
// Also includes digression on HashPathStrategy (not used in the final app)
// #docplaster
// #docregion v2
// #docregion hash-strategy
import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {AppComponent} from './app.component';
// #enddocregion hash-strategy
import {HeroService} from './heroes/hero.service';
// #enddocregion v2
// #docregion hash-strategy
// Add these symbols to register a `LocationStrategy`
import {provide} from 'angular2/core';
import {LocationStrategy,
HashLocationStrategy} from 'angular2/router';
// #enddocregion hash-strategy
/* Can't use AppComponent ... but display as if we can
// #docregion v2,hash-strategy
bootstrap(AppComponent, [
// #enddocregion v2,hash-strategy
*/
// Actually use the v.2 component
import {AppComponent as ac} from './app.component.2';
bootstrap(ac, [
// #docregion hash-strategy
provide(LocationStrategy,
{useClass: HashLocationStrategy}), // ~/src/#/crisis-center/
// #enddocregion hash-strategy
// #docregion v2
HeroService,
// #docregion hash-strategy
ROUTER_PROVIDERS
]);
// #enddocregion hash-strategy
// #enddocregion v2

View File

@ -0,0 +1,13 @@
// #docregion
import {bootstrap} from 'angular2/platform/browser';
import {ROUTER_PROVIDERS} from 'angular2/router';
import {AppComponent} from './app.component';
import {DialogService} from './dialog.service';
import {HeroService} from './heroes/hero.service';
bootstrap(AppComponent, [
ROUTER_PROVIDERS,
DialogService,
HeroService
]);

View File

@ -0,0 +1,41 @@
import {Component} from 'angular2/core';
import {Crisis, CrisisService} from './crisis.service';
import {DialogService} from '../dialog.service';
import {CanDeactivate, ComponentInstruction, Router} from 'angular2/router';
@Component({
template: `
<h2>"{{editName}}"</h2>
<div>
<label>Name: </label>
<input [(ngModel)]="editName" placeholder="name"/>
</div>
<button (click)="save()">Save</button>
<button (click)="cancel()">Cancel</button>
`,
styles: ['input {width: 20em}']
})
export class AddCrisisComponent implements CanDeactivate {
public editName: string;
constructor(
private _service: CrisisService,
private _router: Router,
private _dialog: DialogService) { }
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
return !!this.editName.trim() ||
this._dialog.confirm('Discard changes?');
}
cancel() { this.gotoCrises(); }
save() {
this._service.addCrisis(this.editName);
this.gotoCrises();
}
gotoCrises() {
this._router.navigate(['CrisisCenter']);
}
}

View File

@ -0,0 +1,29 @@
// #docregion
import {Component} from 'angular2/core';
import {RouteConfig, RouterOutlet} from 'angular2/router';
import {CrisisListComponent} from './crisis-list.component';
import {CrisisDetailComponent} from './crisis-detail.component';
import {CrisisService} from './crisis.service';
// #docregion minus-imports
@Component({
template: `
<h2>CRISIS CENTER</h2>
<router-outlet></router-outlet>
`,
directives: [RouterOutlet],
// #docregion providers
providers: [CrisisService]
// #enddocregion providers
})
// #docregion route-config
@RouteConfig([
{path:'/', name: 'CrisisCenter', component: CrisisListComponent, useAsDefault: true},
{path:'/list/:id', name: 'CrisisList', component: CrisisListComponent},
{path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent}
])
// #enddocregion route-config
export class CrisisCenterComponent { }
// #enddocregion minus-imports
// #enddocregion

View File

@ -0,0 +1,90 @@
// #docplaster
// #docregion
import {Component, OnInit} from 'angular2/core';
import {Crisis, CrisisService} from './crisis.service';
import {RouteParams, Router} from 'angular2/router';
// #docregion ngCanDeactivate
import {CanDeactivate, ComponentInstruction} from 'angular2/router';
import {DialogService} from '../dialog.service';
// #enddocregion ngCanDeactivate
@Component({
// #docregion template
template: `
<div *ngIf="crisis">
<h3>"{{editName}}"</h3>
<div>
<label>Id: </label>{{crisis.id}}</div>
<div>
<label>Name: </label>
<input [(ngModel)]="editName" placeholder="name"/>
</div>
<button (click)="save()">Save</button>
<button (click)="cancel()">Cancel</button>
</div>
`,
// #enddocregion template
styles: ['input {width: 20em}']
})
// #docregion ngCanDeactivate, cancel-save
export class CrisisDetailComponent implements OnInit, CanDeactivate {
public crisis: Crisis;
public editName: string;
// #enddocregion ngCanDeactivate, 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 canDeactivate
routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
return !this.crisis ||
this.crisis.name === this.editName ||
this._dialog.confirm('Discard changes?');
}
// #enddocregion canDeactivate
// #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() {
let route =
['CrisisList', {id: this.crisis ? this.crisis.id : null} ]
this._router.navigate(route);
}
// #enddocregion gotoCrises
// #docregion ngCanDeactivate, cancel-save
}
// #enddocregion ngCanDeactivate, cancel-save
// #enddocregion

View File

@ -0,0 +1,45 @@
// #docplaster
// #docregion
import {Component, OnInit} from 'angular2/core';
import {Crisis, CrisisService} from './crisis.service';
import {Router, RouteParams} from 'angular2/router';
@Component({
template: `
<ul>
<li *ngFor="#crisis of crises"
[class.selected]="isSelected(crisis)"
(click)="onSelect(crisis)">
<span class="badge">{{crisis.id}}</span> {{crisis.name}}
</li>
</ul>
`,
})
export class CrisisListComponent implements OnInit {
public crises: Crisis[];
// #docregion isSelected
private _selectedId: number;
constructor(
private _service: CrisisService,
private _router: Router,
routeParams: RouteParams) {
this._selectedId = +routeParams.get('id');
}
// #enddocregion isSelected
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
}

View File

@ -0,0 +1,41 @@
// #docplaster
// #docregion
import {Injectable} from 'angular2/core';
export class Crisis {
constructor(public id: number, public name: string) { }
}
@Injectable()
export class CrisisService {
getCrises() { return crisesPromise; }
getCrisis(id: number | string) {
return crisesPromise
.then(crises => crises.filter(c => c.id === +id)[0]);
}
// #enddocregion
static nextCrisisId = 100;
addCrisis(name:string) {
name = name.trim();
if (name){
let crisis = new Crisis(CrisisService.nextCrisisId++, name);
crisesPromise.then(crises => crises.push(crisis));
}
}
// #docregion
}
var crises = [
new Crisis(1, 'Princess Held Captive'),
new Crisis(2, 'Dragon Burning Cities'),
new Crisis(3, 'Giant Asteroid Heading For Earth'),
new Crisis(4, 'Release Deadline Looms')
];
var crisesPromise = Promise.resolve(crises);
// #enddocregion

View File

@ -0,0 +1,10 @@
// Initial empty version
// #docregion
import {Component} from 'angular2/core';
@Component({
template: `
<h2>CRISIS CENTER</h2>
<p>Get your crisis here</p>`
})
export class CrisisListComponent { }

View File

@ -0,0 +1,18 @@
// #docregion
import {Injectable} from 'angular2/core';
/**
* Async modal dialog service
* DialogService makes this app easier to test by faking this service.
* TODO: better modal implemenation that doesn't use window.confirm
*/
@Injectable()
export class DialogService {
/**
* Ask user to confirm an action. `message` explains the action and choices.
* Returns promise resolving to `true`=confirm or `false`=cancel
*/
confirm(message?:string) {
return new Promise<boolean>((resolve, reject) =>
resolve(window.confirm(message || 'Is it OK?')));
};
}

View File

@ -0,0 +1,10 @@
/// Initial empty version
// #docregion
import {Component} from 'angular2/core';
@Component({
template: `
<h2>HEROES</h2>
<p>Get your heroes here</p>`
})
export class HeroListComponent { }

View File

@ -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: `
<h2>HEROES</h2>
<div *ngIf="hero">
<h3>"{{hero.name}}"</h3>
<div>
<label>Id: </label>{{hero.id}}</div>
<div>
<label>Name: </label>
<input [(ngModel)]="hero.name" placeholder="name"/>
</div>
<button (click)="gotoHeroes()">Back</button>
</div>
`,
})
export class HeroDetailComponent implements OnInit {
public 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() {
// <a [routerLink]="['Heroes']">Heroes</a>
this._router.navigate(['Heroes']);
}
// #enddocregion gotoHeroes
}

View File

@ -0,0 +1,47 @@
// #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: `
<h2>HEROES</h2>
<ul>
<li *ngFor="#hero of heroes"
(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
`
// #enddocregion template
})
export class HeroListComponent implements OnInit {
public heroes: Hero[];
public selectedHero: 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) {
this._router.navigate( ['HeroDetail', { id: hero.id }] );
}
// #enddocregion select
}
// #enddocregion
/* A link parameters array
// #docregion link-parameters-array
['HeroDetail', { id: hero.id }] // {id: 15}
// #enddocregion link-parameters-array
*/

View File

@ -0,0 +1,27 @@
// #docregion
import {Injectable} from 'angular2/core';
export class Hero {
constructor(public id: number, public name: string) { }
}
@Injectable()
export class HeroService {
getHeroes() { return heroesPromise; }
getHero(id: number | string) {
return heroesPromise
.then(heroes => heroes.filter(h => h.id === +id)[0]);
}
}
var HEROES = [
new Hero(11, 'Mr. Nice'),
new Hero(12, 'Narco'),
new Hero(13, 'Bombasto'),
new Hero(14, 'Celeritas'),
new Hero(15, 'Magneta'),
new Hero(16, 'RubberMan')
];
var heroesPromise = Promise.resolve(HEROES);

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<script>
var boot = 'app/boot'+'.2'; // choices: '.1', '.2', ''
</script>
<!-- #docregion -->
<html>
<head>
<!-- #docregion base-href -->
<base href="/">
<!-- #enddocregion base-href -->
<title>Router Sample</title>
<link rel="stylesheet" href="styles.css">
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<!-- #docregion router-lib -->
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<!-- #enddocregion router-lib -->
<script>
System.config({
packages: {'app': {defaultExtension: 'js'}}
});
// window.boot is for our testing; you should just use 'app/boot'
System.import(window.boot||'app/boot').catch(console.log.bind(console));
</script>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>
<!-- #enddocregion -->

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<!-- #docregion -->
<html>
<head>
<!-- #docregion base-href -->
<base href="/">
<!-- #enddocregion base-href -->
<title>Router Sample</title>
<link rel="stylesheet" href="styles.css">
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<!-- #docregion router-lib -->
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<!-- #enddocregion router-lib -->
<script>
System.config({
packages: {'app': {defaultExtension: 'js'}}
});
System.import('app/boot').catch(console.log.bind(console));
</script>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>
<!-- #enddocregion -->

View File

@ -0,0 +1,12 @@
{
"description": "Router",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[1,2,3].*",
"!app/crisis-list.component.ts",
"!app/hero-list.component.ts",
"!app/crisis-center/add-crisis.component.ts"
],
"tags": ["router"]
}

View File

@ -0,0 +1,36 @@
/* #docregion */
/* #docregion heroes */
/* #docregion starter */
h1 {color: #369; font-family: Arial, Helvetica, sans-serif; font-size: 250%;}
h2 { color: #369; font-family: Arial, Helvetica, sans-serif; }
h3 { color: #444; font-weight: lighter; }
body { margin: 2em; }
body, input[text], button { color: #888; font-family: Cambria, Georgia; }
button {padding: 0.2em; font-size: 14px}
ul {list-style-type: none; margin-left: 1em; padding: 0; width: 20em;}
li { cursor: pointer; position: relative; left: 0; transition: all 0.2s ease; }
li:hover {color: #369; background-color: #EEE; left: .2em;}
/* route-link anchor tags */
a {padding: 5px; text-decoration: none; font-family: Arial, Helvetica, sans-serif; }
a:visited, a:link {color: #444;}
a:hover {color: white; background-color: #1171a3; }
a.router-link-active {color: white; background-color: #52b9e9; }
/* #enddocregion starter */
.selected { background-color: #EEE; color: #369; }
.badge {
font-size: small;
color: white;
padding: 0.1em 0.7em;
background-color: #369;
line-height: 1em;
position: relative;
left: -1px;
top: -1px;
}
/* #enddocregion heroes */
/* #enddocregion */

View File

@ -122,7 +122,7 @@ export class AppComponent {
// #docregion setStyles2 // #docregion setStyles2
setStyles2() { setStyles2() {
return { return {
// camelCase style properties works too // camelCase style properties work too
fontStyle: this.canSave ? 'italic' : 'normal', // italic fontStyle: this.canSave ? 'italic' : 'normal', // italic
fontWeight: !this.isUnchanged ? 'bold' : 'normal', // normal fontWeight: !this.isUnchanged ? 'bold' : 'normal', // normal
fontSize: this.isSpecial ? 'x-large': 'smaller', // larger fontSize: this.isSpecial ? 'x-large': 'smaller', // larger

View File

@ -43,6 +43,11 @@
"intro": "Pipes transform displayed values within a template" "intro": "Pipes transform displayed values within a template"
}, },
"router": {
"title": "Routing & Navigation",
"intro": "Discover the basics of screen navigation with the Angular 2 router"
},
"attribute-directives": { "attribute-directives": {
"title": "Attribute Directives", "title": "Attribute Directives",
"intro": "Attribute directives attach behavior to elements." "intro": "Attribute directives attach behavior to elements."

View File

@ -399,9 +399,21 @@
and taking other similar actions that cause the application to and taking other similar actions that cause the application to
replace one view with another. replace one view with another.
The [Angular router](./router.html) is a richly featured mechanism for configuring The Angular [Component Router](./router.html) is a richly featured mechanism for configuring
and managing the entire navigation process including the creation and destruction and managing the entire view navigation process including the creation and destruction
of views. of views.
:marked
## Routing Component
.l-sub-section
:marked
A [Component](#component) with an attached router.
In most cases, the component became attached to a [router](#router) by means
of a `@RouterConfig` decorator that defined routes to views controlled by this component.
The component's template has a `RouterOutlet` element where it can display views produced by the router.
It likely has anchor tags or buttons with `RouterLink` directives that users can click to navigate.
.l-main-section .l-main-section
<a id="S"></a> <a id="S"></a>

View File

@ -0,0 +1,183 @@
//
TODO: REVIVE AUX ROUTE MATERIAL WHEN THAT FEATURE WORKS AS EXPECTED
<a id="chat-feature"></a>
.l-main-section
:marked
## Milestone #4: Auxiliary Routes
Auxiliary routes are routes that can be activated independently of the current
route. They are entirely optional, depending on your app needs.
For example, your application may have a modal that appears and this could
be an auxiliary route. The modal may have its own navigation needs, such as a slideshow
and that auxiliary route is able to manage the navigation stack independently of the
primary routes.
In our sample application, we also want to have a chat feature that allows people
the ability to have a live agent assist them. The chat window will have first an
initial route that contains a prompt to ask the visitor if they'd like to chat with
an agent. Once they initiate a chat, they go to a new route for the chat experience.
.alert.is-critical Make diagram of chat routes
:marked
In this auxiliary chat experience, it overlays the current screen and persists.
If you navigate from the Heros to Crisis Center, the chat auxiliary route remains
active and in view.
Therefore the auxiliary routing is truly independent of the other
routing. In most respects, an auxiliary route behaves the same outside of it is rendered
in its own outlet and modifies the url differently.
We'll look at how to setup an auxiliary route and considerations for when to use them.
### Auxiliary Route Outlet
In order to get an auxiliary route, it needs a place to be rendered. So far the app has
a single `RouterOutet` that the rest of our routes are rendered into. Auxiliary routes need to
have their own `RouterOutlet`, and that is done by giving it a name attribute. Open the
`app.component.ts` file and let's add the new outlet to the template.
.alert.is-critical Should remove app.component.4.ts based example (next) when we know what's what
+_makeExample('router/ts/app/app.component.4.ts', 'chat-outlet', 'app/app.component.ts')
.alert.is-critical Should be able to project from app.component.ts like this
+_makeExample('router/ts/app/app.component.ts', 'template', 'app/app.component.ts (excerpt)')
:marked
The name of the outlet must be unique to the component. You could reuse the name across
different components, so you don't have to worry about collisions.
Here we give it a name of "chat", which will be used by the router when we setup our
route configs. The app component needs to know about this Auxiliary route, so we
import the `ChatComponent`, add a new ROUTE_NAME (`chat`),
and add a new 'Chat' route to the `ROUTES` in `app.routes.ts` (just below the redirect) .
+_makeExample('router/ts/app/routes.ts', null, 'app/routes.ts')
:marked
Look again at the 'Chat' route
+_makeExample('router/ts/app/routes.ts','chat-route')
:marked
You can see the route definition is nearly the same, except instead of `path` there is
an `aux`. The `aux` property makes this an Auxiliary route.
@TODO Explain how a named outlet is paired with an aux route.
The chat component defines its own routes just like the other components, even though
it is an Auxiliary route.
+_makeExample('router/ts/app/chat/routes.ts', null, 'app/chat/routes.ts')
:marked
Even though this is an Auxiliary route, you notice there is no difference in how we've
configured the route config for the primary chat component. The chat component also has
the `RouterOutlet` Directive in the template so the child components render inside of
the chat window.
In the chat components, we can use `RouterLink` to reference routes just the same as
a normal route. Since this is inside of an Auxiliary route, these relative links will
resolve within the chat component and not change the primary route (the Crisis Center or
Heros pages).
+_makeExample('router/ts/app/chat/chat-init.component.ts', 'chat-links')
:marked
When the chat component opens, it first initializes this template to ask the user if
they'd like to chat or not. If they agree, it takes them to the chat window where they
begin to send messages to the 'live' agent.
The behavior of the chat components may be interesting, but have no additional insights
for routing, except for the ability to deactivate an active Auxiliary route.
### Exiting an Auxiliary Route
@TODO Figure out how to close/deactivate an aux route
### Auxiliary Route URLs
Auxiliary Routes do modify the url using parens, like so.
code-example(format=".", language="bash").
localhost:3002/crisis-center(chat)/2(details)
:marked
This would be the url on a page where the user was viewing an item in the Crisis Center,
in this case the "Dragon Burning Cities" crisis, and the `(chat)` Auxiliary Route would
active and on the details child route.
### Multiple Auxiliary Routes
There is no limit to how many Auxiliary Routes you have defined or active. There is probably
a practical limit where too much appears on the screen for a user, but you can have as many
Auxiliary Routes as you have named `RouteOutlet`s.
:marked
### Auxiliary Route Summary
* Auxiliary routes are normal routes that are rendered outside of the primary `RouterOutlet`
* They must use a named `RouterOutlet` to render.
* Can be activated as long as the parent component is active.
* Links inside of child components are resolved against the aux parent component.
* Auxiliary routes are deactivated by @TODO?
* Routes are indicated in the url using parens.
* Multiple aux routes can be active at once.
### Chat
The "Chat" feature area within the `chat` folder looks like this:
```
app/
chat/
├── chat-detail.component.ts
├── chat-init.component.ts
├── chat.component.ts
├── chat.service.ts
└── routes.ts
```
+_makeTabs(
`router/ts/app/chat/chat.component.ts,
router/ts/app/chat/routes.ts,
router/ts/app/chat/chat-init.component.ts,
router/ts/app/chat/chat-detail.component.ts,
router/ts/app/chat/chat.service.ts
`,
null,
`chat.component.ts,
chat/routes.ts,
chat-init.component.ts,
chat-detail.component.ts,
chat.service.ts,
`)
The following are styles extracted from `styles.css`
that only belong if/when we add chat back
```
/* chat styles */
.chat {
position: fixed;
bottom: 0;
right: 20px;
border: 1px solid #1171a3;
width: 400px;
height: 300px;
}
.chat h2 {
background: #1171a3;
color: #fff;
margin: 0;
padding: 8px;
}
.chat .close {
float: right;
display: block;
padding: 0 10px;
cursor: pointer;
}
.chat .chat-content {
padding: 10px;
}
.chat .chat-messages {
height: 190px;
overflow-y: scroll;
}
.chat .chat-input {
border-top: 1px solid #ccc;
padding-top: 10px;
}
.chat .chat-input input {
width: 370px;
padding: 3px;
}
```

View File

@ -0,0 +1,724 @@
.l-main-section
h2#section-route-use Using the Component Router
p There are three steps to setting up routing with Angular's Component Router
ol
li Install the Component Router
li Map paths to components
li Link to routes
.l-main-section
h2#section-install-router Import the Component Router
p.
Create two files, <code>index.html</code> and <code>app.ts</code>, both at the root of the project:
pre.prettyprint.lang-bash
code.
touch index.html app.ts
p Your app directory should look something like:
pre.prettyprint.lang-bash
code.
app.ts
index.html
package.json
node_modules/
└── ...
p.
Because the component is an addition to the core, you must install Angular's Component Router into your app.
When using the angular2.dev.js bundle you have include the additional router.dev.js bundle.
p.
Add Angular and Component Router into your app by adding the relevant <code>&lt;script&gt;</code> tags into your
<code>index.html</code>:
//ANGULAR 1
pre.prettyprint.lang-html.is-angular1.is-hidden
code.
&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;base href=&quot;/&quot;&gt;
&lt;title&gt;My app&lt;/title&gt;
&lt;/head&gt;
&lt;body ng-app=&quot;myApp&quot; ng-controller=&quot;AppController as app&quot;&gt;
&lt;div ng-outlet&gt;&lt;/div&gt;
&lt;script src=&quot;/node_modules/angular/angular.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/dist/router.es5.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;/app/app.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
pre.prettyprint.lang-html.is-angular2
code.
&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;base href=&quot;/&quot;&gt;
&lt;title&gt;My app&lt;/title&gt;
&lt;/head&gt;
&lt;body ng-app=&quot;myApp&quot; ng-controller=&quot;AppController as app&quot;&gt;
&lt;script src=&quot;https://jspm.io/system@0.16.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://code.angularjs.org/2.0.0-alpha.21/angular2.dev.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://code.angularjs.org/2.0.0-alpha.21/router.dev.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
System.import(&#39;main&#39;);
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
p.is-angular2.
Then you can add the router into your app by importing the Router module in your <code>app.ts</code> file:
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
import {Component, View, bootstrap} from 'angular2/angular2';
import {Router, RouterOutlet, RouterLink} from 'angular2/router';
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
// self-executing bundle deploys angular APIs on the window object.
window.angular;
// the router APIs are part of the router sub-object.
window.angular.router;
p.is-angular1.is-hidden.
This is a pretty typical angular app, except the <code>ng-outlet</code> directive. <code>ng-outlet</code> is like
<code>ng-view</code>; it's a placeholder for part of your app loaded dynamically based on the route configuration.
p.is-angular2.
This is the same as you've seen in the rest of Angular 2, except the <code>router-outlet</code> directive.
<code>router-outlet</code> is a placeholder for part of your app loaded dynamically based on the route configuration.
p So how do we configure the app? Let's open <code>app.ts</code> and find out. Add this to the file:
//ANGULAR 1
pre.prettyprint.lang-javascript.is-angular1.is-hidden
code.
angular.module('app', ['ngNewRouter'])
.controller('AppController', ['$router', AppController]);
AppController.$routeConfig = [
{path: '/', component: 'home' }
];
function AppController ($router) {}
// ANGULAR 2
.code-box
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
import {Component, View, bootstrap} from 'angular2/angular2';
import {routerInjectables, RouterOutlet} from 'angular2/router';
import {HomeComp} from './components/home';
@Component({
selector: 'my-app'
})
@View({
template: '&lt;router-outlet&gt;&lt;/router-outlet&gt;',
directives: [RouterOutlet]
})
@RouteConfig([
{path: '/', component: HomeComp }
])
class AppComp {}
bootstrap(AppComp, routerInjectables);
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
var HomeComp = function() {};
...
var AppComp = function() {};
AppComp.annotations = [
new angular.ComponentAnnotation({
selector: 'my-app'
}),
new angular.ViewAnnotation({
template: '&lt;router-outlet&gt;&lt;/router-outlet&gt;',
directives: [angular.router.RouterOutlet]
}),
new angular.router.RouteConfigAnnotation([
{path: '/', component: HomeComp}
])
];
angular.bootstrap(AppComp, routerInjectables);
p.is-angular1.is-hidden.
The <code>ngComponentRouter</code> module provides a new service, <code>$router</code>. In the configuration, we map paths
to components. What's a component? Let's talk about that for a bit.
p.is-angular2.
The <code>angular2/router</code> module provides <code>routerInjectables</code>, which is an array of all of the services
you'll need to use the component router in your app.
.l-main-section
h2#section-map-paths-to-components Map paths to components
//- TODO - Alex - would it make more sense to have some paragraph styles conditionalized like this??
p.angular1.is-hidden.
In Angular 1, a "routable component" is a template, plus a controller, plus a router. You can configure how to map
component names to controllers and templates in the <code>$componentLoader</code> service.
p.
A component's template can have "outlets," which are holes in the DOM for loading parts of your app based on the
route configuration and it can ask the DI system for an instance of Router. A component's router tells the component what to put
inside the outlets based on URL. The configuration maps routes to components for each outlet.
p Let's make a <code>home</code> component that our app can route to:
pre.prettyprint.lang-bash
code.
mkdir -p components/home
touch components/home/home.html components/home/home.js
p This creates our component directory and its corresponding files: a template and a JavaScript component.
p Let's open <code>home.html</code> and add some content:
pre.prettyprint.lang-html
code.
&lt;h1&gt;Hello {{home.name}}!&lt;/h1&gt;
p.is-angular1.is-hidden.
Components use the "controller as" syntax, so if we want to access property <code>name</code> of the controller, we
write the binding as <code>home.name</code>.
p Let's make a controller:
//ANGULAR 1
pre.prettyprint.lang-javascript.is-angular1.is-hidden
code.
angular.module('app.home', [])
.controller('HomeController', [function () {
this.name = 'Friend';
}]);
// ANGULAR 2
.code-box
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
@Component({
selector: 'home-cmp'
})
@View({
template: 'Hello {{name}}'
})
export class HomeComponent {
name:string;
constructor() {
this.name = 'Friend';
}
}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
function HomeComponent() {
this.name = 'Friend';
}
AppComponent.annotations = [
new angular.ComponentAnnotation({
selector: 'home-cmp'
}),
new angular.ViewAnnotation({
template: 'Hello {{name}}'
})
];
p.is-angular1.is-hidden.
To wire this up, we need to add a <code>&lt;script&gt;</code> tag to our <code>index.html</code>:
pre.prettyprint.lang-html
code.
...
&lt;script src=&quot;./components/home/home.js&quot;&gt;&lt;/script&gt;
//ANGULAR 1
p.is-angular1.is-hidden.
And add the controller's module as a dependency to our main module in <code>app.js</code>:
pre.prettyprint.lang-javascript.is-angular1.is-hidden
code.
angular.module('app', ['ngNewRouter', 'app.home'])
.controller('AppController', ['$router', AppController]);
// ...
p.
To wire this up, we need to import the component into the rest of our app.
// ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
import {HomeComp} from './components/home';
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
// Use your favorite module system / bundler for ES5.
p If you load up the app, you should see <code>Hello Friend!</code>
.l-main-section
h2#section-link-to-routes Link to routes
p Let's add another route and then link to it. This route will have a route parameter, <code>id</code>.
p In <code>app.js</code>:
//ANGULAR 1
pre.prettyprint.lang-javascript.is-hidden
code.
angular.module('app', ['ngNewRouter'])
.controller('AppController', ['$router', AppController]);
AppController.$routeConfig = [
{ path: '/', component: 'home' },
{ path: '/detail/:id', component: 'detail' }
];
function AppController ($router) {}
// ANGULAR 2
.code-box
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
...
@RouteConfig([
{ path: '/', component: HomeComp },
{ path: '/detail/:id', component: DetailComp }
])
class AppComp {}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
var AppComp = function() {};
AppComp.annotations = [
...
new angular.router.RouteConfigAnnotation([
{ path: '/', component: HomeComp}
{ path: '/detail/:id', component: DetailComp }
])
];
angular.bootstrap(AppComp, routerInjectables);
p.
We can link to our detail component using the
<code class="is-angular2">router-link</code><code class="is-angular1 is-hidden">ng-link</code> directive.
Add this to <code class="is-angular2">template</code><code class="is-angular1 is-hidden">index.html</code>:
pre.prettyprint.lang-html.is-angular1.is-hidden.
code.
&lt;body ng-app=&quot;myApp&quot; ng-controller=&quot;AppController as app&quot;&gt;
&lt;a ng-link=&quot;detail({id: 5})&quot;&gt;link to detail&lt;/a&gt;
...
pre.prettyprint.lang-html.is-angular2
code.
&lt;a ng-link=&quot;detail({id: 5})&quot;&gt;link to detail&lt;/a&gt;
p This directive will generate an <code>href</code> and update the browser URL.
p We should also implement our detail component. Let's make these new files:
pre.prettyprint.lang-bash
code.
mkdir components/detail
touch components/detail/detail.html components/detail/detail.ts
p In <code>detail.ts</code>, we implement a controller that uses the <code>id</code> route parameter:
//ANGULAR 1
pre.prettyprint.lang-javascript.is-hidden
code.
angular.module('app.detail', ['ngNewRouter'])
.controller('DetailController', ['$routeParams', DetailController]);
function DetailController ($routeParams) {
this.id = $routeParams.id;
}
// ANGULAR 2
.code-box
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
@Component({
selector: 'detail-cmp'
})
@View({
template: 'User ID: {{id}}'
})
export class DetailComp {
id: string;
constructor(routeParams:RouteParams) {
this.id = routeParams.get('id');
}
}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
function DetailComp(routeParams) {
this.id = routeParams.get('id');
}
DetailComp.annotations = [
new angular.ComponentAnnotation({
selector: 'detail-cmp'
}),
new angular.ViewAnnotation({
template: 'User ID: {{id}}'
})
];
DetailComp.parameters = [[RouteParams]];
p.is-angular1.is-hidden.
And then we can display the <code>id</code> in our template by adding this to <code>detail.html</code>:
pre.prettyprint.lang-html.is-angular1.is-hidden
code.
&lt;p&gt;detail {{detail.id}}&lt;/p&gt;
p.is-angular1.is-hidden.
Finally, we'd wire up the controller by adding a script tag and making our <code>app</code> module depend on
<code>app.detail</code>.
.l-main-section
h2#section-configuring-the-router Configuring the Router
p.
Unlike other routing systems, Component Router maps URLs to components. A router takes an array of pairings like
this:
//ANGULAR 1
pre.prettyprint.lang-javascript.is-angular1.is-hidden
code.
//ES5
MyController.$routeConfig = [
{ path: '/user', component: 'user' }
];
//ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-javascript(data-name="typescript")
code.
@Component()
@View()
@RouteConfig([
{ path: '/user', component: UserComponent }
])
class MyComp {}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
function MyComp() {};
MyComp.annotations = [
new angular.ComponentAnnotation({ ... }),
new angular.ViewAnnotation({ ... }),
new angular.router.RouteConfigAnnotation([
{path: '/', component: UserComponent}
])
.l-sub-section
h3#section-sibling-outlets Sibling Outlets
p You can configure multiple outlets on the same path like this:
//ANGULAR 1
.codebox.is-angular1.is-hidden
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
//ES5
MyController.$routeConfig = [
{ path: '/user',
components: {
master: 'userList',
detail: 'user'
} }
];
pre.prettyprint.linenums.lang-html(data-name="html")
code.
//HTML
&lt;div ng-outlet=&quot;master&quot;&gt;&lt;/div&gt;
&lt;div ng-outlet=&quot;detail&quot;&gt;&lt;/div&gt;
//ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
//TypeScript
@Component({})
@View({
template:
`&lt;div router-outlet="master"&gt;&lt;/div&gt;
&lt;div router-outlet="detail"&gt;&lt;/div&gt;`,
directives: [RouterOutlet, RouterLink]
})
@RouteConfig({
path: '/user', components: {
master: UserListComp,
detail: UserComp
}
})
class MyComponent {}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
function MyComponent() {};
MyComponent.annotations = [
new angular.ComponentAnnotation({ ... }),
new angular.ViewAnnotation({
template:
'&lt;div router-outlet="master"&gt;&lt;/div&gt;' +
'&lt;div router-outlet="detail"&gt;&lt;/div&gt;',
directives: [RouterOutlet]
}),
new angular.router.RouteConfigAnnotation([{
path: '/user', components: {
master: UserComponent,
detail: UserComp
}
}])
];
p You can link to any sibling just as you normally would:
//ANGULAR 1
pre.prettyprint.linenums.lang-html.is-angular1.is-hidden
code.
//HTML
&lt;p&gt;These both link to the same view:&lt;/p&gt;
&lt;a ng-link=&quot;userList&quot;&gt;link to userList&lt;/a&gt;
&lt;a ng-link=&quot;user&quot;&gt;link to user component&lt;/a&gt;
//ANGULAR 2
pre.prettyprint.linenums.lang-html.is-angular2
code.
//HTML
&lt;p&gt;These both link to the same view:&lt;/p&gt;
&lt;a router-link=&quot;userList&quot;&gt;link to userList&lt;/a&gt;
&lt;a router-link=&quot;user&quot;&gt;link to user component&lt;/a&gt;
p Or, you can explicitly link to a outlet-component pair like this:
//ANGULAR 1
pre.prettyprint.linenums.lang-html.is-angular1.is-hidden
code.
//HTML
&lt;p&gt;These both link to the same view:&lt;/p&gt;
&lt;a ng-link=&quot;master:userList&quot;&gt;link to userList&lt;/a&gt;
&lt;a ng-link=&quot;detail:user&quot;&gt;link to user component&lt;/a&gt;
//ANGULAR 2
pre.prettyprint.linenums.lang-html.is-angular2
code.
//HTML
&lt;p&gt;These both link to the same view:&lt;/p&gt;
&lt;a router-link=&quot;master:userList&quot;&gt;link to userList&lt;/a&gt;
&lt;a router-link=&quot;detail:user&quot;&gt;link to user component&lt;/a&gt;
.l-sub-section
h3#section-redirecting-routes Redirecting routes
p You can use `redirectTo` for migrating to a new URL scheme and setting up default routes.
p.
For example, as specified below, when a user navigates to `/`, the URL changes to `/user` and the outlet
at that level loads the `user` component.
//ANGULAR 1
pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5")
code.
//ES5
MyController.$routeConfig = [
{ path: '/', redirectTo: '/user' },
{ path: '/user', component: 'user' }
];
function MyController() {}
//ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
//TypeScript
@Component({})
@View({
directives: [RouterOutlet]
})
@RouteConfig([
{ path: '/', redirectTo: '/user' },
{ path: '/user', component: UserComp }
])
class MyComp {}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
function MyComponent() {};
MyComponent.annotations = [
new angular.ComponentAnnotation({ ... }),
new angular.ViewAnnotation({
directives: [RouterOutlet]
}),
new angular.router.RouteConfigAnnotation([
{ path: '/user', component: UserComp }
{ path: '/', redirectTo: '/user' },
])
];
.l-sub-section
h3#section-aliases Aliases
p.
When linking to a route, you normally use the name of the component. You can also specify an alias to use
instead.
p Consider the following route configuration:
//ANGULAR 1
pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5")
code.
//ES5
MyController.$routeConfig = [
{ path: '/', component: 'user' }
];
//ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
//TypeScript
@Component({
selector: 'my-comp'
})
@View({
directives: [RouterOutlet]
})
@RouteConfig([
{ path: '/', component: UserComp }
])
class MyComp {}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
function MyComp() {};
MyComp.annotations = [
new angular.ComponentAnnotation({ ... }),
new angular.ViewAnnotation({
directives: [RouterOutlet]
}),
new angular.router.RouteConfigAnnotation([
{ path: '/', component: UserComp }
])
];
p We can link to the route in our template with the name of the component:
//ANGULAR 1
pre.prettyprint.linenums.lang-html.is-angular1.is-hidden
code.
//HTML
&lt;a ng-link=&quot;user&quot;&gt;link to user component&lt;/a&gt;
//ANGULAR 2
pre.prettyprint.linenums.lang-html
code.
//HTML
&lt;a router-link=&quot;user&quot;&gt;link to user component&lt;/a&gt;
p Or, we can define an alias <code>myUser</code> like this:
//ANGULAR 1
pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5")
code.
//ES5
MyController.$routeConfig = [
{ path: '/', component: 'user', as: 'myUser' }
];
//ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
//TypeScript
@Component()
@View()
@RouteConfig([
{ path: '/', component: UserComp, as: 'myUser' }
])
class MyComp {}
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
//ES5
//TODO: Need Angular 2 ES5 Example here
p And refer instead to the alias for the component in our template, with the same end-result:
//ANGULAR 1
pre.prettyprint.linenums.lang-html.is-angular1.is-hidden
code.
//HTML
&lt;a ng-link=&quot;myUser&quot;&gt;link to user component&lt;/a&gt;
//ANGULAR 2
pre.prettyprint.linenums.lang-html
code.
//HTML
&lt;a router-link=&quot;myUser&quot;&gt;link to user component&lt;/a&gt;
p.
This is especially useful when you have sibling components, but want to refer to an entire level of routing in
your controller. For example:
//ANGULAR 1
pre.prettyprint.linenums.lang-javascript.is-angular1.is-hidden(data-name="es5")
code.
//ES5
MyController.$routeConfig = [
{ path: '/',
components: {
master: 'userList',
detail: 'user'
},
as: 'myUser'
}
];
//ANGULAR 2
.code-box.is-angular2
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
code.
//TypeScript
@RouteConfig([
{ path: '/', components:
{ master: UserListComp, detail: UserComp },
as: 'myUser' }
])
pre.prettyprint.linenums.lang-javascript(data-name="es5")
code.
new angular.router.RouteConfigAnnotation([
{ path: '/', components:
{ master: UserListComp, detail: UserComp },
as: 'myUser' }
])
//- TODO(btford): expand on this.
.l-sub-section
h3#dynamic-configuration Dynamic Configuration
p.is-angular2.
You can configure dynamic routing by asking the DI system for a <code>Router</code>.
p.is-angular1.is-hidden
You can configure dynamic routing by making a request for <code>$router</code>.

File diff suppressed because it is too large Load Diff

View File

@ -784,15 +784,15 @@ figure.image-display
Heres an example: Heres an example:
+makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch')(format=".") +makeExample('template-syntax/ts/app/app.component.html', 'NgSwitch')(format=".")
:marked :marked
We bind the parent `NgSwitch` element to an expression returning a “switch value”. The value is a string in this example but it can be a value of any type. We bind the parent `NgSwitch` directive to an expression returning a “switch value”. The value is a string in this example but it can be a value of any type.
The parent `NgSwitch` element controls a set of child`<template>` elements. Each `<template>` wraps a candidate subtree. A template is either pegged to a “match value” expression or marked as the default template. The parent `NgSwitch` directive controls a set of child`<template>` elements. Each `<template>` wraps a candidate subtree. A template is either pegged to a “match value” expression or marked as the default template.
**At any particular moment, only one of these templates will be rendered** **At any particular moment, only one of these templates will be rendered**
If the templates “match value” equals the “switch value”, Angular adds the templates sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default templates sub-tree to the DOM. Angular removes and destroys the sub-trees of all other templates. If the templates “match value” equals the “switch value”, Angular adds the templates sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default templates sub-tree to the DOM. Angular removes and destroys the sub-trees of all other templates.
There are three related directives at work here. There are three collaborating directives at work here.
1. `ngSwitch` - bound to an expression that returns the switch value. 1. `ngSwitch` - bound to an expression that returns the switch value.
1. `ngSwitchWhen` - bound to an expression returning a match value. 1. `ngSwitchWhen` - bound to an expression returning a match value.
1. `ngSwitchDefault` - a marker attribute on the default template. 1. `ngSwitchDefault` - a marker attribute on the default template.

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB