@@ -12,8 +12,8 @@ block includes
12
12
13
13
* Add a *Dashboard* view.
14
14
* Add the ability to navigate between the *Heroes* and *Dashboard* views.
15
- * When users click a hero name in either view, they should navigate to a detail view of the selected hero.
16
- * When users click a *deep link* in an email, the detail view for a particular hero should open .
15
+ * When users click a hero name in either view, navigate to a detail view of the selected hero.
16
+ * When users click a *deep link* in an email, open the detail view for a particular hero.
17
17
18
18
When you’re done, users will be able to navigate the app like this:
19
19
@@ -37,7 +37,6 @@ figure.image-display
37
37
:marked
38
38
## Where you left off
39
39
Before continuing with the Tour of Heroes, verify that you have the following structure.
40
- If not, go back to the previous pages.
41
40
42
41
block intro-file-tree
43
42
.filetree
@@ -215,14 +214,14 @@ block router-config-intro
215
214
:marked
216
215
### Make the router available
217
216
218
- Add the initial route configuration, `RouterModule`, to the `AppModule` imports !{_array}.
217
+ Import the `RouterModule` and add it to the `AppModule` imports !{_array}.
219
218
220
219
+ makeExcerpt('src/app/app.module.2.ts (app routing)' , '' )
221
220
222
221
.l-sub-section
223
222
:marked
224
- The `forRoot` method is called because a configured router is provided at the app's root.
225
- The `forRoot` method supplies the Router service providers and directives needed for routing, and
223
+ The `forRoot() ` method is called because a configured router is provided at the app's root.
224
+ The `forRoot() ` method supplies the Router service providers and directives needed for routing, and
226
225
performs the initial navigation based on the current browser URL.
227
226
228
227
- var _heroesRoute = _docsFor == ' dart' ? " 'Heroes'" : ' heroes'
@@ -260,7 +259,7 @@ block routerLink
260
259
[Routing & Navigation](../guide/router.html#) page.
261
260
262
261
:marked
263
- Refresh the browser. The app title and heroes link, but not the heroes list, display .
262
+ Refresh the browser. The browser displays the app title and heroes link, but not the heroes list.
264
263
265
264
.l-sub-section
266
265
:marked
@@ -269,7 +268,7 @@ block routerLink
269
268
Soon you'll add a route that matches the path `/`.
270
269
271
270
:marked
272
- Click the *Heroes* navigation link. The browser bar updates to `/heroes`
271
+ Click the *Heroes* navigation link. The address bar updates to `/heroes`
273
272
and the list of heroes displays.
274
273
275
274
`AppComponent` now looks like this:
@@ -361,13 +360,13 @@ block templateUrl-path-resolution
361
360
362
361
:marked
363
362
`*ngFor` is used again to iterate over a list of heroes and display their names.
364
- The extra `<div>` elements will help with styling later in this page .
363
+ The extra `<div>` elements will help with styling later.
365
364
366
365
### Sharing the *HeroService*
367
366
368
367
To populate the component's `heroes` !{_array}, you can re-use the `HeroService`.
369
368
370
- Earlier in the page , you removed the `HeroService` from the `providers` !{_array} of `HeroesComponent`
369
+ Earlier, you removed the `HeroService` from the `providers` !{_array} of `HeroesComponent`
371
370
and added it to the `providers` !{_array} of `!{_AppModuleVsAppComp}`.
372
371
That move created a singleton `HeroService` instance, available to all components of the app.
373
372
Angular injects `HeroService` and you can use it in the `DashboardComponent`.
@@ -379,7 +378,7 @@ block templateUrl-path-resolution
379
378
+ makeExcerpt('src/app/dashboard.component.ts' ,'imports' )
380
379
381
380
:marked
382
- Now implement the `DashboardComponent` class like this:
381
+ Now create the `DashboardComponent` class like this:
383
382
384
383
+ makeExcerpt('src/app/dashboard.component.ts (class)' , 'class' )
385
384
@@ -474,7 +473,7 @@ code-example(format="nocode").
474
473
block route-params
475
474
:marked
476
475
You'll no longer receive the hero in a parent component property binding.
477
- The new `HeroDetailComponent` should take the `id` parameter from the `params` observable
476
+ The new `HeroDetailComponent` should take the `id` parameter from the `params` Observable
478
477
in the `ActivatedRoute` service and use the `HeroService` to fetch the hero with that `id`.
479
478
480
479
:marked
@@ -505,7 +504,7 @@ block route-params
505
504
506
505
block ngOnInit
507
506
:marked
508
- Inside the `ngOnInit` lifecycle hook, use the `params` observable to
507
+ Inside the `ngOnInit` lifecycle hook, use the `params` Observable to
509
508
extract the `id` parameter value from the `ActivatedRoute` service
510
509
and use the `HeroService` to fetch the hero with that `id`.
511
510
@@ -514,11 +513,11 @@ block ngOnInit
514
513
515
514
block extract-id
516
515
:marked
517
- The `switchMap` operator maps the id in the observable route parameters
518
- to a new `Observable`, the result of the `HeroService.getHero` method.
516
+ The `switchMap` operator maps the `id` in the Observable route parameters
517
+ to a new `Observable`, the result of the `HeroService.getHero() ` method.
519
518
520
- If a user re-navigates to this component while a getHero request is still processing,
521
- `switchMap` cancels the old request and then calls `HeroService.getHero` again.
519
+ If a user re-navigates to this component while a ` getHero` request is still processing,
520
+ `switchMap` cancels the old request and then calls `HeroService.getHero() ` again.
522
521
523
522
- var _str2int = _docsFor == ' dart' ? ' <code>int.parse</code> static method' : ' JavaScript (+) operator'
524
523
:marked
@@ -534,13 +533,13 @@ block extract-id
534
533
section of the [Routing & Navigation](../guide/router.html) page,
535
534
the `Router` manages the observables it provides and localizes
536
535
the subscriptions. The subscriptions are cleaned up when the component is destroyed, protecting against
537
- memory leaks, so you don't need to unsubscribe from the route params `Observable`.
536
+ memory leaks, so you don't need to unsubscribe from the route ` params` `Observable`.
538
537
539
538
:marked
540
539
### Add *HeroService.getHero*
541
540
542
- In the previous code snippet, `HeroService` doesn't have a `getHero` method. To fix this issue,
543
- open `HeroService` and add a `getHero` method that filters the heroes list from `getHeroes` by `id`.
541
+ In the previous code snippet, `HeroService` doesn't have a `getHero() ` method. To fix this issue,
542
+ open `HeroService` and add a `getHero() ` method that filters the heroes list from `getHeroes` by `id`.
544
543
545
544
+ makeExcerpt('src/app/hero.service.ts' , 'getHero' )
546
545
@@ -550,7 +549,7 @@ block extract-id
550
549
Users have several ways to navigate *to* the `HeroDetailComponent`.
551
550
552
551
To navigate somewhere else, users can click one of the two links in the `AppComponent` or click the browser's back button.
553
- Now add a third option, a `goBack` method that navigates backward one step in the browser's history stack
552
+ Now add a third option, a `goBack() ` method that navigates backward one step in the browser's history stack
554
553
using the `Location` service you injected previously.
555
554
556
555
+ makeExcerpt('src/app/hero-detail.component.ts' , 'goBack' )
@@ -633,8 +632,8 @@ block extract-id
633
632
establish key facts about the entire app for the Angular compiler.
634
633
635
634
It's a good idea to refactor the routing configuration into its own class.
636
- The current `RouterModule.forRoot()` produces an Angular `ModuleWithProviders`.
637
- A class dedicated to routing should be a *routing module*.
635
+ The current `RouterModule.forRoot()` produces an Angular `ModuleWithProviders`,
636
+ a class dedicated to routing should be a *routing module*.
638
637
For more information, see the [Milestone #2: The Routing Module](../guide/router.html#routing-module)
639
638
section of the [Routing & Navigation](../guide/router.html) page.
640
639
@@ -658,8 +657,8 @@ block extract-id
658
657
659
658
### Update *AppModule*
660
659
661
- Delete the routing configuration from `AppModule` and import the `AppRoutingModule`
662
- (*both* with an ES `import` statement *and* by adding it to the `NgModule.imports` list) .
660
+ Delete the routing configuration from `AppModule` and import the `AppRoutingModule`.
661
+ Use an ES `import` statement *and* add it to the `NgModule.imports` list.
663
662
664
663
:marked
665
664
Here is the revised `AppModule`, compared to its pre-refactor state:
@@ -696,9 +695,6 @@ block extract-id
696
695
697
696
Add the following HTML fragment at the bottom of the template where the `<hero-detail>` used to be:
698
697
699
-
700
- Add the following HTML fragment at the bottom of the template where the `<my-hero-detail>` used to be:
701
-
702
698
+ makeExcerpt('src/app/heroes.component.html' , 'mini-detail' , 'src/app/heroes.component.ts' )
703
699
704
700
@@ -733,41 +729,56 @@ figure.image-display
733
729
The component file is big.
734
730
It's difficult to find the component logic amidst the noise of HTML and CSS.
735
731
736
- Before making any more changes, migrate the template and styles to their own files.
732
+ Before making any more changes, migrate the template and styles to their own files.
737
733
738
- 1. *Cut-and-paste* the template contents into a new <span ngio-ex>heroes.component.html</span> file.
739
- 1. *Cut-and-paste* the styles contents into a new <span ngio-ex>heroes.component.css</span> file.
740
- 1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files.
734
+ First, move the template contents from `heroes.component.ts`
735
+ into a new <span ngio-ex>heroes.component.html</span> file.
736
+ Don't copy the backticks. As for `heroes.component.ts`, you'll
737
+ come back to it in a minute. Next, move the
738
+ styles contents into a new <span ngio-ex>heroes.component.css</span> file.
741
739
742
- .l-sub-section
743
- :marked
744
- The `styleUrls` property is !{_an} !{_array} of style file names (with paths).
745
- You could list multiple style files from different locations if you needed them.
740
+ The two new files should look like this:
741
+
742
+ + makeTabs(
743
+ ` toh-5/ts/src/app/heroes.component.html, toh-5/ts/src/app/heroes.component.css` ,
744
+ null ,
745
+ ` src/app/heroes.component.html, src/app/heroes.component.css` )
746
+
747
+ :marked
748
+ Now, back in the component metadata for `heroes.component.ts`,
749
+ delete `template` and `styles`, replacing them with
750
+ `templateUrl` and `styleUrls` respectively.
751
+ Set their properties to refer to the new files.
746
752
747
753
block heroes-component-cleanup
748
754
//- Only relevant for Dart.
749
755
750
756
+ makeExcerpt('src/app/heroes.component.ts (revised metadata)' , 'metadata' )
751
757
758
+ .l-sub-section
759
+ :marked
760
+ The `styleUrls` property is !{_an} !{_array} of style file names (with paths).
761
+ You could list multiple style files from different locations if you needed them.
762
+
752
763
:marked
753
764
### Update the _HeroesComponent_ class
754
765
755
766
The `HeroesComponent` navigates to the `HeroesDetailComponent` in response to a button click.
756
- The button's click event is bound to a `gotoDetail` method that navigates _imperatively_
767
+ The button's click event is bound to a `gotoDetail() ` method that navigates _imperatively_
757
768
by telling the router where to go.
758
769
759
770
This approach requires the following changes to the component class:
760
771
761
772
1. Import the `router` from the Angular router library.
762
- 1. Inject the `router` in the constructor ( along with the `HeroService`) .
763
- 1. Implement `gotoDetail` by calling the `router.navigate` method.
773
+ 1. Inject the `router` in the constructor, along with the `HeroService`.
774
+ 1. Implement `gotoDetail() ` by calling the `router.navigate() ` method.
764
775
765
776
+ makeExcerpt('src/app/heroes.component.ts' , 'gotoDetail' )
766
777
767
778
:marked
768
779
Note that you're passing a two-element *link parameters !{_array}*—a
769
780
path and the route parameter—to
770
- the `router.navigate` method, just as you did in the `[routerLink]` binding
781
+ the `router.navigate() ` method, just as you did in the `[routerLink]` binding
771
782
back in the `DashboardComponent`.
772
783
Here's the revised `HeroesComponent` class:
773
784
@@ -788,7 +799,7 @@ block heroes-component-cleanup
788
799
The dashboard heroes should display in a row of rectangles.
789
800
You've received around 60 lines of CSS for this purpose, including some simple media queries for responsive design.
790
801
791
- Adding the CSS to the component `styles` metadata
802
+ As you now know, adding the CSS to the component `styles` metadata
792
803
would obscure the component logic.
793
804
Instead, edit the CSS in a separate `*.css` file.
794
805
@@ -805,7 +816,7 @@ block heroes-component-cleanup
805
816
Add a <span ngio-ex>hero-detail.component.css</span> to the `!{_appDir}`
806
817
folder and refer to that file inside
807
818
the `styleUrls` !{_array} as you did for `DashboardComponent`.
808
- Also, in hero-detail.component.ts, remove the `hero` property `@Input` !{_decorator}
819
+ Also, in ` hero-detail.component.ts` , remove the `hero` property `@Input` !{_decorator}
809
820
<span if-docs="ts">and its import</span>.
810
821
811
822
Here's the content for the component CSS files.
0 commit comments