docs(toh-5): dashboard uses [routerLink] bindings #998 (#2718)

* docs(toh-5): dashboard uses [routerLink] bindings #998
closes #998

* chore: temp add toh-5 to bad-code-excerpt-skip-patterns.txt
This commit is contained in:
Ward Bell 2016-11-03 10:25:01 -07:00 committed by GitHub
parent ae35f0e017
commit fa99a8b0b2
21 changed files with 189 additions and 268 deletions

View File

@ -0,0 +1,9 @@
<!-- #docregion -->
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<div *ngFor="let hero of heroes" class="col-1-4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</div>
</div>

View File

@ -1,6 +1,12 @@
/* #docregion */ /* #docregion */
[class*='col-'] { [class*='col-'] {
float: left; float: left;
text-decoration: none;
padding-right: 20px;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
} }
*, *:after, *:before { *, *:after, *:before {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
@ -10,12 +16,8 @@
h3 { h3 {
text-align: center; margin-bottom: 0; text-align: center; margin-bottom: 0;
} }
[class*='col-'] { h4 {
padding-right: 20px; position: relative;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
} }
.grid { .grid {
margin: 0; margin: 0;
@ -32,9 +34,6 @@ h3 {
background-color: #607D8B; background-color: #607D8B;
border-radius: 2px; border-radius: 2px;
} }
h4 {
position: relative;
}
.module:hover { .module:hover {
background-color: #EEE; background-color: #EEE;
cursor: pointer; cursor: pointer;

View File

@ -1,14 +1,13 @@
// #docplaster // #docplaster
// #docregion // #docregion
// #docregion imports
import 'dart:async'; import 'dart:async';
import 'package:angular2/core.dart'; import 'package:angular2/core.dart';
// #docregion import-router
import 'package:angular2/router.dart';
// #enddocregion import-router
import 'hero.dart'; import 'hero.dart';
import 'hero_service.dart'; import 'hero_service.dart';
// #enddocregion imports
@Component( @Component(
selector: 'my-dashboard', selector: 'my-dashboard',
@ -24,24 +23,14 @@ class DashboardComponent implements OnInit {
List<Hero> heroes; List<Hero> heroes;
// #docregion ctor // #docregion ctor
final Router _router;
final HeroService _heroService; final HeroService _heroService;
DashboardComponent(this._heroService, this._router); DashboardComponent(this._heroService);
// #enddocregion ctor // #enddocregion ctor
Future<Null> ngOnInit() async { Future<Null> ngOnInit() async {
heroes = (await _heroService.getHeroes()).skip(1).take(4).toList(); heroes = (await _heroService.getHeroes()).skip(1).take(4).toList();
} }
// #docregion gotoDetail
void gotoDetail(Hero hero) {
var link = [
'HeroDetail',
{'id': hero.id.toString()}
];
_router.navigate(link);
}
// #enddocregion gotoDetail
} }
// #enddocregion component

View File

@ -2,10 +2,10 @@
<h3>Top Heroes</h3> <h3>Top Heroes</h3>
<div class="grid grid-pad"> <div class="grid grid-pad">
<!-- #docregion click --> <!-- #docregion click -->
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4" > <a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">
<!-- #enddocregion click --> <!-- #enddocregion click -->
<div class="module hero"> <div class="module hero">
<h4>{{hero.name}}</h4> <h4>{{hero.name}}</h4>
</div> </div>
</div> </a>
</div> </div>

View File

@ -1,26 +0,0 @@
// #docplaster
// #docregion imports
import 'dart:async';
import 'package:angular2/core.dart';
import 'hero.dart';
import 'hero_service.dart';
// #enddocregion imports
// #docregion component
@Component(
selector: 'my-dashboard',
templateUrl: 'dashboard_component.html')
class DashboardComponent implements OnInit {
List<Hero> heroes;
final HeroService _heroService;
DashboardComponent(this._heroService);
Future<Null> ngOnInit() async {
heroes = (await _heroService.getHeroes()).skip(1).take(4).toList();
}
gotoDetail(Hero hero) {/* not implemented yet */}
}

View File

@ -42,16 +42,16 @@ describe('Tutorial part 5', () => {
beforeAll(() => browser.get('')); beforeAll(() => browser.get(''));
function getPageElts() { function getPageElts() {
let hrefElts = element.all(by.css('my-app a')); let navElts = element.all(by.css('my-app nav a'));
return { return {
hrefs: hrefElts, navElts: navElts,
myDashboardHref: hrefElts.get(0), myDashboardHref: navElts.get(0),
myDashboard: element(by.css('my-app my-dashboard')), myDashboard: element(by.css('my-app my-dashboard')),
topHeroes: element.all(by.css('my-app my-dashboard > div h4')), topHeroes: element.all(by.css('my-app my-dashboard > div h4')),
myHeroesHref: hrefElts.get(1), myHeroesHref: navElts.get(1),
myHeroes: element(by.css('my-app my-heroes')), myHeroes: element(by.css('my-app my-heroes')),
allHeroes: element.all(by.css('my-app my-heroes li')), allHeroes: element.all(by.css('my-app my-heroes li')),
selectedHero: element(by.css('my-app li.selected')), selectedHero: element(by.css('my-app li.selected')),
@ -73,7 +73,7 @@ describe('Tutorial part 5', () => {
const expectedViewNames = ['Dashboard', 'Heroes']; const expectedViewNames = ['Dashboard', 'Heroes'];
it(`has views ${expectedViewNames}`, () => { it(`has views ${expectedViewNames}`, () => {
let viewNames = getPageElts().hrefs.map((el: ElementFinder) => el.getText()); let viewNames = getPageElts().navElts.map((el: ElementFinder) => el.getText());
expect(viewNames).toEqual(expectedViewNames); expect(viewNames).toEqual(expectedViewNames);
}); });

View File

@ -0,0 +1,9 @@
<!-- #docregion -->
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<div *ngFor="let hero of heroes" class="col-1-4">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</div>
</div>

View File

@ -1,27 +0,0 @@
// #docplaster
// #docregion imports
import { Component, OnInit } from '@angular/core';
import { Hero } from './hero';
import { HeroService } from './hero.service';
// #enddocregion imports
@Component({
moduleId: module.id,
selector: 'my-dashboard',
templateUrl: 'dashboard.component.html'
})
// #docregion component
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit(): void {
this.heroService.getHeroes()
.then(heroes => this.heroes = heroes.slice(1, 5));
}
gotoDetail(hero: Hero): void { /* not implemented yet */}
}

View File

@ -1,22 +1,26 @@
/* #docregion */ /* #docregion */
[class*='col-'] { [class*='col-'] {
float: left; float: left;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
[class*='col-'] {
padding-right: 20px; padding-right: 20px;
padding-bottom: 20px; padding-bottom: 20px;
} }
[class*='col-']:last-of-type { [class*='col-']:last-of-type {
padding-right: 0; padding-right: 0;
} }
a {
text-decoration: none;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
h4 {
position: relative;
}
.grid { .grid {
margin: 0; margin: 0;
} }
@ -24,16 +28,13 @@ h3 {
width: 25%; width: 25%;
} }
.module { .module {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
color: #eee; color: #eee;
max-height: 120px; max-height: 120px;
min-width: 120px; min-width: 120px;
background-color: #607D8B; background-color: #607D8B;
border-radius: 2px; border-radius: 2px;
}
h4 {
position: relative;
} }
.module:hover { .module:hover {
background-color: #EEE; background-color: #EEE;
@ -47,15 +48,15 @@ h4 {
padding-right: 20px; padding-right: 20px;
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.module { .module {
font-size: 10px; font-size: 10px;
max-height: 75px; } max-height: 75px; }
} }
@media (max-width: 1024px) { @media (max-width: 1024px) {
.grid { .grid {
margin: 0; margin: 0;
} }
.module { .module {
min-width: 60px; min-width: 60px;
} }
} }

View File

@ -2,10 +2,10 @@
<h3>Top Heroes</h3> <h3>Top Heroes</h3>
<div class="grid grid-pad"> <div class="grid grid-pad">
<!-- #docregion click --> <!-- #docregion click -->
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4"> <a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">
<!-- #enddocregion click --> <!-- #enddocregion click -->
<div class="module hero"> <div class="module hero">
<h4>{{hero.name}}</h4> <h4>{{hero.name}}</h4>
</div> </div>
</div> </a>
</div> </div>

View File

@ -1,13 +1,13 @@
// #docplaster // #docplaster
// #docregion // #docregion
// #docregion imports
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
// #docregion import-router
import { Router } from '@angular/router';
// #enddocregion import-router
import { Hero } from './hero'; import { Hero } from './hero';
import { HeroService } from './hero.service'; import { HeroService } from './hero.service';
// #docregion metadata // #enddocregion imports
// #docregion metadata
@Component({ @Component({
moduleId: module.id, moduleId: module.id,
selector: 'my-dashboard', selector: 'my-dashboard',
@ -19,27 +19,18 @@ import { HeroService } from './hero.service';
// #docregion metadata // #docregion metadata
}) })
// #enddocregion metadata // #enddocregion metadata
// #docregion component // #docregion class
export class DashboardComponent implements OnInit { export class DashboardComponent implements OnInit {
heroes: Hero[] = []; heroes: Hero[] = [];
// #docregion ctor // #docregion ctor
constructor( constructor(private heroService: HeroService) { }
private router: Router,
private heroService: HeroService) {
}
// #enddocregion ctor // #enddocregion ctor
ngOnInit(): void { ngOnInit(): void {
this.heroService.getHeroes() this.heroService.getHeroes()
.then(heroes => this.heroes = heroes.slice(1, 5)); .then(heroes => this.heroes = heroes.slice(1, 5));
} }
// #docregion gotoDetail
gotoDetail(hero: Hero): void {
let link = ['/detail', hero.id];
this.router.navigate(link);
}
// #enddocregion gotoDetail
} }
// #enddocregion class

View File

@ -40,8 +40,10 @@ export class HeroesComponent implements OnInit {
this.selectedHero = hero; this.selectedHero = hero;
} }
// #docregion gotoDetail
gotoDetail(): void { gotoDetail(): void {
this.router.navigate(['/detail', this.selectedHero.id]); this.router.navigate(['/detail', this.selectedHero.id]);
} }
// #enddocregion gotoDetail
// #docregion renaming // #docregion renaming
} }

View File

@ -1,22 +1,26 @@
/* #docregion */ /* #docregion */
[class*='col-'] { [class*='col-'] {
float: left; float: left;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
[class*='col-'] {
padding-right: 20px; padding-right: 20px;
padding-bottom: 20px; padding-bottom: 20px;
} }
[class*='col-']:last-of-type { [class*='col-']:last-of-type {
padding-right: 0; padding-right: 0;
} }
a {
text-decoration: none;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
h4 {
position: relative;
}
.grid { .grid {
margin: 0; margin: 0;
} }
@ -24,16 +28,13 @@ h3 {
width: 25%; width: 25%;
} }
.module { .module {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
color: #eee; color: #eee;
max-height: 120px; max-height: 120px;
min-width: 120px; min-width: 120px;
background-color: #607D8B; background-color: #607D8B;
border-radius: 2px; border-radius: 2px;
}
h4 {
position: relative;
} }
.module:hover { .module:hover {
background-color: #EEE; background-color: #EEE;
@ -47,15 +48,15 @@ h4 {
padding-right: 20px; padding-right: 20px;
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.module { .module {
font-size: 10px; font-size: 10px;
max-height: 75px; } max-height: 75px; }
} }
@media (max-width: 1024px) { @media (max-width: 1024px) {
.grid { .grid {
margin: 0; margin: 0;
} }
.module { .module {
min-width: 60px; min-width: 60px;
} }
} }

View File

@ -18,20 +18,11 @@ import 'hero_search_component.dart';
class DashboardComponent implements OnInit { class DashboardComponent implements OnInit {
List<Hero> heroes; List<Hero> heroes;
final Router _router;
final HeroService _heroService; final HeroService _heroService;
DashboardComponent(this._heroService, this._router); DashboardComponent(this._heroService);
Future<Null> ngOnInit() async { Future<Null> ngOnInit() async {
heroes = (await _heroService.getHeroes()).skip(1).take(4).toList(); heroes = (await _heroService.getHeroes()).skip(1).take(4).toList();
} }
void gotoDetail(Hero hero) {
var link = [
'HeroDetail',
{'id': hero.id.toString()}
];
_router.navigate(link);
}
} }

View File

@ -1,10 +1,10 @@
<!-- #docregion --> <!-- #docregion -->
<h3>Top Heroes</h3> <h3>Top Heroes</h3>
<div class="grid grid-pad"> <div class="grid grid-pad">
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4"> <a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">
<div class="module hero"> <div class="module hero">
<h4>{{hero.name}}</h4> <h4>{{hero.name}}</h4>
</div> </div>
</div> </a>
</div> </div>
<hero-search></hero-search> <hero-search></hero-search>

View File

@ -48,16 +48,16 @@ describe('Tutorial part 6', () => {
beforeAll(() => browser.get('')); beforeAll(() => browser.get(''));
function getPageElts() { function getPageElts() {
let hrefElts = element.all(by.css('my-app a')); let navElts = element.all(by.css('my-app nav a'));
return { return {
hrefs: hrefElts, navElts: navElts,
myDashboardHref: hrefElts.get(0), myDashboardHref: navElts.get(0),
myDashboard: element(by.css('my-app my-dashboard')), myDashboard: element(by.css('my-app my-dashboard')),
topHeroes: element.all(by.css('my-app my-dashboard > div h4')), topHeroes: element.all(by.css('my-app my-dashboard > div h4')),
myHeroesHref: hrefElts.get(1), myHeroesHref: navElts.get(1),
myHeroes: element(by.css('my-app my-heroes')), myHeroes: element(by.css('my-app my-heroes')),
allHeroes: element.all(by.css('my-app my-heroes li')), allHeroes: element.all(by.css('my-app my-heroes li')),
selectedHero: element(by.css('my-app li.selected')), selectedHero: element(by.css('my-app li.selected')),
@ -82,7 +82,7 @@ describe('Tutorial part 6', () => {
const expectedViewNames = ['Dashboard', 'Heroes']; const expectedViewNames = ['Dashboard', 'Heroes'];
it(`has views ${expectedViewNames}`, () => { it(`has views ${expectedViewNames}`, () => {
let viewNames = getPageElts().hrefs.map((el: ElementFinder) => el.getText()); let viewNames = getPageElts().navElts.map((el: ElementFinder) => el.getText());
expect(viewNames).toEqual(expectedViewNames); expect(viewNames).toEqual(expectedViewNames);
}); });

View File

@ -1,23 +1,26 @@
/* #docplaster */
/* #docregion */ /* #docregion */
[class*='col-'] { [class*='col-'] {
float: left; float: left;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
[class*='col-'] {
padding-right: 20px; padding-right: 20px;
padding-bottom: 20px; padding-bottom: 20px;
} }
[class*='col-']:last-of-type { [class*='col-']:last-of-type {
padding-right: 0; padding-right: 0;
} }
a {
text-decoration: none;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
h3 {
text-align: center; margin-bottom: 0;
}
h4 {
position: relative;
}
.grid { .grid {
margin: 0; margin: 0;
} }
@ -25,16 +28,13 @@ h3 {
width: 25%; width: 25%;
} }
.module { .module {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
color: #eee; color: #eee;
max-height: 120px; max-height: 120px;
min-width: 120px; min-width: 120px;
background-color: #607D8B; background-color: #607D8B;
border-radius: 2px; border-radius: 2px;
}
h4 {
position: relative;
} }
.module:hover { .module:hover {
background-color: #EEE; background-color: #EEE;
@ -48,16 +48,15 @@ h4 {
padding-right: 20px; padding-right: 20px;
} }
@media (max-width: 600px) { @media (max-width: 600px) {
.module { .module {
font-size: 10px; font-size: 10px;
max-height: 75px; } max-height: 75px; }
} }
@media (max-width: 1024px) { @media (max-width: 1024px) {
.grid { .grid {
margin: 0; margin: 0;
} }
.module { .module {
min-width: 60px; min-width: 60px;
} }
} }
/* #enddocregion */

View File

@ -1,10 +1,10 @@
<!-- #docregion --> <!-- #docregion -->
<h3>Top Heroes</h3> <h3>Top Heroes</h3>
<div class="grid grid-pad"> <div class="grid grid-pad">
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4"> <a *ngFor="let hero of heroes" [routerLink]="['/detail', hero.id]" class="col-1-4">
<div class="module hero"> <div class="module hero">
<h4>{{hero.name}}</h4> <h4>{{hero.name}}</h4>
</div> </div>
</div> </a>
</div> </div>
<hero-search></hero-search> <hero-search></hero-search>

View File

@ -1,6 +1,5 @@
// #docregion , search // #docregion , search
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Hero } from './hero'; import { Hero } from './hero';
import { HeroService } from './hero.service'; import { HeroService } from './hero.service';
@ -15,18 +14,10 @@ import { HeroService } from './hero.service';
export class DashboardComponent implements OnInit { export class DashboardComponent implements OnInit {
heroes: Hero[] = []; heroes: Hero[] = [];
constructor( constructor(private heroService: HeroService) { }
private router: Router,
private heroService: HeroService) {
}
ngOnInit(): void { ngOnInit(): void {
this.heroService.getHeroes() this.heroService.getHeroes()
.then(heroes => this.heroes = heroes.slice(1, 5)); .then(heroes => this.heroes = heroes.slice(1, 5));
} }
gotoDetail(hero: Hero): void {
let link = ['/detail', hero.id];
this.router.navigate(link);
}
} }

View File

@ -370,16 +370,12 @@ block redirect-vs-use-as-default
:marked :marked
Create that file with this content: Create that file with this content:
+makeExcerpt('app/dashboard.component.html') +makeExample('app/dashboard.component.1.html', '', 'app/dashboard.component.html')
:marked :marked
We use `*ngFor` once again to iterate over a list of heroes and display their names. We use `*ngFor` once again to iterate over a list of heroes and display their names.
We added extra `<div>` elements to help with styling later in this chapter. We added extra `<div>` elements to help with styling later in this chapter.
There's a `(click)` binding to a `gotoDetail` method we haven't written yet and
we're displaying a list of heroes that we don't have.
We have work to do, starting with those heroes.
### Share the *HeroService* ### Share the *HeroService*
We'd like to re-use the `HeroService` to populate the component's `heroes` !{_array}. We'd like to re-use the `HeroService` to populate the component's `heroes` !{_array}.
@ -394,12 +390,12 @@ block redirect-vs-use-as-default
Open <span ngio-ex>dashboard.component.ts</span> and add the requisite `import` statements. Open <span ngio-ex>dashboard.component.ts</span> and add the requisite `import` statements.
+makeExcerpt('app/dashboard.component.2.ts','imports') +makeExcerpt('app/dashboard.component.ts','imports')
:marked :marked
Now implement the `DashboardComponent` class like this: Now implement the `DashboardComponent` class like this:
+makeExcerpt('app/dashboard.component.2.ts (class)', 'component') +makeExcerpt('app/dashboard.component.ts (class)', 'class')
:marked :marked
We've seen this kind of logic before in the `HeroesComponent`: We've seen this kind of logic before in the `HeroesComponent`:
@ -408,8 +404,7 @@ block redirect-vs-use-as-default
* Inject the `HeroService` in the constructor and hold it in a private `!{_priv}heroService` field. * Inject the `HeroService` in the constructor and hold it in a private `!{_priv}heroService` field.
* Call the service to get heroes inside the Angular `ngOnInit` lifecycle hook. * Call the service to get heroes inside the Angular `ngOnInit` lifecycle hook.
The noteworthy differences: we cherry-pick four heroes (2nd, 3rd, 4th, and 5th) In this dashboard we cherry-pick four heroes (2nd, 3rd, 4th, and 5th) with the `Array.slice` method.
and stub the `gotoDetail` method until we're ready to implement it.
Refresh the browser and see four heroes in the new dashboard. Refresh the browser and see four heroes in the new dashboard.
@ -580,7 +575,7 @@ block extract-id
incremental improvement and migrate the template to its own file, incremental improvement and migrate the template to its own file,
called <span ngio-ex>hero-detail.component.html</span>: called <span ngio-ex>hero-detail.component.html</span>:
+makeExample('app/hero-detail.component.html') +makeExample('app/hero-detail.component.html')(format='.')
:marked :marked
We update the component metadata with a `moduleId` and a `templateUrl` pointing to the template file that we just created. We update the component metadata with a `moduleId` and a `templateUrl` pointing to the template file that we just created.
@ -596,32 +591,26 @@ block extract-id
When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero. When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero.
In the dashboard template we bound each hero's click event to the `gotoDetail` method, passing along the selected `hero` entity. Although the dashboard heroes are presented as button-like blocks, they should behave like anchor tags.
When hovering over a hero block, the target URL should display in the browser status bar
and the user should be able to copy the link or open the hero detail view in a new tab.
+makeExcerpt('app/dashboard.component.html', 'click') To achieve this effect, reopen the `dashboard.component.html` and replace the repeated `<div *ngFor...>` tags
with `<a>` tags. The opening `<a>` tag looks like this:
:marked +makeExample('app/dashboard.component.html', 'click', 'app/dashboard.component.html (repeated <a> tag)')
We stubbed the `gotoDetail` method when we rewrote the `DashboardComponent`.
Now we give it a real implementation.
+makeExcerpt('app/dashboard.component.ts','gotoDetail')
- var _pathVsName = _docsFor == 'dart' ? 'name' : 'path' - var _pathVsName = _docsFor == 'dart' ? 'name' : 'path'
:marked :marked
The `gotoDetail` method navigates in two steps: Notice the `[routerLink]` binding.
1. Set a route *link parameters !{_array}* In the top level navigation in the [`AppComponent`
1. Pass the !{_array} to the router's navigate method template](#router-links) has router links set to fixed !{_pathVsName}s of the
destination routes, "/dashboard" and "/heroes".
For navigation, we wrote router links <span if-docs="dart">as *link This time, we're binding to an expression containing a **link parameters !{_array}**.
parameters !{_array}s*</span> in the [`AppComponent` The !{_array} has two elements, the ***!{_pathVsName}*** of
template](#router-links). Those link<span if-docs="dart"> parameters the destination route and a ***route parameter*** set to the value of the current hero's `id`.
!{_array}</span>s had only one element, the !{_pathVsName} of the
destination route.
This link parameters !{_array} has two elements, the ***!{_pathVsName}*** of
the destination route and a ***route parameter*** <span if-docs="dart">with
an `id` field</span> set to the value of the selected hero's `id`.
The two !{_array} items align with the ***!{_pathVsName}*** and ***:id*** The two !{_array} items align with the ***!{_pathVsName}*** and ***:id***
token in the parameterized hero detail route definition we added to token in the parameterized hero detail route definition we added to
@ -630,14 +619,6 @@ block extract-id
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.module.3.ts' - var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.module.3.ts'
+makeExcerpt(_file + ' (hero detail)', 'hero-detail') +makeExcerpt(_file + ' (hero detail)', 'hero-detail')
:marked
The `DashboardComponent` doesn't have the router yet. We obtain it in the usual way:
import the `router` reference and inject it in the constructor (along with the `HeroService`):
+makeExcerpt('app/dashboard.component.ts ()','import-router', '')
+makeExcerpt('app/dashboard.component.ts', 'ctor', '')
:marked :marked
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details. Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details.
@ -703,14 +684,14 @@ block extract-id
:marked :marked
Our goal is to move the detail to its own view and navigate to it when the user decides to edit a selected hero. Our goal is to move the detail to its own view and navigate to it when the user decides to edit a selected hero.
Delete the `<h1>` at the top (forgot about it during the `AppComponent`-to-`HeroesComponent` conversion). Delete the `<h1>` at the top (we forgot about it during the `AppComponent`-to-`HeroesComponent` conversion).
Delete the last line of the template with the `<my-hero-detail>` tags. Delete the last line of the template with the `<my-hero-detail>` tags.
We'll no longer show the full `HeroDetailComponent` here. We'll no longer show the full `HeroDetailComponent` here.
We're going to display the hero detail on its own page and route to it as we did in the dashboard. We're going to display the hero detail on its own page and route to it as we did in the dashboard.
But we'll throw in a small twist for variety. We'll throw in a small twist for variety.
We are keeping the "master/detail" style but shrinking the detail to a "mini", read-only version. We are keeping the "master/detail" style but shrinking the detail to a "mini", read-only version.
When the user selects a hero from the list, we *don't* go to the detail page. When the user selects a hero from the list, we *don't* go to the detail page.
We show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page. We show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page.
@ -770,15 +751,25 @@ block heroes-component-cleanup
+makeExcerpt('app/heroes.component.ts (revised metadata)', 'metadata') +makeExcerpt('app/heroes.component.ts (revised metadata)', 'metadata')
:marked :marked
Now we can see what's going on as we update the component class along the same lines as the dashboard: ### Update the _HeroesComponent_ class.
1. Import the `router` The `HeroesComponent` navigates to the `HeroesDetailComponent` in response to a button click.
The button's _click_ event is bound to a `gotoDetail` method that navigates _imperatively_
by telling the router where to go.
This approach requires some changes to the component class:
1. Import the `router` from the Angular router library
1. Inject the `router` in the constructor (along with the `HeroService`) 1. Inject the `router` in the constructor (along with the `HeroService`)
1. Implement the `gotoDetail` method by calling the `router.navigate` method 1. Implement `gotoDetail` by calling the `router.navigate` method
with a two-part hero-detail link parameters !{_array}. +makeExcerpt('app/heroes.component.ts', 'gotoDetail')
:marked
Here's the revised component class: Note that we're passing a two-element **link parameters !{_array}**
&mdash; a path and the route parameter &mdash; to
the `router.navigate` method just as we did in the `[routerLink]` binding
back in the `DashboardComponent`
Here's the fully revised `HeroesComponent` class:
+makeExcerpt('app/heroes.component.ts', 'class') +makeExcerpt('app/heroes.component.ts', 'class')

View File

@ -5,3 +5,4 @@
/ts/latest/guide/style-guide.html # https://github.com/angular/angular.io/issues/2123 /ts/latest/guide/style-guide.html # https://github.com/angular/angular.io/issues/2123
/ts/latest/guide/upgrade.html # In a transient state until RC6 - @filipe.silva /ts/latest/guide/upgrade.html # In a transient state until RC6 - @filipe.silva
/[jt]s/.*/api/forms/index/NG_VALIDATORS-let.html # RC6 contains broken example tags /[jt]s/.*/api/forms/index/NG_VALIDATORS-let.html # RC6 contains broken example tags
/dart/latest/tutorial/toh-pt5.html