docs(toh-5/dart): use routerLink in dashboard (#2744)

* docs(toh-5/dart): use routerLink in dashboard

* minor edits to TS jade

* remove dart/toh-pt5 from bad-code-excerpt-skip-patterns
This commit is contained in:
Patrice Chalin 2016-11-08 14:48:03 -08:00 committed by Kathy Walrath
parent 2808878c36
commit c24dd074a6
10 changed files with 218 additions and 154 deletions

View File

@ -4,21 +4,27 @@
import 'dart:async';
import 'package:angular2/core.dart';
// #docregion import-router
import 'package:angular2/router.dart';
// #enddocregion import-router
import 'hero.dart';
import 'hero_service.dart';
// #enddocregion imports
// #docregion metadata
@Component(
selector: 'my-dashboard',
// #docregion templateUrl
templateUrl: 'dashboard_component.html',
// #enddocregion templateUrl
// #docregion css
styleUrls: const ['dashboard_component.css']
styleUrls: const ['dashboard_component.css'],
// #enddocregion css
directives: const [ROUTER_DIRECTIVES],
)
// #docregion component
// #enddocregion metadata
// #docregion class, component
class DashboardComponent implements OnInit {
List<Hero> heroes;
@ -26,11 +32,9 @@ class DashboardComponent implements OnInit {
final HeroService _heroService;
DashboardComponent(this._heroService);
// #enddocregion ctor
Future<Null> ngOnInit() async {
heroes = (await _heroService.getHeroes()).skip(1).take(4).toList();
}
}
// #enddocregion component

View File

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

View File

@ -2,12 +2,12 @@
// #docregion , v2
// #docregion added-imports
import 'dart:async';
import 'dart:html' show window;
// #enddocregion added-imports
import 'package:angular2/core.dart';
// #docregion added-imports
import 'package:angular2/router.dart';
import 'package:angular2/platform/common.dart';
// #enddocregion added-imports
import 'hero.dart';
@ -17,9 +17,9 @@ import 'hero_service.dart';
@Component(
selector: 'my-hero-detail',
// #docregion templateUrl
// #docregion metadata, templateUrl
templateUrl: 'hero_detail_component.html',
// #enddocregion templateUrl, v2
// #enddocregion metadata, templateUrl, v2
styleUrls: const ['hero_detail_component.css']
// #docregion v2
)
@ -30,8 +30,9 @@ class HeroDetailComponent implements OnInit {
// #docregion ctor
final HeroService _heroService;
final RouteParams _routeParams;
final Location _location;
HeroDetailComponent(this._heroService, this._routeParams);
HeroDetailComponent(this._heroService, this._routeParams, this._location);
// #enddocregion ctor
// #docregion ngOnInit
@ -44,7 +45,7 @@ class HeroDetailComponent implements OnInit {
// #docregion goBack
void goBack() {
window.history.back();
_location.back();
}
// #enddocregion goBack
}

View File

@ -41,9 +41,11 @@ class HeroesComponent implements OnInit {
selectedHero = hero;
}
// #docregion gotoDetail
Future<Null> gotoDetail() => _router.navigate([
'HeroDetail',
{'id': selectedHero.id.toString()}
]);
// #enddocregion gotoDetail
// #docregion renaming
}

View File

@ -33,4 +33,3 @@ export class DashboardComponent implements OnInit {
.then(heroes => this.heroes = heroes.slice(1, 5));
}
}
// #enddocregion class

View File

@ -96,12 +96,13 @@ block redirect-vs-use-as-default
router will display the dashboard when the browser URL doesn't match an existing route.
block templateUrl-path-resolution
:marked
The value of `templateUrl` can be an [asset][] in this package or another
package. To use an asset in another package, use a full package reference,
such as `'package:some_other_package/dashboard_component.html'`.
.l-sub-section
:marked
The value of `templateUrl` can be an [asset][] in this package or another
package. To use an asset in another package, use a full package reference,
such as `'package:some_other_package/dashboard_component.html'`.
[asset]: https://www.dartlang.org/tools/pub/glossary#asset
[asset]: https://www.dartlang.org/tools/pub/glossary#asset
block route-params
:marked

View File

@ -2,7 +2,7 @@
block includes
include ../_util-fns
- var _appRoutingTsVsAppComp = 'app-routing.module.ts'
- var _appRoutingTsVsAppComp = 'app.module.ts'
- var _declsVsDirectives = 'declarations'
- var _RoutesVsAtRouteConfig = 'Routes'
- var _RouterModuleVsRouterDirectives = 'RouterModule'
@ -24,7 +24,7 @@ figure.image-display
img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations")
:marked
We'll add Angulars *Component Router* to our app to satisfy these requirements.
We'll add Angulars *Router* to our app to satisfy these requirements.
.l-sub-section
:marked
@ -52,7 +52,7 @@ figure.image-display
block intro-file-tree
.filetree
.file angular2-tour-of-heroes
.file angular-tour-of-heroes
.children
.file app
.children
@ -164,7 +164,7 @@ block app-comp-v1
Instead of displaying heroes automatically, we'd like to show them *after* the user clicks a button.
In other words, we'd like to navigate to the list of heroes.
We'll need the Angular *Component Router*.
We'll need the Angular *Router*.
block angular-router
:marked
@ -192,7 +192,7 @@ block router-config-intro
### Configure routes
Our application doesn't have any routes yet.
We'll start by creating a configuration file for the application routes.
We'll start by creating a configuration for the application routes.
:marked
*Routes* tell the router which views to display when a user clicks a link or
@ -200,7 +200,7 @@ block router-config-intro
Let's define our first route as a route to the heroes component:
- var _file = _docsFor == 'dart' ? 'app.component.ts' : 'app-routing.module.ts'
- var _file = _docsFor == 'dart' ? 'app.component.ts' : 'app.module.2.ts'
+makeExcerpt('app/' + _file + ' (heroes route)', 'heroes')
- var _are = _docsFor == 'dart' ? 'takes' : 'are'
@ -222,24 +222,18 @@ block router-config-intro
+ifDocsFor('ts|js')
:marked
We'll export a `routing` constant initialized using the `RouterModule.forRoot` method applied to our !{_array} of routes.
This method returns a **configured router module** that we'll add to our root NgModule, `AppModule`.
### Make the router available
+makeExcerpt('app/app-routing.module.1.ts (excerpt)', 'routing-export')
We've setup the initial route configuration. Now we'll add it to our `AppModule`.
We'll add our configured `RouterModule` to the `AppModule` imports !{_array}.
+makeExcerpt('app/app.module.2.ts (app routing)', '')
.l-sub-section
:marked
We call the `forRoot` method because we're providing a configured router at the _root_ of the application.
The `forRoot` method gives us the Router service providers and directives needed for routing.
:marked
### Make the router available
We've setup initial routes in the `app-routing.module.ts` file. Now we'll add it to our root NgModule.
Import the `routing` constant from `app-routing.module.ts` and add it the `imports` !{_array} of `AppModule`.
+makeExcerpt('app/app.module.ts', 'routing')
We use the `forRoot` method because we're providing a configured router at the _root_ of the application.
The `forRoot` method gives us the Router service providers and directives needed for routing, and
performs the initial navigation based on the current browser URL.
- var _heroesRoute = _docsFor == 'dart' ? "'Heroes'" : 'heroes'
:marked
@ -317,12 +311,12 @@ block routerLink
Import the dashboard component and
add the following route definition to the `!{_RoutesVsAtRouteConfig}` !{_array} of definitions.
- var _file = _docsFor == 'dart' ? 'lib/app_component.dart' : 'app/app-routing.module.ts'
- var _file = _docsFor == 'dart' ? 'lib/app_component.dart' : 'app/app.module.3.ts'
+makeExcerpt(_file + ' (Dashboard route)', 'dashboard')
+ifDocsFor('ts|js')
:marked
Also import and add `DashboardComponent` to our root NgModule's `declarations`.
Also import and add `DashboardComponent` to our `AppModule`'s `declarations`.
+makeExcerpt('app/app.module.ts', 'dashboard')
@ -338,7 +332,7 @@ block redirect-vs-use-as-default
We can use a redirect route to make this happen. Add the following
to our array of route definitions:
+makeExcerpt('app/app-routing.module.ts','redirect')
+makeExcerpt('app/app.module.3.ts','redirect')
.l-sub-section
:marked
@ -354,7 +348,7 @@ block redirect-vs-use-as-default
.l-sub-section
:marked
We nestled the two links within `<nav>` tags.
We nested the two links within `<nav>` tags.
They don't do anything yet but they'll be convenient when we style the links a little later in the chapter.
:marked
@ -367,30 +361,24 @@ block redirect-vs-use-as-default
Replace the `template` metadata with a `templateUrl` property that points to a new
template file.
+ifDocsFor('ts|js')
:marked
Set the `moduleId` property to `module.id` for module-relative loading of the `templateUrl`.
+makeExcerpt('app/dashboard.component.ts', 'templateUrl')
+makeExcerpt('app/dashboard.component.ts', 'metadata')
.l-sub-section
block templateUrl-path-resolution
:marked
We specify the path _all the way back to the application root_ &mdash;
<span if-docs="ts">`app/` in this case &mdash;</span>
because Angular doesn't support relative paths _by default_.
We _can_ switch to [component-relative paths](../cookbook/component-relative-paths.html) if we prefer.
block templateUrl-path-resolution
//- N/A for TS
:marked
Create that file with this content:
+makeExcerpt('app/dashboard.component.html')
+makeExample('app/dashboard.component.1.html', '', 'app/dashboard.component.html')
:marked
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.
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*
We'd like to re-use the `HeroService` to populate the component's `heroes` !{_array}.
@ -405,12 +393,12 @@ block redirect-vs-use-as-default
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
Now implement the `DashboardComponent` class like this:
+makeExcerpt('app/dashboard.component.2.ts (class)', 'component')
+makeExcerpt('app/dashboard.component.ts (class)', 'class')
:marked
We've seen this kind of logic before in the `HeroesComponent`:
@ -419,8 +407,7 @@ block redirect-vs-use-as-default
* 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.
The noteworthy differences: we cherry-pick four heroes (2nd, 3rd, 4th, and 5th)
and stub the `gotoDetail` method until we're ready to implement it.
In this dashboard we cherry-pick four heroes (2nd, 3rd, 4th, and 5th)<span if-docs="ts"> with the `Array.slice` method</span>.
Refresh the browser and see four heroes in the new dashboard.
@ -470,7 +457,7 @@ code-example(format='').
Here's the *route definition* we'll use.
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app-routing.module.ts'
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.module.3.ts'
+makeExcerpt(_file + ' (hero detail)','hero-detail')
:marked
@ -521,7 +508,7 @@ block route-params
- var _ActivatedRoute = _docsFor == 'dart' ? 'RouteParams' : 'ActivatedRoute'
:marked
Let's have the `!{_ActivatedRoute}` service and the `HeroService` injected
Let's have the `!{_ActivatedRoute}` service, the `HeroService` and the `Location` service injected
into the constructor, saving their values in private fields:
+makeExcerpt('app/hero-detail.component.ts (constructor)', 'ctor')
@ -534,7 +521,7 @@ block route-params
block ngOnInit
:marked
Inside the `ngOnInit` lifecycle hook, we use the `params` observable to
extract the `id` parameter value from the `ActivateRoute` service
extract the `id` parameter value from the `ActivatedRoute` service
and use the `HeroService` to fetch the hero with that `id`.
+makeExcerpt('app/hero-detail.component.ts', 'ngOnInit')
@ -567,7 +554,8 @@ block extract-id
How do we navigate somewhere else when we're done?
The user could click one of the two links in the `AppComponent`. Or click the browser's back button.
We'll add a third option, a `goBack` method that navigates backward one step in the browser's history stack.
We'll add a third option, a `goBack` method that navigates backward one step in the browser's history stack
using the `Location` service we injected previously.
+makeExcerpt('app/hero-detail.component.ts', 'goBack')
@ -586,16 +574,16 @@ block extract-id
+makeExcerpt('app/hero-detail.component.html', 'back-button', '')
:marked
Modifing the template to add this button spurs us to take one more
Modifying the template to add this button spurs us to take one more
incremental improvement and migrate the template to its own file,
called <span ngio-ex>hero-detail.component.html</span>:
+makeExample('app/hero-detail.component.html')
:marked
We update the component metadata with a `templateUrl` pointing to the template file that we just created.
We update the component metadata with a <span if-docs="ts">`moduleId` and a </span>`templateUrl` pointing to the template file that we just created.
+makeExcerpt('app/hero-detail.component.ts', 'templateUrl')
+makeExcerpt('app/hero-detail.component.ts', 'metadata')
:marked
Refresh the browser and see the results.
@ -606,71 +594,118 @@ 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.
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
We stubbed the `gotoDetail` method when we rewrote the `DashboardComponent`.
Now we give it a real implementation.
+makeExample('app/dashboard.component.html', 'click', 'app/dashboard.component.html (repeated <a> tag)')
+makeExcerpt('app/dashboard.component.ts','gotoDetail')
+ifDocsFor('dart')
.alert.is-important
:marked
Router links in the dashboard are currently not operational, as reported in issue
[dart-lang/angular2/issues/186](https://github.com/dart-lang/angular2/issues/186).
- var _pathVsName = _docsFor == 'dart' ? 'name' : 'path'
:marked
The `gotoDetail` method navigates in two steps:
Notice the `[routerLink]` binding.
1. Set a route *link parameters !{_array}*
1. Pass the !{_array} to the router's navigate method
Top level navigation in the [`AppComponent`
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
parameters !{_array}s*</span> in the [`AppComponent`
template](#router-links). Those link<span if-docs="dart"> parameters
!{_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`.
This time, we're binding to an expression containing a **link parameters !{_array}**.
The !{_array} has two elements, the ***!{_pathVsName}*** of
the destination route and a ***route parameter*** set to the value of the current hero's `id`.
The two !{_array} items align with the ***!{_pathVsName}*** and ***:id***
token in the parameterized hero detail route definition we added to
`!{_appRoutingTsVsAppComp}` earlier in the chapter:
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app-routing.module.ts'
- var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.module.3.ts'
+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
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details.
+ifDocsFor('ts')
.l-main-section
:marked
## Refactor routes to a _Routing Module_
Almost 20 lines of `AppModule` are devoted to configuring four routes.
Most applications have many more routes and they [add guard services](../guide/router.html#guards)
to protect against unwanted or unauthorized navigations.
Routing considerations could quickly dominate this module and obscure its primary purpose which is to
establish key facts about the entire app for the Angular compiler.
We should refactor the routing configuration into its own class.
What kind of class?
The current `RouterModule.forRoot()` produces an Angular `ModuleWithProviders` which suggests that a
class dedicated to routing should be some kind of module.
It should be a [_Routing Module_](../guide/router.html#routing-module).
By convention the name of a _Routing Module_ contains the word "Routing" and
aligns with the name of the module that declares the components navigated to.
Create an `app-routing.module.ts` file as a sibling to `app.module.ts`. Give it the following contents extracted from the `AppModule` class:
+makeExample('app/app-routing.module.ts')
:marked
Noteworthy points, typical of _Routing Modules_:
* Pull the routes into a variable. You might export it in future and it clarifies the _Routing Module_ pattern.
* Add `RouterModule.forRoot(routes)` to `imports`.
* Add `RouterModule` to `exports` so that the components in the companion module have access to Router declarables
such as `RouterLink` and `RouterOutlet`.
* No `declarations`! Declarations are the responsibility of the companion module.
* Add module `providers` for guard services if you have them; there are none in this example.
### Update _AppModule_
Now delete the routing configuration from `AppModule` and import the `AppRoutingModule`
(_both_ with an ES `import` statement _and_ by adding it to the `NgModule.imports` list).
Here is the revised `AppModule`, compared to its pre-refactor state:
+makeTabs(
`toh-5/ts/app/app.module.ts, toh-5/ts/app/app.module.3.ts`,
null,
`app/app.module.ts (after), app/app.module.ts (before)`)
:marked
It's simpler and focused on indentifying the key pieces of the application.
.l-main-section
:marked
## Select a Hero in the *HeroesComponent*
Earlier we added the ability to select a hero from the dashboard.
We'll do something similar in the `HeroesComponent`.
That component's current template exhibits a "master/detail" style with the list of heroes
The `HeroesComponent` template exhibits a "master/detail" style with the list of heroes
at the top and details of the selected hero below.
+makeExample('toh-4/ts/app/app.component.ts','template', 'app/heroes.component.ts (current template)')(format=".")
: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.
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.
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.
But we'll throw in a small twist for variety.
When the user selects a hero from the list, we *won't* go to the detail page.
We'll show a *mini-detail* on *this* page instead and make the user click a button to navigate to the *full detail *page.
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.
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.
### Add the *mini-detail*
@ -714,13 +749,12 @@ figure.image-display
1. *Cut-and-paste* the template contents into a new <span ngio-ex>heroes.component.html</span> file.
1. *Cut-and-paste* the styles contents into a new <span ngio-ex>heroes.component.css</span> file.
1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files.
<li if-docs="ts">. *Set* the `moduleId` property to `module.id` so that `templateUrl` and `styleUrls` are relative to the component.</li>
.l-sub-section
:marked
The `styleUrls` property is !{_an} !{_array} of style file names (with paths).
We could list multiple style files from different locations if we needed them.
<span if-docs="ts">As with `templateUrl`, we must specify the path _all the way
back to the application root_.</span>
block heroes-component-cleanup
//- Only relevant for Dart.
@ -728,15 +762,26 @@ block heroes-component-cleanup
+makeExcerpt('app/heroes.component.ts (revised metadata)', 'metadata')
: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. 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')
Here's the revised component class:
:marked
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')
@ -834,7 +879,7 @@ block css-files
+makeExcerpt('styles.css (excerpt)', 'toh')
- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/styles.css'
- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/_boilerplate/styles.css'
:marked
Create the file <span ngio-ex>styles.css</span>, if it doesn't exist already.
@ -859,7 +904,7 @@ figure.image-display
block file-tree-end
.filetree
.file angular2-tour-of-heroes
.file angular-tour-of-heroes
.children
.file app
.children
@ -895,12 +940,13 @@ block file-tree-end
We travelled a great distance in this chapter
- We added the Angular *Component Router* to navigate among different components.
- We added the Angular *Router* to navigate among different components.
- We learned how to create router links to represent navigation menu items.
- We used router link parameters to navigate to the details of user selected hero.
- We shared the `HeroService` among multiple components.
- We moved HTML and CSS out of the component file and into their own files.
- We added the `uppercase` pipe to format data.
<li if-docs="ts"> We refactored routes into a `Routing Module` that we import.</li>
### The Road Ahead

View File

@ -205,7 +205,6 @@ block router-config-intro
- var _are = _docsFor == 'dart' ? 'takes' : 'are'
- var _routePathPrefix = _docsFor == 'dart' ? '/' : ''
:marked
The `!{_RoutesVsAtRouteConfig}` !{_are} !{_an} !{_array} of *route definitions*.
We have only one route definition at the moment but rest assured, we'll add more.
@ -362,11 +361,15 @@ block redirect-vs-use-as-default
Replace the `template` metadata with a `templateUrl` property that points to a new
template file.
Set the `moduleId` property to `module.id` for module-relative loading of the `templateUrl`.
+ifDocsFor('ts|js')
:marked
Set the `moduleId` property to `module.id` for module-relative loading of the `templateUrl`.
+makeExcerpt('app/dashboard.component.ts', 'metadata')
block templateUrl-path-resolution
//- N/A for TS
:marked
Create that file with this content:
@ -404,7 +407,7 @@ block redirect-vs-use-as-default
* 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.
In this dashboard we cherry-pick four heroes (2nd, 3rd, 4th, and 5th) with the `Array.slice` method.
In this dashboard we cherry-pick four heroes (2nd, 3rd, 4th, and 5th)<span if-docs="ts"> with the `Array.slice` method</span>.
Refresh the browser and see four heroes in the new dashboard.
@ -575,10 +578,10 @@ block extract-id
incremental improvement and migrate the template to its own file,
called <span ngio-ex>hero-detail.component.html</span>:
+makeExample('app/hero-detail.component.html')(format='.')
+makeExample('app/hero-detail.component.html')
: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 <span if-docs="ts">`moduleId` and a </span>`templateUrl` pointing to the template file that we just created.
+makeExcerpt('app/hero-detail.component.ts', 'metadata')
@ -600,11 +603,17 @@ block extract-id
+makeExample('app/dashboard.component.html', 'click', 'app/dashboard.component.html (repeated <a> tag)')
+ifDocsFor('dart')
.alert.is-important
:marked
Router links in the dashboard are currently not operational, as reported in issue
[dart-lang/angular2/issues/186](https://github.com/dart-lang/angular2/issues/186).
- var _pathVsName = _docsFor == 'dart' ? 'name' : 'path'
:marked
Notice the `[routerLink]` binding.
In the top level navigation in the [`AppComponent`
Top level navigation in the [`AppComponent`
template](#router-links) has router links set to fixed !{_pathVsName}s of the
destination routes, "/dashboard" and "/heroes".
@ -622,53 +631,55 @@ block extract-id
:marked
Refresh the browser and select a hero from the dashboard; the app should navigate directly to that heros details.
.l-main-section
:marked
## Refactor routes to a _Routing Module_
+ifDocsFor('ts')
.l-main-section
:marked
## Refactor routes to a _Routing Module_
Almost 20 lines of `AppModule` are devoted to configuring four routes.
Most application have many more routes and they [add guard services](../guide/router.html#guards)
to protect against unwanted or unauthorized navigations.
Routing considerations could quickly dominate this module and obscure its primary purpose which is to
establish key facts about the entire app for the Angular compiler.
Almost 20 lines of `AppModule` are devoted to configuring four routes.
Most applications have many more routes and they [add guard services](../guide/router.html#guards)
to protect against unwanted or unauthorized navigations.
Routing considerations could quickly dominate this module and obscure its primary purpose which is to
establish key facts about the entire app for the Angular compiler.
We should refactor the routing configuration into its own class.
What kind of class?
The current `RouterModule.forRoot()` produces an Angular `ModuleWithProviders` which suggests that a
class dedicated to routing should be some kind of module.
It should be a [_Routing Module_](../guide/router.html#routing-module).
We should refactor the routing configuration into its own class.
What kind of class?
The current `RouterModule.forRoot()` produces an Angular `ModuleWithProviders` which suggests that a
class dedicated to routing should be some kind of module.
It should be a [_Routing Module_](../guide/router.html#routing-module).
By convention the name of a _Routing Module_ contains the word "Routing" and
aligns with the name of the module that declares the components navigated to".
Create an `app-routing.module.ts` file as a sibling to `app.module.ts`. Give it the following contents extracted from the `AppModule` class:
By convention the name of a _Routing Module_ contains the word "Routing" and
aligns with the name of the module that declares the components navigated to.
+makeExample('app/app-routing.module.ts')
:marked
Noteworthy points, typical of _Routing Modules_:
* Pull the routes into a variable. You might export it in future and it clarifies the _Routing Module_ pattern.
Create an `app-routing.module.ts` file as a sibling to `app.module.ts`. Give it the following contents extracted from the `AppModule` class:
* Add `RouterModule.forRoot(routes)` to `imports`.
* Add `RouterModule` to `exports` so that the components in the companion module have access to Router declarables
such as `RouterLink` and `RouterOutlet`.
* No `declarations`! Declarations are the responsibility of the companion module.
+makeExample('app/app-routing.module.ts')
:marked
Noteworthy points, typical of _Routing Modules_:
* Pull the routes into a variable. You might export it in future and it clarifies the _Routing Module_ pattern.
* Add module `providers` for guard services if you have them; there are none in this example.
* Add `RouterModule.forRoot(routes)` to `imports`.
### Update _AppModule_
* Add `RouterModule` to `exports` so that the components in the companion module have access to Router declarables
such as `RouterLink` and `RouterOutlet`.
Now delete the routing configuration from `AppModule` and import the `AppRoutingModule`
(_both_ with an ES `import` statement _and_ by adding it to the `NgModule.imports` list).
* No `declarations`! Declarations are the responsibility of the companion module.
* Add module `providers` for guard services if you have them; there are none in this example.
### Update _AppModule_
Now delete the routing configuration from `AppModule` and import the `AppRoutingModule`
(_both_ with an ES `import` statement _and_ by adding it to the `NgModule.imports` list).
Here is the revised `AppModule`, compared to its pre-refactor state:
+makeTabs(
`toh-5/ts/app/app.module.ts, toh-5/ts/app/app.module.3.ts`,
null,
`app/app.module.ts (after), app/app.module.ts (before)`)
:marked
It's simpler and focused on indentifying the key pieces of the application.
Here is the revised `AppModule`, compared to its pre-refactor state:
+makeTabs(
`toh-5/ts/app/app.module.ts, toh-5/ts/app/app.module.3.ts`,
null,
`app/app.module.ts (after), app/app.module.ts (before)`)
:marked
It's simpler and focused on indentifying the key pieces of the application.
.l-main-section
:marked
## Select a Hero in the *HeroesComponent*
@ -738,7 +749,7 @@ figure.image-display
1. *Cut-and-paste* the template contents into a new <span ngio-ex>heroes.component.html</span> file.
1. *Cut-and-paste* the styles contents into a new <span ngio-ex>heroes.component.css</span> file.
1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files.
1. *Set* the `moduleId` property to `module.id` so that `templateUrl` and `styleUrls` are relative to the component.
<li if-docs="ts">. *Set* the `moduleId` property to `module.id` so that `templateUrl` and `styleUrls` are relative to the component.</li>
.l-sub-section
:marked
@ -764,11 +775,12 @@ block heroes-component-cleanup
1. Implement `gotoDetail` by calling the `router.navigate` method
+makeExcerpt('app/heroes.component.ts', 'gotoDetail')
:marked
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`
back in the `DashboardComponent`.
Here's the fully revised `HeroesComponent` class:
+makeExcerpt('app/heroes.component.ts', 'class')
@ -934,7 +946,7 @@ block file-tree-end
- We shared the `HeroService` among multiple components.
- We moved HTML and CSS out of the component file and into their own files.
- We added the `uppercase` pipe to format data.
- We refactored routes into a `Routing Module` that we import.
<li if-docs="ts"> We refactored routes into a `Routing Module` that we import.</li>
### The Road Ahead

View File

@ -2,4 +2,3 @@
# <grep-pattern-to-match-file-path> # reason / issue number
/[jt]s/.*/api/forms/index/NG_VALIDATORS-let.html # RC6 contains broken example tags
/dart/latest/tutorial/toh-pt5.html