| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | - var _example = 'toh-5'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | block includes | 
					
						
							|  |  |  |  |   include ../_util-fns | 
					
						
							|  |  |  |  |   - var _appRoutingTsVsAppComp = 'app.routing.ts' | 
					
						
							|  |  |  |  |   - var _declsVsDirectives = 'declarations' | 
					
						
							|  |  |  |  |   - var _RoutesVsAtRouteConfig = 'Routes' | 
					
						
							|  |  |  |  |   - var _RouterModuleVsRouterDirectives = 'RouterModule' | 
					
						
							|  |  |  |  |   - var _redirectTo = 'redirectTo' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   # Routing Around the App | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   We received new requirements for our Tour of Heroes application: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   * Add a *Dashboard* view. | 
					
						
							|  |  |  |  |   * Navigate between the *Heroes* and *Dashboard* views. | 
					
						
							|  |  |  |  |   * Clicking on a hero in either view navigates to a detail view of the selected hero. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   * Clicking a *deep link* in an email opens the detail view for a particular hero. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   When we’re done, users will be able to navigate the app like this: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src='/resources/images/devguide/toh/nav-diagram.png' alt="View navigations") | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We'll add Angular’s *Component Router* to our app to satisfy these requirements. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     The [Routing and Navigation](../guide/router.html) chapter covers the router | 
					
						
							|  |  |  |  |     in more detail than we will in this tutorial. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Run the <live-example></live-example> for this part. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +ifDocsFor('ts|js') | 
					
						
							|  |  |  |  |   .l-sub-section | 
					
						
							|  |  |  |  |     img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     :marked | 
					
						
							|  |  |  |  |       To see the URL changes in the browser address bar, | 
					
						
							|  |  |  |  |       pop out the preview window by clicking the blue 'X' button in the upper right corner: | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Where We Left Off | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Before we continue with our Tour of Heroes, let’s verify that | 
					
						
							|  |  |  |  |   we have the following structure after adding our hero service | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   and hero detail component. If not, we’ll need to go back and follow the previous chapters. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | block intro-file-tree | 
					
						
							|  |  |  |  |   .filetree | 
					
						
							|  |  |  |  |     .file angular2-tour-of-heroes | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |     .children | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |       .file app | 
					
						
							|  |  |  |  |       .children | 
					
						
							|  |  |  |  |         .file app.component.ts | 
					
						
							|  |  |  |  |         .file app.module.ts | 
					
						
							|  |  |  |  |         .file hero.service.ts | 
					
						
							|  |  |  |  |         .file hero.ts | 
					
						
							|  |  |  |  |         .file hero-detail.component.ts | 
					
						
							|  |  |  |  |         .file main.ts | 
					
						
							|  |  |  |  |         .file mock-heroes.ts | 
					
						
							|  |  |  |  |       .file node_modules ... | 
					
						
							|  |  |  |  |       .file typings ... | 
					
						
							|  |  |  |  |       .file index.html | 
					
						
							|  |  |  |  |       .file package.json | 
					
						
							|  |  |  |  |       .file styles.css | 
					
						
							|  |  |  |  |       .file systemjs.config.js | 
					
						
							|  |  |  |  |       .file tsconfig.json | 
					
						
							|  |  |  |  |       .file typings.json | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | block keep-app-running | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     ### Keep the app transpiling and running | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     Open a terminal/console window and enter the following command to | 
					
						
							|  |  |  |  |     start the TypeScript compiler, start the server, and watch for changes: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   code-example(language="bash"). | 
					
						
							|  |  |  |  |     npm start | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   The application runs and updates automatically as we continue to build the Tour of Heroes. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ## Action plan | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Here's our plan: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   * Turn `AppComponent` into an application shell that only handles navigation | 
					
						
							|  |  |  |  |   * Relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent` | 
					
						
							|  |  |  |  |   * Add routing | 
					
						
							|  |  |  |  |   * Create a new `DashboardComponent` | 
					
						
							|  |  |  |  |   * Tie the *Dashboard* into the navigation structure | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     *Routing* is another name for *navigation*. The *router* is the mechanism for navigating from view to view. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Splitting the *AppComponent* | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Our current app loads `AppComponent` and immediately displays the list of heroes. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Our revised app should present a shell with a choice of views (*Dashboard* and *Heroes*) | 
					
						
							|  |  |  |  |   and then default to one of them. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   The `AppComponent` should only handle navigation. | 
					
						
							|  |  |  |  |   Let's move the display of *Heroes* out of `AppComponent` and into its own `HeroesComponent`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### *HeroesComponent* | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   `AppComponent` is already dedicated to *Heroes*. | 
					
						
							|  |  |  |  |   Instead of moving anything out of `AppComponent`, we'll just rename it `HeroesComponent` | 
					
						
							|  |  |  |  |   and create a new `AppComponent` shell separately. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   The steps are to rename: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   * <span ngio-ex>app.component.ts</span> file to <span ngio-ex>heroes.component.ts</span> | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   * `AppComponent` class to `HeroesComponent` | 
					
						
							|  |  |  |  |   * Selector `my-app` to `my-heroes` | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +makeExcerpt('app/heroes.component.ts (showing renamings only)', 'renaming') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Create *AppComponent* | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The new `AppComponent` will be the application shell. | 
					
						
							|  |  |  |  |   It will have some navigation links at the top and a display area below for the pages we navigate to. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   The initial steps are: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   * Create the file <span ngio-ex>app/app.component.ts</span>. | 
					
						
							|  |  |  |  |   * Define an <span if-docs="ts">exported</span> `AppComponent` class. | 
					
						
							|  |  |  |  |   * Add an `@Component` !{_decorator} above the class with a `my-app` selector. | 
					
						
							|  |  |  |  |   * Move the following from `HeroesComponent` to `AppComponent`: | 
					
						
							|  |  |  |  |     * `title` class property | 
					
						
							|  |  |  |  |     * `@Component` template `<h1>` element, which contains a binding to  `title` | 
					
						
							|  |  |  |  |   * Add a `<my-heroes>` element to the app template just below the heading so we still see the heroes. | 
					
						
							|  |  |  |  |   * Add `HeroesComponent` to the `!{_declsVsDirectives}` !{_array} of `!{_AppModuleVsAppComp}` so Angular recognizes the `<my-heroes>` tags. | 
					
						
							|  |  |  |  |   * Add `HeroService` to the  `providers` !{_array} of `!{_AppModuleVsAppComp}` because we'll need it in every other view. | 
					
						
							|  |  |  |  |   * Remove `HeroService` from the `HeroesComponent` `providers` !{_array} since it has been promoted. | 
					
						
							|  |  |  |  |   * Add the supporting `import` statements for `AppComponent`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Our first draft looks like this: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | block app-comp-v1 | 
					
						
							|  |  |  |  |   +makeTabs( | 
					
						
							|  |  |  |  |     `toh-5/ts/app/app.component.1.ts, | 
					
						
							|  |  |  |  |     toh-5/ts/app/app.module.1.ts`, | 
					
						
							|  |  |  |  |     ',', | 
					
						
							|  |  |  |  |     `app/app.component.ts (v1), | 
					
						
							|  |  |  |  |     app/app.module.ts (v1)`) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   The app still runs and still displays heroes. | 
					
						
							|  |  |  |  |   Our refactoring of `AppComponent` into a new `AppComponent` and a `HeroesComponent` worked! | 
					
						
							|  |  |  |  |   We have done no harm. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Add Routing | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   We're ready to take the next step. | 
					
						
							|  |  |  |  |   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*. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | block angular-router | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     The Angular router is an external, optional Angular NgModule called `RouterModule`. | 
					
						
							|  |  |  |  |     The router is a combination of multiple provided services (`RouterModule`), | 
					
						
							|  |  |  |  |     multiple directives (`RouterOutlet, RouterLink, RouterLinkActive`), | 
					
						
							|  |  |  |  |     and a configuration (`Routes`). We'll configure our routes first. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Add the base tag | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Open `index.html` and add `<base href="/">` at the top of the `<head>` section. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('index.html', 'base-href') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .callout.is-important | 
					
						
							|  |  |  |  |   header base href is essential | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     See the *base href* section of the [Router](../guide/router.html#!#base-href) | 
					
						
							|  |  |  |  |     chapter to learn why this matters. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | a#configure-routes | 
					
						
							|  |  |  |  | block router-config-intro | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     ### Configure routes | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     Our application doesn't have any routes yet. | 
					
						
							|  |  |  |  |     We'll start by creating a configuration file for the application routes. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   *Routes* tell the router which views to display when a user clicks a link or | 
					
						
							|  |  |  |  |   pastes a URL into the browser address bar. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Let's define our first route as a route to the heroes component: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _file = _docsFor == 'dart' ? 'app.component.ts' : 'app.routing.ts' | 
					
						
							|  |  |  |  | +makeExcerpt('app/' + _file + ' (heroes route)', 'heroes') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _are = _docsFor == 'dart' ? 'takes' : 'are' | 
					
						
							|  |  |  |  | - var _routePathPrefix = _docsFor == 'dart' ? '/' : '' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   The `!{_RoutesVsAtRouteConfig}` !{_are} !{_an} !{_array} of *route definitions*. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   We have only one route definition at the moment but rest assured, we'll add more. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   This *route definition* has the following parts: | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   - **path**: the router matches this route's path to the URL in the browser address bar (`!{_routePathPrefix}heroes`). | 
					
						
							|  |  |  |  |   <li if-docs="dart"> **name**: the official name of the route; | 
					
						
							|  |  |  |  |    it *must* begin with a capital letter to avoid confusion with the *path* (`Heroes`).</li> | 
					
						
							|  |  |  |  |   - **component**: the component that the router should create when navigating to this route (`HeroesComponent`). | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     Learn more about defining routes with `!{_RoutesVsAtRouteConfig}` in the [Routing](../guide/router.html) chapter. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +ifDocsFor('ts|js') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     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`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   +makeExcerpt('app/app.routing.ts (excerpt)', '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. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   :marked | 
					
						
							|  |  |  |  |     ### Make the router available | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     We've setup initial routes in the `app.routing.ts` file. Now we'll add it to our root NgModule. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     Import the `routing` constant from `app.routing.ts` and add it the `imports` !{_array} of `AppModule`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   +makeExcerpt('app/app.module.ts', 'routing') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | - var _heroesRoute = _docsFor == 'dart' ? "'Heroes'" : 'heroes' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Router Outlet | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   If we paste the path, `/heroes`, into the browser address bar, | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   the router should match it to the `!{_heroesRoute}` route and display the `HeroesComponent`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   But where? | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We have to ***tell it where*** by adding a `<router-outlet>` element to the bottom of the template. | 
					
						
							|  |  |  |  |   `RouterOutlet` is one of the <span if-docs="ts">directives provided by</span> the `!{_RouterModuleVsRouterDirectives}`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The router displays each component immediately below the `<router-outlet>` as we navigate through the application. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Router Links | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   We don't really expect users to paste a route URL into the address bar. | 
					
						
							|  |  |  |  |   We add an anchor tag to the template which, when clicked, triggers navigation to the `HeroesComponent`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   The revised template looks like this: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +makeExcerpt('app/app.component.1.ts', 'template-v2') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | block routerLink | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     Notice the `routerLink` binding in the anchor tag. | 
					
						
							|  |  |  |  |     We bind the `RouterLink` directive (another of the `RouterModule` directives) to a string | 
					
						
							|  |  |  |  |     that tells the router where to navigate when the user clicks the link. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     Since our link is not dynamic, we define a *routing instruction* with a **one-time binding** to our route **path**. | 
					
						
							|  |  |  |  |     Looking back at the route configuration, we confirm that `'/heroes'` is the path of the route to the `HeroesComponent`. | 
					
						
							|  |  |  |  |   .l-sub-section | 
					
						
							|  |  |  |  |     :marked | 
					
						
							|  |  |  |  |       Learn more about dynamic router links and the *link parameters array* | 
					
						
							|  |  |  |  |       in the [Routing](../guide/router.html#link-parameters-array) chapter. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Refresh the browser.  We see only the app title and heroes link. We don't see the heroes list. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     The browser's address bar shows `/`. | 
					
						
							|  |  |  |  |     The route path to `HeroesComponent` is `/heroes`, not `/`. | 
					
						
							|  |  |  |  |     We don't have a route that matches the path `/`, so there is nothing to show. | 
					
						
							|  |  |  |  |     That's something we'll want to fix. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We click the *Heroes* navigation link, the browser bar updates to `/heroes`, | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   and now we see the list of heroes. We are navigating at last! | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   At this stage, our `AppComponent` looks like this. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExample('app/app.component.1.ts', 'v2', 'app/app.component.ts (v2)') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   The  *AppComponent* is now attached to a router and displaying routed views. | 
					
						
							|  |  |  |  |   For this reason and to distinguish it from other kinds of components, | 
					
						
							|  |  |  |  |   we call this type of component a *Router Component*. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Add a *Dashboard* | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Routing only makes sense when we have multiple views. We need another view. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Create a placeholder `DashboardComponent` that gives us something to navigate to and from. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.1.ts (v1)', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We’ll come back and make it more useful later. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Configure the dashboard route | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Go back to `!{_appRoutingTsVsAppComp}` and teach it to navigate to the dashboard. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Import the dashboard component and | 
					
						
							|  |  |  |  |   add the following route definition to the `!{_RoutesVsAtRouteConfig}` !{_array} of definitions. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | - var _file = _docsFor == 'dart' ? 'lib/app_component.dart' : 'app/app.routing.ts' | 
					
						
							|  |  |  |  | +makeExcerpt(_file + ' (Dashboard route)', 'dashboard') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +ifDocsFor('ts|js') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     Also import and add `DashboardComponent` to our root NgModule's `declarations`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   +makeExcerpt('app/app.module.ts', 'dashboard') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   #### !{_redirectTo} | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We want the app to show the dashboard when it starts and | 
					
						
							|  |  |  |  |   we want to see a nice URL in the browser address bar that says `/dashboard`. | 
					
						
							|  |  |  |  |   Remember that the browser launches with `/` in the address bar. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | block redirect-vs-use-as-default | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     We can use a redirect route to make this happen. Add the following | 
					
						
							|  |  |  |  |     to our array of route definitions: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   +makeExcerpt('app/app.routing.ts','redirect') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   .l-sub-section | 
					
						
							|  |  |  |  |     :marked | 
					
						
							|  |  |  |  |       Learn about the *redirects* in the [Routing](../guide/router.html#!#redirect) chapter. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   #### Add navigation to the template | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Finally, add a dashboard navigation link to the template, just above the *Heroes* link. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | - var _vers = _docsFor == 'dart' ? '' : '.1' | 
					
						
							|  |  |  |  | +makeExcerpt('app/app.component' + _vers + '.ts', 'template-v3') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     We nestled 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. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   To see these changes in your browser, go to the application root (`/`) and reload. | 
					
						
							|  |  |  |  |   The app displays the dashboard and we can navigate between the dashboard and the heroes. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   ## Dashboard Top Heroes | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Let’s spice up the dashboard by displaying the top four heroes at a glance. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Replace the `template` metadata with a `templateUrl` property that points to a new | 
					
						
							|  |  |  |  |   template file. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +makeExcerpt('app/dashboard.component.ts', 'templateUrl') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   block templateUrl-path-resolution | 
					
						
							|  |  |  |  |     :marked | 
					
						
							|  |  |  |  |       We specify the path _all the way back to the application root_ — | 
					
						
							|  |  |  |  |       <span if-docs="ts">`app/` in this case —</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. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Create that file with this content: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.html') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :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* | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We'd like to re-use the `HeroService` to populate the component's `heroes` !{_array}. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Recall earlier in the chapter that we removed the `HeroService` from the `providers` !{_array} of `HeroesComponent` | 
					
						
							|  |  |  |  |   and added it to the `providers` !{_array} of `!{_AppModuleVsAppComp}`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   That move created a singleton `HeroService` instance, available to *all* components of the application. | 
					
						
							|  |  |  |  |   Angular will inject `HeroService` and we'll use it here in the `DashboardComponent`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Get heroes | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Open <span ngio-ex>dashboard.component.ts</span> and add the requisite `import` statements. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.2.ts','imports') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Now implement the `DashboardComponent` class like this: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.2.ts (class)', 'component') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We've seen this kind of logic before in the `HeroesComponent`: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   * Define a `heroes` !{_array} property. | 
					
						
							|  |  |  |  |   * 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. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   The noteworthy differences: we cherry-pick four heroes (2nd, 3rd, 4th, and 5th) | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   and stub the `gotoDetail` method until we're ready to implement it. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Refresh the browser and see four heroes in the new dashboard. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Navigate to Hero Details | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Although we display the details of a selected hero at the bottom of the `HeroesComponent`, | 
					
						
							|  |  |  |  |   we don't yet *navigate* to the `HeroDetailComponent` in the three ways specified in our requirements: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   1. from the *Dashboard* to a selected hero. | 
					
						
							|  |  |  |  |   1. from the *Heroes* list to a selected hero. | 
					
						
							|  |  |  |  |   1. from a "deep link" URL pasted into the browser address bar. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Adding a hero-detail route seems like an obvious place to start. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Routing to a hero detail | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We'll add a route to the `HeroDetailComponent` in `!{_appRoutingTsVsAppComp}` where our other routes are configured. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   The new route is a bit unusual in that we must tell the `HeroDetailComponent` *which hero to show*. | 
					
						
							|  |  |  |  |   We didn't have to tell the `HeroesComponent` or the `DashboardComponent` anything. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   At the moment the parent `HeroesComponent` sets the component's `hero` property to a | 
					
						
							|  |  |  |  |   hero object with a binding like this. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | code-example(language="html"). | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   <my-hero-detail [hero]="selectedHero"></my-hero-detail> | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   That clearly won't work in any of our routing scenarios. | 
					
						
							|  |  |  |  |   Certainly not the last one; we can't embed an entire hero object in the URL! Nor would we want to. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Parameterized route | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   We *can* add the hero's `id` to the URL. When routing to the hero whose `id` is 11, | 
					
						
							|  |  |  |  |   we could expect to see an URL such as this: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | code-example(format=''). | 
					
						
							|  |  |  |  |   /detail/11 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   The `/detail/` part of that URL is constant. The trailing numeric `id` part changes from hero to hero. | 
					
						
							|  |  |  |  |   We need to represent that variable part of the route with a *parameter* (or *token*) that stands for the hero's `id`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Configure a Route with a Parameter | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Here's the *route definition* we'll use. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _file = _docsFor == 'dart' ? 'app/app.component.ts' : 'app/app.routing.ts' | 
					
						
							|  |  |  |  | +makeExcerpt(_file + ' (hero detail)','hero-detail') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   The colon (:) in the path indicates that `:id` is a placeholder to be filled with a specific hero `id` | 
					
						
							|  |  |  |  |   when navigating to the `HeroDetailComponent`. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |     Remember to import the hero detail component before creating this route. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +ifDocsFor('ts|js') | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Add the `HeroDetailComponent` to our root NgModule's `declarations`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   +makeExcerpt('app/app.module.ts', 'hero-detail') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   We're finished with the application routes. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   We won't add a `'Hero Detail'` link to the template because users | 
					
						
							|  |  |  |  |   don't click a navigation *link* to view a particular hero. | 
					
						
							|  |  |  |  |   They click a *hero* whether that hero is displayed on the dashboard or in the heroes list. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   We'll get to those *hero* clicks later in the chapter. | 
					
						
							|  |  |  |  |   There's no point in working on them until the `HeroDetailComponent` | 
					
						
							|  |  |  |  |   is ready to be navigated *to*. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   That will require an `HeroDetailComponent` overhaul. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Revise the *HeroDetailComponent* | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Before we rewrite the `HeroDetailComponent`, let's review what it looks like now: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | +makeExample('toh-4/ts/app/hero-detail.component.ts', null, 'app/hero-detail.component.ts (current)') | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   The template won't change. We'll display a hero the same way. | 
					
						
							|  |  |  |  |   The big changes are driven by how we get the hero. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | block route-params | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     We will no longer receive the hero in a parent component property binding. | 
					
						
							|  |  |  |  |     The new `HeroDetailComponent` should take the `id` parameter from the `params` observable | 
					
						
							|  |  |  |  |     in the `ActivatedRoute` service and use the `HeroService` to fetch the hero with that `id`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   First, add the requisite imports: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _vers = _docsFor == 'dart' ? '' : '.1' | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero-detail.component' + _vers + '.ts', 'added-imports', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _ActivatedRoute = _docsFor == 'dart' ? 'RouteParams' : 'ActivatedRoute' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Let's have the `!{_ActivatedRoute}` service and the `HeroService` injected | 
					
						
							|  |  |  |  |   into the constructor, saving their values in private fields: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero-detail.component.ts (constructor)', 'ctor') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We tell the class that we want to implement the `OnInit` interface. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero-detail.component.ts', 'implement', '')(format=".") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | block ngOnInit | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Inside the `ngOnInit` lifecycle hook, we use the `params` observable to | 
					
						
							|  |  |  |  |     extract the `id` parameter value from the `ActivateRoute` service | 
					
						
							|  |  |  |  |     and use the `HeroService` to fetch the hero with that `id`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero-detail.component.ts', 'ngOnInit') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | block extract-id | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Notice how we extract the `id` by calling the `forEach` method | 
					
						
							|  |  |  |  |     which will deliver our !{_array} of route parameters. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _str2int = _docsFor == 'dart' ? '<code>int.parse</code> static method' : 'JavaScript (+) operator' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   The hero `id` is a number. Route parameters are *always strings*. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   So we convert the route parameter value to a number with the !{_str2int}. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Add *HeroService.getHero* | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The problem with this bit of code is that `HeroService` doesn't have a `getHero` method! | 
					
						
							|  |  |  |  |   We better fix that quickly before someone notices that we broke the app. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Open `HeroService` and add a `getHero` method that filters the heroes list from `getHeroes` by `id`: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero.service.ts', 'getHero') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Let's return to the `HeroDetailComponent` to clean up loose ends. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Find our way back | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   We can navigate *to* the `HeroDetailComponent` in several ways. | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   We'll add a third option, a `goBack` method that navigates backward one step in the browser's history stack. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +makeExcerpt('app/hero-detail.component.ts', 'goBack') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _CanDeactivateGuard = _docsFor == 'dart' ? '<em>routerCanDeactivate</em> hook' : '<em>CanDeactivate</em> guard' | 
					
						
							|  |  |  |  | - var _CanDeactivateGuardUri = _docsFor == 'dart' ? 'angular2.router/CanDeactivate-class' : 'router/index/CanDeactivate-interface' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Going back too far could take us out of the application. | 
					
						
							|  |  |  |  |     That's acceptable in a demo. We'd guard against it in a real application, | 
					
						
							|  |  |  |  |     perhaps with the [!{_CanDeactivateGuard}](../api/!{_CanDeactivateGuardUri}.html). | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Then we wire this method with an event binding to a *Back* button that we | 
					
						
							|  |  |  |  |   add to the bottom of the component template. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero-detail.component.html', 'back-button', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Modifing 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') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We update the component metadata with a `templateUrl` pointing to the template file that we just created. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/hero-detail.component.ts', 'templateUrl') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Refresh the browser and see the results. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Select a *Dashboard* Hero | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.html', 'click') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   We stubbed the `gotoDetail` method when we rewrote the `DashboardComponent`. | 
					
						
							|  |  |  |  |   Now we give it a real implementation. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.ts','gotoDetail') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | - var _pathVsName = _docsFor == 'dart' ? 'name' : 'path' | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   The `gotoDetail` method navigates in two steps: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   1. Set a route *link parameters !{_array}* | 
					
						
							|  |  |  |  |   1. Pass the !{_array} to the router's navigate method | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   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`. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   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.ts' | 
					
						
							|  |  |  |  | +makeExcerpt(_file + ' (hero detail)', 'hero-detail') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :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`): | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +makeExcerpt('app/dashboard.component.ts ()','import-router', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.ts', 'ctor', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Refresh the browser and select a hero from the dashboard; the app should navigate directly to that hero’s details. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Select a Hero in the *HeroesComponent* | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   We'll do something similar in the `HeroesComponent`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   That component's current template exhibits a "master/detail" style with the list of heroes | 
					
						
							|  |  |  |  |   at the top and details of the selected hero below. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | +makeExample('toh-4/ts/app/app.component.ts','template', 'app/heroes.component.ts (current template)')(format=".") | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   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. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### Add the *mini-detail* | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Add the following HTML fragment at the bottom of the template where the `<my-hero-detail>` used to be: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/heroes.component.html', 'mini-detail', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   After clicking a hero, the user should see something like this below the hero list: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src='/resources/images/devguide/toh/mini-hero-detail.png' alt="Mini Hero Detail" height="70") | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   ### Format with the *uppercase* pipe | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `uppercase` pipe | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   that we slipped into the interpolation binding. Look for it right after the pipe operator ( | ). | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/heroes.component.html', 'pipe', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Pipes are a good way to format strings, currency amounts, dates and other display data. | 
					
						
							|  |  |  |  |   Angular ships with several pipes and we can write our own. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							|  |  |  |  |   :marked | 
					
						
							|  |  |  |  |     Learn about pipes in the [Pipes](../guide/pipes.html) chapter. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Move content out of the component file | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   We are not done. We still have to update the component class to support navigation to the | 
					
						
							|  |  |  |  |   `HeroDetailComponent` when the user clicks the *View Details* button. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   This component file is really big. Most of it is either template or CSS styles. | 
					
						
							|  |  |  |  |   It's difficult to find the component logic amidst the noise of HTML and CSS. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Let's migrate the template and the styles to their own files before we make any more changes: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   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. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   1. *Set* the component metadata's `templateUrl` and `styleUrls` properties to refer to both files. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | .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. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/heroes.component.ts (revised metadata)', 'metadata') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Now we can see what's going on as we update the component class along the same lines as the dashboard: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   1. Import the `router` | 
					
						
							|  |  |  |  |   1. Inject the `router` in the constructor (along with the `HeroService`) | 
					
						
							|  |  |  |  |   1. Implement the `gotoDetail` method by calling the `router.navigate` method | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   with a two-part hero-detail link parameters !{_array}. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Here's the revised component class: | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/heroes.component.ts', 'class') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   Refresh the browser and start clicking. | 
					
						
							|  |  |  |  |   We can navigate around the app, from the dashboard to hero details and back, | 
					
						
							|  |  |  |  |   for heroes list to the mini-detail to the hero details and back to the heroes again. | 
					
						
							|  |  |  |  |   We can jump back and forth between the dashboard and the heroes. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   We've met all of the navigational requirements that propelled this chapter. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Styling the App | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The app is functional but pretty ugly. | 
					
						
							|  |  |  |  |   Our creative designer team provided some CSS files to make it look better. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### A Dashboard with Style | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The designers think we should display the dashboard heroes in a row of rectangles. | 
					
						
							|  |  |  |  |   They've given us ~60 lines of CSS for this purpose including some simple media queries for responsive design. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   If we paste these ~60 lines into the component `styles` metadata, | 
					
						
							|  |  |  |  |   they'll completely obscure the component logic. | 
					
						
							|  |  |  |  |   Let's not do that. It's easier to edit CSS in a separate `*.css` file anyway. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Add a <span ngio-ex>dashboard.component.css</span> file to the `!{_appDir}` folder and reference | 
					
						
							|  |  |  |  |   that file in the component metadata's `styleUrls` !{_array} property like this: | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/dashboard.component.ts (styleUrls)', 'css') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Stylish Hero Details | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The designers also gave us CSS styles specifically for the `HeroDetailComponent`. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Add a <span ngio-ex>hero-detail.component.css</span> to the `!{_appDir}` | 
					
						
							|  |  |  |  |   folder and refer to that file inside | 
					
						
							|  |  |  |  |   the `styleUrls` !{_array} as we did for `DashboardComponent`. | 
					
						
							|  |  |  |  |   Let's also remove the `hero` property `@Input` !{_decorator} | 
					
						
							|  |  |  |  |   <span if-docs="ts">and its import</span> | 
					
						
							|  |  |  |  |   while we are at it. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   Here's the content for the aforementioned component CSS files. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | block css-files | 
					
						
							|  |  |  |  |   +makeTabs( | 
					
						
							|  |  |  |  |     `toh-5/ts/app/hero-detail.component.css, | 
					
						
							|  |  |  |  |     toh-5/ts/app/dashboard.component.css`, | 
					
						
							|  |  |  |  |     null, | 
					
						
							|  |  |  |  |     `app/hero-detail.component.css, | 
					
						
							|  |  |  |  |     app/dashboard.component.css`) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Style the Navigation Links | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   The designers gave us CSS to make the navigation links in our `AppComponent` look more like selectable buttons. | 
					
						
							|  |  |  |  |   We cooperated by surrounding those links in `<nav>` tags. | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Add a <span ngio-ex>app.component.css</span> file to the `!{_appDir}` folder with the following content. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/app.component.css (navigation styles)', '') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | .l-sub-section | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   block router-link-active | 
					
						
							|  |  |  |  |     :marked | 
					
						
							|  |  |  |  |       **The *routerLinkActive* directive** | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       The Angular Router provides a `routerLinkActive` directive we can use to | 
					
						
							|  |  |  |  |       add a class to the HTML navigation element whose route matches the active route. | 
					
						
							|  |  |  |  |       All we have to do is define the style for it. Sweet! | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     +makeExcerpt('app/app.component.ts (active router links)', 'template') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   Set the `AppComponent`’s `styleUrls` property to this CSS file. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('app/app.component.ts','styleUrls') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							|  |  |  |  |   ### Global application styles | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   When we add styles to a component, we're keeping everything a component needs | 
					
						
							|  |  |  |  |   — HTML, the CSS, the code — together in one convenient place. | 
					
						
							|  |  |  |  |   It's pretty easy to package it all up and re-use the component somewhere else. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   We can also create styles at the *application level* outside of any component. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Our designers provided some basic styles to apply to elements across the entire app. | 
					
						
							|  |  |  |  |   These correspond to the full set of master styles that we | 
					
						
							|  |  |  |  |   introduced earlier (see | 
					
						
							|  |  |  |  |   [QuickStart, "Add some style"](../quickstart.html#!#add-some-style)). | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Here is an excerpt: | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | +makeExcerpt('styles.css (excerpt)', 'toh') | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | - var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/styles.css' | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Create the file <span ngio-ex>styles.css</span>, if it doesn't exist already. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   Ensure that it contains the [master styles given here](!{styles_css}). | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   If necessary, also edit <span ngio-ex>index.html</span> to refer to this stylesheet. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | +makeExcerpt('index.html (link ref)', 'css') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   Look at the app now. Our dashboard, heroes, and navigation links are styling! | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | figure.image-display | 
					
						
							|  |  |  |  |   img(src='/resources/images/devguide/toh/dashboard-top-heroes.png' alt="View navigations") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Application structure and code | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   Review the sample source code in the <live-example></live-example> for this chapter. | 
					
						
							|  |  |  |  |   Verify that we have the following structure: | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | block file-tree-end | 
					
						
							|  |  |  |  |   .filetree | 
					
						
							|  |  |  |  |     .file angular2-tour-of-heroes | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |     .children | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |       .file app | 
					
						
							|  |  |  |  |       .children | 
					
						
							|  |  |  |  |         .file app.component.css | 
					
						
							|  |  |  |  |         .file app.component.ts | 
					
						
							|  |  |  |  |         .file app.module.ts | 
					
						
							|  |  |  |  |         .file app.routing.ts | 
					
						
							|  |  |  |  |         .file dashboard.component.css | 
					
						
							|  |  |  |  |         .file dashboard.component.html | 
					
						
							|  |  |  |  |         .file dashboard.component.ts | 
					
						
							|  |  |  |  |         .file hero.service.ts | 
					
						
							|  |  |  |  |         .file hero.ts | 
					
						
							|  |  |  |  |         .file hero-detail.component.css | 
					
						
							|  |  |  |  |         .file hero-detail.component.html | 
					
						
							|  |  |  |  |         .file hero-detail.component.ts | 
					
						
							|  |  |  |  |         .file heroes.component.css | 
					
						
							|  |  |  |  |         .file heroes.component.html | 
					
						
							|  |  |  |  |         .file heroes.component.ts | 
					
						
							|  |  |  |  |         .file main.ts | 
					
						
							|  |  |  |  |         .file mock-heroes.ts | 
					
						
							|  |  |  |  |       .file node_modules ... | 
					
						
							|  |  |  |  |       .file typings ... | 
					
						
							|  |  |  |  |       .file index.html | 
					
						
							|  |  |  |  |       .file package.json | 
					
						
							|  |  |  |  |       .file styles.css | 
					
						
							|  |  |  |  |       .file systemjs.config.js | 
					
						
							|  |  |  |  |       .file tsconfig.json | 
					
						
							|  |  |  |  |       .file typings.json | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | .l-main-section | 
					
						
							|  |  |  |  | :marked | 
					
						
							|  |  |  |  |   ## Recap | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### The Road Behind | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   We travelled a great distance in this chapter | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   - We added the Angular *Component Router* to navigate among different components. | 
					
						
							|  |  |  |  |   - We learned how to create router links to represent navigation menu items. | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  |   - We used router link parameters to navigate to the details of user selected hero. | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   - 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. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ### The Road Ahead | 
					
						
							| 
									
										
										
										
											2016-08-17 13:31:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 13:39:17 -07:00
										 |  |  |  |   We have much of the foundation we need to build an application. | 
					
						
							|  |  |  |  |   We're still missing a key piece: remote data access. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   In the next chapter, | 
					
						
							|  |  |  |  |   we’ll replace our mock data with data retrieved from a server using http. |