docs(router): new chapter
Ward and Jeremy Todo: EXCLUDE Old router doc for reference while re-writing
|
@ -0,0 +1 @@
|
||||||
|
**/*.js
|
|
@ -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
|
|
@ -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
|
|
@ -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 { }
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
]);
|
|
@ -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']);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
@ -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 { }
|
|
@ -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?')));
|
||||||
|
};
|
||||||
|
}
|
|
@ -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 { }
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
*/
|
|
@ -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);
|
|
@ -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 -->
|
|
@ -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 -->
|
|
@ -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"]
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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
|
||||||
|
|
|
@ -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."
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
```
|
|
@ -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><script></code> tags into your
|
||||||
|
<code>index.html</code>:
|
||||||
|
|
||||||
|
//ANGULAR 1
|
||||||
|
pre.prettyprint.lang-html.is-angular1.is-hidden
|
||||||
|
code.
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<base href="/">
|
||||||
|
<title>My app</title>
|
||||||
|
</head>
|
||||||
|
<body ng-app="myApp" ng-controller="AppController as app">
|
||||||
|
<div ng-outlet></div>
|
||||||
|
<script src="/node_modules/angular/angular.js"></script>
|
||||||
|
<script src="/dist/router.es5.js"></script>
|
||||||
|
<script src="/app/app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
pre.prettyprint.lang-html.is-angular2
|
||||||
|
code.
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<base href="/">
|
||||||
|
<title>My app</title>
|
||||||
|
</head>
|
||||||
|
<body ng-app="myApp" ng-controller="AppController as app">
|
||||||
|
<script src="https://jspm.io/system@0.16.js"></script>
|
||||||
|
<script src="https://code.angularjs.org/2.0.0-alpha.21/angular2.dev.js"></script>
|
||||||
|
<script src="https://code.angularjs.org/2.0.0-alpha.21/router.dev.js"></script>
|
||||||
|
<script>
|
||||||
|
System.import('main');
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
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: '<router-outlet></router-outlet>',
|
||||||
|
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: '<router-outlet></router-outlet>',
|
||||||
|
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.
|
||||||
|
<h1>Hello {{home.name}}!</h1>
|
||||||
|
|
||||||
|
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><script></code> tag to our <code>index.html</code>:
|
||||||
|
pre.prettyprint.lang-html
|
||||||
|
code.
|
||||||
|
...
|
||||||
|
<script src="./components/home/home.js"></script>
|
||||||
|
|
||||||
|
//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.
|
||||||
|
<body ng-app="myApp" ng-controller="AppController as app">
|
||||||
|
<a ng-link="detail({id: 5})">link to detail</a>
|
||||||
|
...
|
||||||
|
|
||||||
|
pre.prettyprint.lang-html.is-angular2
|
||||||
|
code.
|
||||||
|
<a ng-link="detail({id: 5})">link to detail</a>
|
||||||
|
|
||||||
|
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.
|
||||||
|
<p>detail {{detail.id}}</p>
|
||||||
|
|
||||||
|
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
|
||||||
|
<div ng-outlet="master"></div>
|
||||||
|
<div ng-outlet="detail"></div>
|
||||||
|
|
||||||
|
|
||||||
|
//ANGULAR 2
|
||||||
|
.code-box.is-angular2
|
||||||
|
pre.prettyprint.linenums.lang-typescript(data-name="typescript")
|
||||||
|
code.
|
||||||
|
//TypeScript
|
||||||
|
@Component({})
|
||||||
|
@View({
|
||||||
|
template:
|
||||||
|
`<div router-outlet="master"></div>
|
||||||
|
<div router-outlet="detail"></div>`,
|
||||||
|
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:
|
||||||
|
'<div router-outlet="master"></div>' +
|
||||||
|
'<div router-outlet="detail"></div>',
|
||||||
|
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
|
||||||
|
<p>These both link to the same view:</p>
|
||||||
|
<a ng-link="userList">link to userList</a>
|
||||||
|
<a ng-link="user">link to user component</a>
|
||||||
|
|
||||||
|
//ANGULAR 2
|
||||||
|
pre.prettyprint.linenums.lang-html.is-angular2
|
||||||
|
code.
|
||||||
|
//HTML
|
||||||
|
<p>These both link to the same view:</p>
|
||||||
|
<a router-link="userList">link to userList</a>
|
||||||
|
<a router-link="user">link to user component</a>
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
<p>These both link to the same view:</p>
|
||||||
|
<a ng-link="master:userList">link to userList</a>
|
||||||
|
<a ng-link="detail:user">link to user component</a>
|
||||||
|
|
||||||
|
//ANGULAR 2
|
||||||
|
pre.prettyprint.linenums.lang-html.is-angular2
|
||||||
|
code.
|
||||||
|
//HTML
|
||||||
|
<p>These both link to the same view:</p>
|
||||||
|
<a router-link="master:userList">link to userList</a>
|
||||||
|
<a router-link="detail:user">link to user component</a>
|
||||||
|
|
||||||
|
.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
|
||||||
|
<a ng-link="user">link to user component</a>
|
||||||
|
|
||||||
|
//ANGULAR 2
|
||||||
|
pre.prettyprint.linenums.lang-html
|
||||||
|
code.
|
||||||
|
//HTML
|
||||||
|
<a router-link="user">link to user component</a>
|
||||||
|
|
||||||
|
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
|
||||||
|
<a ng-link="myUser">link to user component</a>
|
||||||
|
|
||||||
|
//ANGULAR 2
|
||||||
|
pre.prettyprint.linenums.lang-html
|
||||||
|
code.
|
||||||
|
//HTML
|
||||||
|
<a router-link="myUser">link to user component</a>
|
||||||
|
|
||||||
|
|
||||||
|
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>.
|
|
@ -784,15 +784,15 @@ figure.image-display
|
||||||
Here’s an example:
|
Here’s 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 template’s “match value” equals the “switch value”, Angular adds the template’s sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default template’s sub-tree to the DOM. Angular removes and destroys the sub-tree’s of all other templates.
|
If the template’s “match value” equals the “switch value”, Angular adds the template’s sub-tree to the DOM. If no template is a match and there is a default template, Angular adds the default template’s sub-tree to the DOM. Angular removes and destroys the sub-tree’s 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.
|
||||||
|
|
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 367 KiB |
After Width: | Height: | Size: 32 KiB |