| 
									
										
										
										
											2016-02-05 23:27:06 -08:00
										 |  |  | include ../_util-fns | 
					
						
							| 
									
										
										
										
											2016-05-02 16:53:25 -07:00
										 |  |  | .alert.is-critical | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     This chapter is a *work in progress*. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     It describes the *release candidate* Component Router which | 
					
						
							|  |  |  |     replaces the [*beta* router](router-deprecated.html). | 
					
						
							| 
									
										
										
										
											2015-10-17 10:01:41 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-10 18:31:46 +00:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-28 13:55:37 -08:00
										 |  |  |   The Angular ***Component Router*** enables navigation from one [view](./glossary.html#view) to the next | 
					
						
							|  |  |  |   as users perform application tasks. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   We cover the router's primary features in this chapter, illustrating them through the evolution | 
					
						
							|  |  |  |   of a small application that we can [run live](/resources/live-examples/router/ts/plnkr.html). | 
					
						
							|  |  |  | .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,  | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |     pop out the preview window by clicking the blue 'X' button in the upper right corner. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 13:55:37 -08:00
										 |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## Overview | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The browser is a familiar model of application navigation. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We enter a URL in the address bar and the browser navigates to a corresponding page. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   We click links on the page and the browser navigates to a new page. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We click the browser's back and forward buttons and the browser navigates | 
					
						
							|  |  |  |   backward and forward through the history of pages we've seen. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-28 13:55:37 -08:00
										 |  |  |   The Angular ***Component Router*** ("the router") borrows from this model. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   It can interpret a browser URL as an instruction | 
					
						
							|  |  |  |   to navigate to a client-generated view and pass optional parameters along to the supporting view component | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   to help it decide what specific content to present. | 
					
						
							|  |  |  |   We can bind the router to links on a page and it will navigate to | 
					
						
							|  |  |  |   the appropriate application view when the user clicks a link. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We can navigate imperatively when the user clicks a button, selects from a drop box, | 
					
						
							|  |  |  |   or in response to some other stimulus from any source. And the router logs activity | 
					
						
							|  |  |  |   in the browser's history journal so the back and forward buttons work as well. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |      | 
					
						
							|  |  |  |   We'll learn many router details in this chapter which covers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  |   * setting the [base href](#base-href) | 
					
						
							|  |  |  |   * importing from the [router library](#import) | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   * [configuring a router](#route-config) | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   * the [link parameters array](#link-parameters-array) that propels router navigation | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   * navigating when the user clicks a data-bound [RouterLink](#router-link) | 
					
						
							|  |  |  |   * navigating under [program control](#navigate) | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  |   * embedding critical information in the URL with [positional parameters](#positional-parameters) | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   * creating a [child router](#child-router) with its own routes | 
					
						
							|  |  |  |   * setting a [default route](#default) | 
					
						
							|  |  |  |   * confirming or canceling navigation with [router lifecycle hooks](#lifecycle-hooks) | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  |   * passing optional information in [matrix parameters](#matrix-parameters) | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   * choosing the "HTML5" or "hash" [URL style](#browser-url-styles) | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   We proceed in phases marked by milestones building from a simple two-pager with placeholder views | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   up to a modular, multi-view design with child routes. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   But first, an overview of router basics. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## The Basics | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Let's begin with a few core concepts of the Component Router. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Then we can explore the details through a sequence of examples. | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ### *<base href>* | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |   Most routing applications should add a `<base>` element to the **`index.html`** just after the  `<head>` tag | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   to tell the router how to compose navigation URLs. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   If the `app` folder is the application root, as it is for our sample application, | 
					
						
							|  |  |  |   set the `href` value *exactly* as shown here. | 
					
						
							| 
									
										
										
										
											2016-05-02 16:53:25 -07:00
										 |  |  | +makeExample('router/ts/index.1.html','base-href', 'index.html (base href)')(format=".") | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Router imports | 
					
						
							|  |  |  |   The Angular Component Router is an optional service that presents a particular component view for a given URL. | 
					
						
							|  |  |  |   It is not part of the Angular 2 core. It is in its own library package, `@angular/router`. | 
					
						
							|  |  |  |   We import what we need from it as we would from any other Angular package. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  | +makeExample('router/ts/app/app.component.1.ts','import-router', 'app/app.component.ts (import)')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     We cover other options in the [details below](#browser-url-styles). | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Configuration | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   When the browser's URL changes, the router looks for a corresponding **`RouteDefinition`** | 
					
						
							| 
									
										
										
										
											2016-01-03 16:27:57 -08:00
										 |  |  |   from which it can determine the component to display. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-17 15:02:15 -08:00
										 |  |  |   A router has no route definitions until we configure it. | 
					
						
							|  |  |  |   The preferred way to simultaneously create a router and add its routes is with a **`@RouteConfig`** [decorator](glossary.html#decorator) | 
					
						
							|  |  |  |   applied to the router's host component. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   In this example, we configure the top-level `AppComponent` with three route definitions | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.2.ts', 'route-config', 'app.component.ts (excerpt)')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     There are several flavors of `RouteDefinition`. | 
					
						
							| 
									
										
										
										
											2016-01-03 16:27:57 -08:00
										 |  |  |     The most common by far is the named **`Route`** which maps a URL path to a component | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-17 15:02:15 -08:00
										 |  |  |     The `name` field is the route name which **must** be spelled in **PascalCase**  | 
					
						
							|  |  |  |     to avoid potential confusion with the route `path`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     The `:id` in the third route is a token for a route parameter. In a URL such as `/hero/42`, "42" | 
					
						
							|  |  |  |     is the value of the `id` parameter. The corresponding `HeroDetailComponent` | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     will use that value to find and present the hero whose `id` is 42. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     We'll learn more about route parameters later in this chapter. | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   ### Router Outlet | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Now we know how the router gets its configuration. | 
					
						
							|  |  |  |   When the browser URL for this application becomes `/heroes`, | 
					
						
							| 
									
										
										
										
											2016-04-07 11:15:48 +03:00
										 |  |  |   the router matches that URL to the `RouteDefinition` named *Heroes* and displays the `HeroListComponent` | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   in a **`RouterOutlet`** that we've placed in the host view's HTML. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | code-example(format="", language="html"). | 
					
						
							|  |  |  |   <!-- Routed views go here --> | 
					
						
							|  |  |  |   <router-outlet></router-outlet> | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   ### Router Links | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Now we have routes configured and a place to render them, but | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   how do we navigate? The URL could arrive directly from the browser address bar. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   But most of the time we navigate as a result of some user action such as the click of | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   an anchor tag. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We add a **`RouterLink`** directive  to the anchor tag and bind it to a template expression that | 
					
						
							|  |  |  |   returns an array of route link parameters (the **link parameters array**). The router ultimately resolves that array | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   into a URL and a component view. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We see such bindings in the following `AppComponent` template: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.1.ts', 'template')(format=".") | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |  :marked | 
					
						
							|  |  |  |    We're adding two anchor tags with `RouterLink` directives. | 
					
						
							|  |  |  |    We bind each `RouterLink` to an array containing the string name of a route definition. | 
					
						
							|  |  |  |    'CrisisCenter' and 'Heroes' are the names of the `Routes` we configured above. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |    We'll learn to write more complex link expressions — and why they are arrays — | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |    [later](#link-parameters-array) in the chapter. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ### Let's summarize | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The `@RouterConfig` configuration tied the `AppComponent` to a router configured with routes. | 
					
						
							|  |  |  |   The component has a `RouterOutlet` where it can display views produced by the router. | 
					
						
							|  |  |  |   It has `RouterLinks` that users can click to navigate via the router. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The `AppComponent` has become a ***Routing Component***, a component that can route. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Here are the key *Component Router* terms and their meanings: | 
					
						
							|  |  |  | table | 
					
						
							|  |  |  |   tr | 
					
						
							|  |  |  |     th Router Part | 
					
						
							|  |  |  |     th Meaning | 
					
						
							|  |  |  |   tr | 
					
						
							|  |  |  |     td <code>Router</code> | 
					
						
							|  |  |  |     td. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |       Displays the application component for the active URL. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |       Manages navigation from one component to the next. | 
					
						
							|  |  |  |   tr | 
					
						
							|  |  |  |     td <code>@RouteConfig</code> | 
					
						
							|  |  |  |     td. | 
					
						
							| 
									
										
										
										
											2016-01-03 16:27:57 -08:00
										 |  |  |       Configures a router with <code>RouteDefinitions</code>, each mapping a URL path to a component. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   tr | 
					
						
							|  |  |  |     td <code>RouteDefinition</code> | 
					
						
							|  |  |  |     td. | 
					
						
							| 
									
										
										
										
											2016-01-03 16:27:57 -08:00
										 |  |  |       Defines how the router should navigate to a component based on a URL pattern. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   tr | 
					
						
							|  |  |  |     td <code>Route</code> | 
					
						
							|  |  |  |     td. | 
					
						
							|  |  |  |       The most common form of <code>RouteDefinition</code> consisting of a path, a route name, | 
					
						
							|  |  |  |       and a component type. | 
					
						
							|  |  |  |   tr | 
					
						
							|  |  |  |     td <code>RouterOutlet</code> | 
					
						
							|  |  |  |     td. | 
					
						
							|  |  |  |       The directive (<code><router-outlet></code>) that marks where the router should display a view. | 
					
						
							|  |  |  |   tr | 
					
						
							|  |  |  |     td <code>RouterLink</code> | 
					
						
							|  |  |  |     td. | 
					
						
							|  |  |  |       The directive for binding a clickable HTML element to | 
					
						
							|  |  |  |       a route. Clicking an anchor tag with a <code>routerLink</code> directive | 
					
						
							|  |  |  |       that is bound to a <i>Link Parameters Array</i> triggers a navigation. | 
					
						
							|  |  |  |   tr | 
					
						
							|  |  |  |     td <i>Link Parameters Array</i></code> | 
					
						
							|  |  |  |     td. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |       An array that the router inteprets into a routing instruction. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |       We can bind a <code>RouterLink</code> to that array or pass the array as an argument to | 
					
						
							|  |  |  |       the <code>Router.navigate</code> method. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   tr | 
					
						
							|  |  |  |     td <i>Routing Component</i></code> | 
					
						
							|  |  |  |     td. | 
					
						
							|  |  |  |       An Angular component with an attached router. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   We've barely touched the surface of the router and its capabilities. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The following detail sections describe a sample routing application | 
					
						
							|  |  |  |   as it evolves over a sequence of milestones.  | 
					
						
							|  |  |  |   We strongly recommend taking the time to read and understand this story. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## The Sample Application | 
					
						
							|  |  |  |   We have an application in mind as we move from milestone to milestone. | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |     While we make incremental progress toward the ultimate sample application, this chapter is not a tutorial. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |     We discuss code and design decisions pertinent to routing and application design. | 
					
						
							|  |  |  |     We gloss over everything in between. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     The full source is available in the [live example](/resources/live-examples/router/ts/plnkr.html). | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Our client is the Hero Employment Agency. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Heroes need work and The Agency finds Crises for them to solve. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The application has two main feature areas: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   1. A *Crisis Center* where we maintain the list of crises for assignment to heroes. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   1. A *Heroes* area where we maintain the list of heroes employed by The Agency. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   Run the [live example](/resources/live-examples/router/ts/plnkr.html). | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   It opens in the *Crisis Center*.  We'll come back to that. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Click the *Heroes* link. We're presented with a list of Heroes. | 
					
						
							|  |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/hero-list.png' alt="Hero List" width="250") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   We select one and the application takes us to a hero editing screen. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/hero-detail.png' alt="Crisis Center Detail" width="250") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   Our changes take effect immediately. We click the "Back" button and the | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   app returns us to the Heroes list. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   We could have clicked the browser's back button instead. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   That would have returned us to the Heroes List as well. | 
					
						
							|  |  |  |   Angular app navigation updates the browser history as normal web navigation does. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Now click the *Crisis Center* link. We go to the *Crisis Center* and its list of ongoing crises. | 
					
						
							|  |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/crisis-center-list.png' alt="Crisis Center List" ) | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   We select one and the application takes us to a crisis editing screen. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/crisis-center-detail.png' alt="Crisis Center Detail") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |    This is a bit different from the *Hero Detail*. *Hero Detail* saves the changes as we type. | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |    In *Crisis Detail* our changes are temporary until we either save or discard them by pressing the "Save" or "Cancel" buttons.  | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |    Both buttons navigate back to the *Crisis Center* and its list of crises. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |    Suppose we click a crisis, make a change, but ***do not click either button***. | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |    Maybe we click the browser back button instead. Maybe we click the "Heroes" link.  | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |     | 
					
						
							|  |  |  |    Do either. Up pops a dialog box. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/confirm-dialog.png' alt="Confirm Dialog" width="300") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   We can say "OK" and lose our changes or click "Cancel" and continue editing. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The router supports a `routerCanDeactivate` lifecycle hook that gives us a chance to clean-up | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   or ask the user's permission before navigating away from the current view. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Here we see an entire user session that touches all of these features. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | <a id="full-app-demo"></a> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/router-anim.gif' alt="App in action" ) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   Here's a diagram of all application routing options: | 
					
						
							|  |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/complete-nav.png' alt="Navigation diagram" ) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   This app illustrates the router features we'll cover in this chapter | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * navigating to a component (*Heroes* link to "Heroes List") | 
					
						
							|  |  |  |   * including a route parameter (passing the Hero `id` while routing to the "Hero Detail") | 
					
						
							|  |  |  |   * child routes (the *Crisis Center* has its own routes) | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   * the `routerCanDeactivate` lifecycle hook (ask permission to discard unsaved changes) | 
					
						
							| 
									
										
										
										
											2015-11-10 18:31:46 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | <a id="getting-started"></a> | 
					
						
							| 
									
										
										
										
											2015-10-17 10:01:41 -07:00
										 |  |  | .l-main-section | 
					
						
							| 
									
										
										
										
											2015-11-10 18:31:46 +00:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ## Milestone #1: Getting Started with the Router | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Let's begin with a simple version of the app that navigates between two empty views. | 
					
						
							|  |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" ) | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | <a id="base-href"></a> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   <a id="base-href"></a> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### Set the *<base href>* | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The Component Router uses the browser's | 
					
						
							|  |  |  |   [history.pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries) | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   for navigation. Thanks to `pushState`, we can make our in-app URL paths look the way we want them to | 
					
						
							|  |  |  |   look, e.g. `localhost:3000/crisis-center`. Our in-app URLs can be indistinguishable from server URLs. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Modern HTML 5 browsers were the first to support `pushState` which is why many people refer to these URLs as | 
					
						
							|  |  |  |   "HTML 5 style" URLs. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   We must **add a [<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag** | 
					
						
							| 
									
										
										
										
											2016-01-17 15:02:15 -08:00
										 |  |  |   to the `index.html` to make `pushState` routing work.  | 
					
						
							|  |  |  |   The browser also needs the base `href` value to prefix *relative* URLs when downloading and linking to  | 
					
						
							| 
									
										
										
										
											2016-01-17 19:59:34 -08:00
										 |  |  |   css files, scripts, and images. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Add the base element just after the  `<head>` tag. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   If the `app` folder is the application root, as it is for our application, | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  |   set the `href` value in **`index.html`** *exactly* as shown here. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-02 16:53:25 -07:00
										 |  |  | +makeExample('router/ts/index.1.html','base-href', 'index.html (base href)')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     HTML 5 style navigation is the Component Router default. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     Learn why "HTML 5" style is preferred, how to adjust its behavior, and how to switch to the | 
					
						
							|  |  |  |     older hash (#) style if necessary in the [Browser URL Styles](#browser-url-styles) appendix below. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     #### Live example note | 
					
						
							| 
									
										
										
										
											2016-04-07 11:15:48 +03:00
										 |  |  |     We have to get tricky when we run the live example because the host service sets | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     the application base address dynamically. That's why we replace the `<base href...>` with a | 
					
						
							|  |  |  |     script that writes a `<base>` tag on the fly to match. | 
					
						
							|  |  |  |   code-example(format="") | 
					
						
							|  |  |  |     <script>document.write('<base href="' + document.location + '" />');</script> | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     We should only need this trick for the live example, not production code. | 
					
						
							| 
									
										
										
										
											2016-04-27 11:28:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | <a id="import"></a> | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Import from the Component Router library | 
					
						
							|  |  |  |   The Component Router is not part of the Angular 2 core. It is in its own library. | 
					
						
							|  |  |  |   The router is an optional service because not all applications need routing and, | 
					
						
							|  |  |  |   depending on your requirements, you may need a different routing library. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   The Component Router library is in its own `@angular/router` package. | 
					
						
							|  |  |  |   We import what we need from it as we would from any Angular package: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.1.ts','import-router', 'app/app.component.ts (import)')(format=".") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ### Booting with the router service providers | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   Our app launches from the `main.ts` file in the `/app` folder so let's start there. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   It's short and all of it is relevant to routing. | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  | +makeExample('router/ts/app/main.1.ts','all', 'main.ts')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   We import our root `AppComponent` and Angular's `bootstrap` function as expected. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We also import `ROUTER_PROVIDERS` from the router library. | 
					
						
							|  |  |  |   The router is a service implemented by a collection of *Dependency Injection* providers, most of which are identified in the | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   `ROUTER_PROVIDERS` array. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We're booting Angular with `AppComponent` as our app's root component and | 
					
						
							|  |  |  |   registering providers, as we often do, in the providers array in the second parameter of the `bootstrap` function. | 
					
						
							|  |  |  |   Providing the router providers at the root makes the Component Router available everywhere in our application. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     Learn about providers, the `provide` function, and injected services in the | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     [Dependency Injection chapter](dependency-injection.html). | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### The *AppComponent* shell | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The root `AppComponent` is the application shell. It has title at the top, a navigation bar with two links, | 
					
						
							|  |  |  |   and a *Router Outlet* at the bottom where the router swaps views on and off the page. Here's what we mean: | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/shell-and-outlet.png' alt="Shell" width="300" ) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   <a id="shell-template"></a> | 
					
						
							|  |  |  |   The corresponding component template looks like this: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.1.ts','template')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   ### *RouterOutlet* | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   `RouterOutlet` is a component from the router library. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The router displays views within the bounds of the `<router-outlet>` tags. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     A template may hold exactly one ***unnamed*** `<router-outlet>`. | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | <a id="router-link"></a> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ### *RouterLink* binding | 
					
						
							|  |  |  |   Above the outlet, within the anchor tags, we see [Property Bindings](template-syntax.html#property-binding) to | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   the `RouterLink` directive that look like `[routerLink]="[...]"`. We imported `RouterLink` from the router library. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   The template expression to the right of the equals (=) returns a *link parameters array*. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   A link parameters array holds the ingredients for router navigation: | 
					
						
							|  |  |  |   * the name of the route that prescribes the destination component and a path for the URL | 
					
						
							|  |  |  |   * the optional route and query parameters that go into the route URL | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The arrays in this example each have a single string parameter, the name of a `Route` that | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   we'll configure for this application with `@RouteConfig()`. We don't need to set route parameters yet. | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     Learn more about the link parameters array in the [appendix below](#link-parameters-array). | 
					
						
							|  |  |  | <a id="route-config"></a> | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### *@RouteConfig()* | 
					
						
							|  |  |  |   A router holds a list of route definitions. The list is empty for a new router. We must configure it. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   A router also needs a **Host Component**, a point of origin for its navigations. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   It's natural to combine the creation of a new router, its configuration, and its assignment to a host component | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   in a single step. That's the purpose of the `@RouteConfig` decorator which we put to good use here: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.1.ts','route-config')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The `@RouteConfig` decorator creates a new router. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We applied the decorator to `AppComponent` which makes that the router's host component. | 
					
						
							|  |  |  |   The argument to `@RouteConfig()` is an array of **Route Definitions**. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We're supplying two definitions: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.1.ts','route-defs')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-03-16 21:42:55 -07:00
										 |  |  |   Each definition translates to a [Route](../api/router/Route-class.html) which has a | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * `path` - the URL path segment for this route | 
					
						
							|  |  |  |   * `name` - the name of the route | 
					
						
							| 
									
										
										
										
											2016-01-03 16:27:57 -08:00
										 |  |  |   * `component` - the component associated with this route. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The router draws upon its registry of route definition when | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   1. the browser URL changes | 
					
						
							|  |  |  |   2. we tell the router to go to a named route | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   In plain English, we might say of the first route: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   1. *When the browser's location URL changes to **match the path** segment `/crisis-center`, create or retrieve an instance of | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   the `CrisisCenterComponent` and display its view.* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   1. *When the application requests navigation to a route **named** `CrisisCenter`, compose a browser URL | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   with the path segment `/crisis-center`, update the browser's address location and history, create or retrieve an instance of | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   the `CrisisListComponent`, and display that component's list view.* | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   ### "Getting Started" wrap-up | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We've got a very basic, navigating app, one that can switch between two views | 
					
						
							|  |  |  |   when the user clicks a link. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We've learned how to | 
					
						
							|  |  |  |   * load the router library | 
					
						
							|  |  |  |   * add a nav bar to the shell template with anchor tags and `routerLink` directives | 
					
						
							|  |  |  |   * added a `router-outlet` to the shell template where views will be displayed | 
					
						
							|  |  |  |   * configure the router with `@RouterConfig` | 
					
						
							|  |  |  |   * set the router to compose "HTML 5" browser URLs. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The rest of the starter app is mundane, with little interest from a router perspective. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Here are the details for readers inclined to build the sample through to this milestone. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Our starter app's structure looks like this: | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  | .filetree | 
					
						
							|  |  |  |   .file router-sample | 
					
						
							|  |  |  |   .children | 
					
						
							|  |  |  |     .file app | 
					
						
							|  |  |  |       .children | 
					
						
							|  |  |  |         .file app.component.ts | 
					
						
							|  |  |  |         .file crisis-list.component.ts | 
					
						
							|  |  |  |         .file hero-list.component.ts | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |         .file main.ts | 
					
						
							|  |  |  |     .file node_modules ... | 
					
						
							|  |  |  |     .file typings ... | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  |     .file index.html | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |     .file package.json | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  |     .file styles.css | 
					
						
							|  |  |  |     .file tsconfig.json | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |     .file typings.json | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   Here are the files discussed in this milestone | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | +makeTabs( | 
					
						
							|  |  |  |   `router/ts/app/app.component.1.ts, | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   router/ts/app/main.1.ts, | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   router/ts/app/hero-list.component.ts, | 
					
						
							|  |  |  |   router/ts/app/crisis-list.component.ts, | 
					
						
							|  |  |  |   router/ts/index.html`, | 
					
						
							|  |  |  |   ',all,,', | 
					
						
							|  |  |  |   `app.component.ts,  | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   main.ts, | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   hero-list.component.ts, | 
					
						
							|  |  |  |   crisis-list.component.ts,  | 
					
						
							|  |  |  |   index.html`) | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <a id="heroes-feature"></a> | 
					
						
							|  |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## Milestone #2: The Heroes Feature | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We've seen how to navigate using the `RouterLink` directive. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Now we'll learn some new tricks such as how to | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   * organize our app into *feature areas* | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * navigate imperatively from one component to another | 
					
						
							|  |  |  |   * pass information along in route parameters (`RouteParams`) | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   To demonstrate, we'll build out the *Heroes* feature. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### The Heroes "feature area" | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   A typical application has multiple *feature areas*, each an island of functionality | 
					
						
							|  |  |  |   with its own workflow(s), dedicated to a particular business purpose. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   We could continue to add files to the `app/` folder. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   That's unrealistic and ultimately not maintainable. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We think it's better to put each feature area in its own folder. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   Our first step is to **create a separate `app/heroes/` folder** | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   and add *Hero Management* feature files there. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We won't be creative about it. Our example is pretty much a | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   copy of the code and capabilities in the "[Tutorial: Tour of Heroes](../tutorial/index.html)". | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Here's how the user will experience this version of the app | 
					
						
							|  |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/router-2-anim.gif' alt="App in action" ) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Add Heroes functionality | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We delete the placeholder `hero-list.component.ts` that's in | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   the `app/` folder. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We create a new `hero-list.component.ts` in the `app/heroes/` | 
					
						
							|  |  |  |   folder and copy over the contents of the final `heroes.component.ts` from the tutorial. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   We also copy the `hero-detail.component.ts` and the `hero.service.ts` files | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   into the `heroes/` folder. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   When we're done organizing, we have three *Hero Management* files: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  | .filetree | 
					
						
							|  |  |  |   .file app/heroes | 
					
						
							|  |  |  |   .children | 
					
						
							|  |  |  |     .file hero-detail.component.ts | 
					
						
							|  |  |  |     .file hero-list.component.ts | 
					
						
							|  |  |  |     .file hero.service.ts | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   We provide the `HeroService` in the application root `AppComponent` | 
					
						
							|  |  |  |   so that is available everywhere in the app. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Now it's time for some surgery to bring these files and the rest of the app | 
					
						
							|  |  |  |   into alignment with our application router. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ### New route definition with route parameter | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The new Heroes feature has two interacting components, the list and the detail. | 
					
						
							|  |  |  |   The list view is self-sufficient; we navigate to it, it gets a list of heroes and displays them. | 
					
						
							|  |  |  |   It doesn't need any outside information. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The detail view is different. It displays a particular hero. It can't know which hero on its own. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   That information must come from outside. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   In our example, when the user selects a hero from the list, we navigate to the detail view to show that hero. | 
					
						
							|  |  |  |   We'll tell the detail view which hero to display by including the selected hero's id in the route URL. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   With that plan in mind, we return to the `app.component.ts` to  make changes to the router's configuration | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   First, we import the two components from their new locations in the `app/heroes/` folder: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.2.ts','hero-import')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   Then we update the `@RouteConfig` route definitions : | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.2.ts','route-config')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The `CrisisCenter` and `Heroes` definitions didn't change. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   While we moved `hero-list.component.ts` to a new location in the `app/heroes/` folder, that only affects the `import` statement; | 
					
						
							|  |  |  |   it doesn't affect its route definition. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We added a new route definition for the `HeroDetailComponent` — and this definition has a twist. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | +makeExample('router/ts/app/app.component.2.ts','hero-detail-route')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   Notice the `:id` token in the path. That creates a slot in the path for a **Route Parameter**. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   In this case, we're expecting the router to insert the `id` of a hero into that slot. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   If we tell the router to navigate to the detail component and display "Magneta", we expect hero `id` (15) to appear in the | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   browser URL like this: | 
					
						
							|  |  |  | code-example(format="." language="bash"). | 
					
						
							|  |  |  |   localhost:3000/hero/15 | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   If a user enters that URL into the browser address bar, the router should recognize the | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   pattern and go to the same "Magneta" detail view. | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     #### Route parameter or query parameter? | 
					
						
							|  |  |  |     Embedding the route parameter token, `:id`, in the route definition path is a good choice for our scenario  | 
					
						
							|  |  |  |     because the `id` is *required* by the `HeroDetailComponent` and because | 
					
						
							|  |  |  |     the value `15` in the path clearly distinguishes the route to "Magneta" from  | 
					
						
							|  |  |  |     a route for some other hero. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     A [query parameter](#query-parameter) might be a better choice if we were passing an *optional* value to `HeroDetailComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  | <a id="navigate"></a> | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### Navigate to the detail imperatively | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   *We don't navigate to the detail component by clicking a link*. | 
					
						
							|  |  |  |   We won't be adding a new anchor tag to the shell navigation bar. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Instead, we'll *detect* when the user selects a hero from the list and *command* the router | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   to present the hero detail view of the selected hero. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We'll adjust the `HeroListComponent` to implement these tasks, beginning with its constructor | 
					
						
							|  |  |  |   which acquires the router service and the `HeroService` by dependency injection: | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.1.ts','ctor')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We make a few changes to the template: | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.1.ts','template')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   The template defines an `*ngFor` repeater such as [we've seen before](displaying-data.html#ngFor). | 
					
						
							|  |  |  |   There's a `(click)` [EventBinding](template-syntax.html#event-binding) to the component's `onSelect` method | 
					
						
							|  |  |  |   which we implement as follows: | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.1.ts','select')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   It calls the router's **`navigate`** method with a **Link Parameters Array**. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   This array is similar to the  *link parameters array* we met [earlier](#shell-template) in an anchor tag while | 
					
						
							|  |  |  |   binding to the `RouterLink` directive. This time we see it in code rather than in HTML. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  |   <a id="positional-parameters"></id> | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   ### Setting the route parameters object | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   We're navigating to the `HeroDetailComponent` where we expect to see the details of the selected hero. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We'll need *two* pieces of information: the destination and the hero's `id`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Accordingly, the *link parameters array* has *two* items:  the **name** of the destination route and a **route parameters object** that specifies the | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   `id` of the selected hero. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The router composes the appropriate two-part destination URL from this array: | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | code-example(format="." language="bash"). | 
					
						
							|  |  |  |   localhost:3000/hero/15 | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Getting the route parameter | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   <a id="hero-detail-ctor"></a> | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   How does the target `HeroDetailComponent` learn about that `id`? | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Certainly not by analyzing the URL!  That's the router's job. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The router extracts the route parameter (`id:15`) from the URL and supplies it to | 
					
						
							|  |  |  |   the `HeroDetailComponent` via the **RouteParams** service. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   As usual, we write a constructor that asks Angular to inject that service among the other services | 
					
						
							|  |  |  |   that the component require and reference them as private variables. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-detail.component.1.ts','ctor')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   Later, in the `ngOnInit` method, | 
					
						
							|  |  |  |   we ask the `RouteParams` service for the `id` parameter by name and | 
					
						
							|  |  |  |   tell the `HeroService` to fetch the hero with that `id`. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-detail.component.1.ts','ngOnInit')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     We put the data access logic in the `ngOnInit` method rather than inside the constructor | 
					
						
							|  |  |  |     to improve the component's testability. | 
					
						
							|  |  |  |     We explore this point in greater detail in the [OnInit appendix](#onInit) below. | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Navigating back to the list component | 
					
						
							|  |  |  |   The `HeroDetailComponent` has a "Back" button wired to its `gotoHeroes` method that navigates imperatively | 
					
						
							|  |  |  |   back to the `HeroListComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The router `navigate` method takes the same one-item *link parameters array*  | 
					
						
							|  |  |  |   that we wrote for the `[routerLink]` directive binding. | 
					
						
							|  |  |  |   It holds the **name of the `HeroListComponent` route**:  | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ### Heroes App Wrap-up | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We've reached the second milestone in our router education. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We've learned how to | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   * organize our app into *feature areas* | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * navigate imperatively from one component to another | 
					
						
							|  |  |  |   * pass information along in route parameters (`RouteParams`) | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   After these changes, the folder structure looks like this: | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  | .filetree | 
					
						
							|  |  |  |   .file router-sample | 
					
						
							|  |  |  |   .children | 
					
						
							|  |  |  |     .file app | 
					
						
							|  |  |  |     .children | 
					
						
							|  |  |  |       .file heroes | 
					
						
							|  |  |  |       .children | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |         .file hero-detail.component.ts | 
					
						
							|  |  |  |         .file hero-list.component.ts | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |         .file hero.service.ts | 
					
						
							| 
									
										
										
										
											2016-02-29 13:29:42 -08:00
										 |  |  |       .file app.component.ts | 
					
						
							|  |  |  |       .file crisis-list.component.ts | 
					
						
							| 
									
										
										
										
											2016-02-25 13:47:54 +01:00
										 |  |  |       .file main.ts | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |     .file node_modules ... | 
					
						
							|  |  |  |     .file typings ... | 
					
						
							|  |  |  |     .file index.html | 
					
						
							|  |  |  |     .file package.json | 
					
						
							|  |  |  |     .file styles.css | 
					
						
							|  |  |  |     .file tsconfig.json | 
					
						
							|  |  |  |     .file typings.json | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   <a id="heroes-app-code"></a> | 
					
						
							|  |  |  |   ### The Heroes App code | 
					
						
							|  |  |  |   Here are the relevant files for this version of the sample application. | 
					
						
							|  |  |  | +makeTabs( | 
					
						
							|  |  |  |   `router/ts/app/app.component.2.ts, | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |    router/ts/app/heroes/hero-list.component.1.ts, | 
					
						
							|  |  |  |    router/ts/app/heroes/hero-detail.component.1.ts, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |    router/ts/app/heroes/hero.service.ts`, | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |    null, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   `app.component.ts, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   hero-list.component.ts, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   hero-detail.component.ts, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   hero.service.ts`) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <a id="crisis-center-feature"></a> | 
					
						
							|  |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## Milestone #3: The Crisis Center | 
					
						
							|  |  |  |   The *Crisis Center* is a fake view at the moment. Time to make it useful. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The new *Crisis Center* begins as a virtual copy of the *Heroes* feature. | 
					
						
							|  |  |  |   We create a new `app/crisis-center` folder, copy the Hero files, | 
					
						
							|  |  |  |   and change every mention of "hero" to "crisis". | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   A `Crisis` has an `id` and `name`, just like a `Hero` | 
					
						
							|  |  |  |   The new `CrisisListComponent` displays lists of crises. | 
					
						
							|  |  |  |   When the user selects a crisis, the app navigates to the `CrisisDetailComponent` | 
					
						
							|  |  |  |   for display and editing of the crisis name. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Voilà, instant feature module! | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   There's no point to this exercise unless we can learn something. | 
					
						
							|  |  |  |   We do have new ideas and techniques in mind: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * The application should navigate to the *Crisis Center* by default. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * The user should be able to cancel unwanted changes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * The router should prevent navigation away from the detail view while there are pending changes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   There are also a few lingering annoyances in the *Heroes* implementation that we can cure in the *Crisis Center*. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   * We currently register every route of every view at the highest level of the application. | 
					
						
							|  |  |  |   If we expand the *Crisis Center* with a 100 new views, we'll make 100 changes to the | 
					
						
							|  |  |  |   `AppComponent` route configuration. If we rename a *Crisis Center* component or change a route definition, | 
					
						
							|  |  |  |   we'll be changing the `AppComponent` too. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   * If we followed *Heroes* lead, we'd be adding the `CrisisService` to the providers in `app.component.ts`. | 
					
						
							|  |  |  |   Then both `HeroService` and `CrisisService` would be available everywhere although | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   they're only needed in their respective feature modules. That stinks. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   Changes to a sub-module such as *Crisis Center* shouldn't provoke changes to the `AppComponent` or `main.ts`. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We need to [*separate our concerns*](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We'll fix all of these problems and add the new routing features to *Crisis Center*. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The most significant fix is the introduction of a **child *Routing Component*** | 
					
						
							|  |  |  |   and its **child router** | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   We'll leave *Heroes* in its less-than-perfect state to | 
					
						
							|  |  |  |   serve as a contrast with what we hope is a superior *Crisis Center*. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ### A free-standing Crisis Center Feature Module | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   The *Crisis Center* is one of two application workflows. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Users navigate between them depending on whether they are managing crises or heroes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The `CrisisCenter` and `Heroes` components are children of the root `AppComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Unfortunately, they and their related files are physically commingled in the same folder with the `AppComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We'd prefer to separate them in their own *feature areas* so they can operate and evolve independently. | 
					
						
							|  |  |  |   Someday we might re-use one or the other in a different application. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Someday we might load one of them dynamically only when the user chose to enter its workflow. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Some might call it [yagni](http://martinfowler.com/bliki/Yagni.html) to even think about such things. | 
					
						
							|  |  |  |   But we're right to be nervous about the way *Heroes* and *Crisis Center* artifacts are | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   bubbling up to the root `AppComponent` and blending with each other. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   That's a [code smell](http://martinfowler.com/bliki/CodeSmell.html). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Isolating feature area modules from each other looks good to us. | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     It's looking good as a general pattern for Angular applications. | 
					
						
							|  |  |  |   figure.image-display | 
					
						
							|  |  |  |     img(src='/resources/images/devguide/router/component-tree.png' alt="Component Tree" ) | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     * each feature area in its own module folder | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     * each area with its own root component | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     * each area root component with its own router-outlet and child routes | 
					
						
							|  |  |  |     * area routes rarely (if ever) cross | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   We'll make the *Crisis Center* stand on its own and leave the *Heroes* as it is | 
					
						
							|  |  |  |   so we can compare the effort, results, and consequences. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Then each of us can decide which path to prefer (as if we didn't already know). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   <a id="child-router"></id> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### Child Routing Component | 
					
						
							| 
									
										
										
										
											2016-01-27 02:29:51 +01:00
										 |  |  |   We create a new `app/crisis-center` folder and add `crisis-center.component.ts` to it with the following contents: | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'minus-imports', 'crisis-center/crisis-center.component.ts (minus imports)') | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   The `CrisisCenterComponent` parallels the `AppComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The `CrisisCenterComponent` is the root of the *Crisis Center* area | 
					
						
							|  |  |  |   just as `AppComponent` is the root of the entire application. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   This `CrisisCenterComponent` is a shell for crisis management | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   just as the `AppComponent` is a shell to manage the high-level workflow. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   `AppComponent` has a `@RouteConfig` decorator that defines the top-level routes. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   `CrisisCenterComponent` has a `@RouteConfig` decorator that defines *Crisis Center* child routes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The `CrisisCenterComponent` template is dead simple — simpler even than the `AppComponent` template. | 
					
						
							|  |  |  |   It has no content, no links, just a `<router-outlet>` for the *Crisis Center* child views. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   It has no selector either. It doesn't need one. We don't *embed* this component in a parent template. We *navigate* to it | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   from the outside, via a parent router (more on that soon). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### Service isolation | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   We add the `CrisisService` to the component's providers array | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   instead of registering it with the `bootstrap` function in `main.ts`. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'providers') | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   This step limits the scope of that service to the *Crisis Center* component and its sub-component tree. | 
					
						
							|  |  |  |   No component outside of the *Crisis Center* needs access to the `CrisisService`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   By restricting its scope, we feel confident that we can evolve it independently without fear of breaking | 
					
						
							|  |  |  |   unrelated application modules — modules that *shouldn't have access to it anyway*. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### Child Route Configuration | 
					
						
							|  |  |  |   The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   The `@RouteConfig` decorator that adorns the `CrisisCenterComponent` class defines routes in much the same way | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   that we did earlier. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'route-config', 'app/crisis-center/crisis-center.component.ts (routes only)' )(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   The two routes terminate in the two *Crisis Center* child components, `CrisisListComponent` and `CrisisDetailComponent`. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   There is an *important difference* in the treatment of the root `AppComponent` paths and these paths.  | 
					
						
							|  |  |  |   Normally paths that begin with `/` refer to the root of the application. | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   Here they refer to the **root of the child component!**. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The Component Router composes the final route by concatenating route paths beginning with the ancestor paths to this child router. | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   In our example, there is one ancestor path: "crisis-center". | 
					
						
							|  |  |  |   The final route to the `CrisisDetailComponent` displaying the crisis whose `id` is 2 would be something like: | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  | code-example(format=""). | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   localhost:3000/crisis-center/2 | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   We cannot know this simply by looking at the `CrisisCenterComponent` alone. | 
					
						
							|  |  |  |   We can't tell that it is a *child* routing component. | 
					
						
							|  |  |  |   We can't tell that its routes are child routes; they are indistinguiable from top level application routes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   Such ignorance is intentional. The *Crisis Center* shouldn't know that it is the child of anything. | 
					
						
							|  |  |  |   Today it is a child component one level down.  | 
					
						
							|  |  |  |   Tomorrow it might be the top level component of its own application.  | 
					
						
							|  |  |  |   Next month it might be re-purposed in a different application. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The *Crisis Center* itself is indifferent to these possibilities. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   *We* make it a child component of our application by reconfiguring the routes of the top level `AppComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ### Parent Route Configuration | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   Here is the revised route configuration for the parent `AppComponent`: | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | +makeExample('router/ts/app/app.component.ts', 'route-config', 'app/app.component.ts (routes only)' ) | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   The last two *Hero* routes haven't changed. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The first *Crisis Center* route has changed — *significantly* — and we've formatted it to draw attention to the differences: | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | +makeExample('router/ts/app/app.component.ts', 'route-config-cc')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Notice that the **path ends with a slash and three trailing periods (`/...`)**. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-17 15:02:15 -08:00
										 |  |  |   That means this is an incomplete route (a ***non-terminal route***).  The finished route will be some combination of | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   the parent `/crisis-center/` route and a route from the **child router** that belongs to the designated component. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   All is well. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The parent route's designated component is the `CrisisCenterComponent` which is a *Routing Component* with its own router and routes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   <a id="default"></a> | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   ### Default route | 
					
						
							|  |  |  |   The other important change is the addition of the `useAsDefault` property. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Its value is `true` which makes *this* route the *default* route. | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   When the application launches, in the absence of any routing information from the browser's URL, the router | 
					
						
							|  |  |  |   will default to the *Crisis Center*. That's our plan. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ### Routing to the Child | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We've set the top level default route to go to the `CrisisCenterComponent`. | 
					
						
							|  |  |  |   The final route will be a combination of `/crisis-center/`  | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   and one of the child `CrisisCenterComponent` router's two routes. Which one? | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   It could be either of them. In the absence of additional information, the router can't decide and must throw an error. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   We've tried the sample application and it didn't fail. We must have done something right. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   Look at the end of the child `CrisisCenterComponent`s first route. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/crisis-center/crisis-center.component.1.ts', 'default-route', 'app/crisis-center/crisis-center.component.ts (default route)')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   We see `useAsDefault: true` once again.  | 
					
						
							|  |  |  |   That tells the router to compose the final URL using the path from the default *child* route. | 
					
						
							|  |  |  |   Concatenate the base URL with the parent path, `/crisis-center/`, and the child path, `/`.  | 
					
						
							|  |  |  |   Remove superfluous slashes. We get: | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | code-example(format=""). | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   localhost:3000/crisis-center/ | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | .l-main-section | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   <a id="lifecycle-hooks"></a> | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   ## Router Lifecycle Hooks | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Angular components have [lifecycle hooks](lifecycle-hooks.html). For example, Angular calls the hook methods of the | 
					
						
							| 
									
										
										
										
											2016-03-16 21:42:55 -07:00
										 |  |  |   [OnInit](../api/core/OnInit-interface.html) and [OnDestroy](../api/core/OnDestroy-interface.html) | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   interfaces when it creates and destroys components. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   The router also has hooks for *its* lifecycle such as | 
					
						
							| 
									
										
										
										
											2016-03-18 19:16:46 -07:00
										 |  |  |   [CanActivate](../api/router/CanActivate-decorator.html), [OnActivate](../api/router/OnActivate-interface.html), and | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   [CanDeactivate](../api/router/CanDeactivate-interface.html). | 
					
						
							|  |  |  |   These three hooks can change the way the router navigates *to* a component or *away* from a component. | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   The router lifecycle hooks *supplement* the component lifecycle hooks. | 
					
						
							|  |  |  |   We still need the component hooks but the router hooks do what the component hooks cannot. | 
					
						
							|  |  |  |   For example, the component hooks can't stop component creation or destruction. | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   They can't pause view navigation to wait for an asynchronous process to finish because they are synchronous. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   A *router* hook can permit or prevent a navigation.  | 
					
						
							|  |  |  |   If the hook returns `true`, the navigation proceeds; if it returns `false`, the | 
					
						
							|  |  |  |   router cancels the navigation and stays on the current view. | 
					
						
							|  |  |  |   A hook can also tell the router to navigate to a *different* component. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   Router hook methods can act synchronously by returning a boolean value directly or | 
					
						
							|  |  |  |   act asynchronously by returning a promise that resolves to a boolean. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   Let's look at `CanDeactivate`, one of the most important router hooks. | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     We'll examine other router hooks in a future update to this chapter. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### *CanDeactivate*: handling unsaved changes | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   Back in the "Heroes" workflow, the app accepts every change to a hero immediately without hesitation or validation. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   In the real world, we might have to accumulate the users changes. | 
					
						
							|  |  |  |   We might have to validate across fields. We might have to validate on the server. | 
					
						
							|  |  |  |   We might have to hold changes in a pending state until the user confirms them *as a group* or | 
					
						
							|  |  |  |   cancels and reverts all changes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |   What do we do about unapproved, unsaved changes when the user navigates away? | 
					
						
							|  |  |  |   We can't just leave and risk losing the user's changes; that would be a terrible experience. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   We'd like to pause and let the user decide what to do.  | 
					
						
							|  |  |  |   If the user cancels, we'll stay put and allow more changes. | 
					
						
							|  |  |  |   If the user approves, the app can save.  | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   We still might delay navigation until the save succeeds. | 
					
						
							|  |  |  |   If we let the user move to the next screen immediately and  | 
					
						
							|  |  |  |   the save failed (perhaps the data are ruled invalid), we would have lost the context of the error. | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   We can't block while waiting for the server — that's not possible in a browser. | 
					
						
							|  |  |  |   We need to stop the navigation while we wait, asynchronously, for the server | 
					
						
							|  |  |  |   to return with its answer. | 
					
						
							| 
									
										
										
										
											2016-03-16 12:14:06 -07:00
										 |  |  |    | 
					
						
							|  |  |  |   We need the `CanDeactivate` hook. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### Cancel and Save | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Our sample application doesn't talk to a server.  | 
					
						
							|  |  |  |   Fortunately, we have another way to demonstrate an asynchronous router hook. | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Users update crisis information in the `CrisisDetailComponent`. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Unlike the `HeroDetailComponent`, the user changes do not update the | 
					
						
							|  |  |  |   crisis entity immediately. We update the entity when the user presses the *Save* button. | 
					
						
							|  |  |  |   We discard the changes if the user presses he *Cancel* button. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Both buttons navigate back to the crisis list after save or cancel. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'cancel-save', 'crisis-detail.component.ts (excerpt)')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   What if the user tries to navigate away without saving or canceling? | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   The user could push the browser back button or click the heroes link. | 
					
						
							|  |  |  |   Both actions trigger a navigation. | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Should the app save or cancel automatically? | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   We'll do neither. Instead we'll ask the user to make that choice explicitly | 
					
						
							|  |  |  |   in a confirmation dialog box that *waits asynchronously for the user's | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   answer*. | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |     We could wait for the user's answer with synchronous, blocking code. | 
					
						
							|  |  |  |     Our app will be more responsive ... and can do other work ... | 
					
						
							|  |  |  |     by waiting for the user's answer asynchronously. Waiting for the user asynchronously | 
					
						
							|  |  |  |     is like waiting for the server asynchronously. | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   The `DialogService` (injected in the `AppComponent` for app-wide use) does the asking. | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2016-03-25 02:33:56 -04:00
										 |  |  |   It returns a [promise](http://exploringjs.com/es6/ch_promises.html) that | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   *resolves* when the user eventually decides what to do: either | 
					
						
							|  |  |  |   to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`). | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  | <a id="CanDeactivate"></a> | 
					
						
							|  |  |  | <a id="routerCanDeactivate"></a> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   We execute the dialog inside the router's `routerCanDeactivate` lifecycle hook method. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'routerCanDeactivate', 'crisis-detail.component.ts (excerpt)') | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   Notice that the `routerCanDeactivate` method *can* return synchronously;  | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   it returns `true` immediately if there is no crisis or there are no pending changes. | 
					
						
							|  |  |  |   But it can also return a promise and the router will wait for that promise to resolve to truthy (navigate) or falsey (stay put). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   **Two critical points** | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |   1. The router hook is optional. We don't inherit from a base class. We simply implement the interface method or not. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   1. We rely on the router to call the hook. We don't worry about all the ways that the user | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   could navigate away. That's the router's job. | 
					
						
							|  |  |  |   We simply write this method and let the router take it from there. | 
					
						
							| 
									
										
										
										
											2015-12-31 16:55:53 -08:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   The relevant *Crisis Center* code for this milestone is | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  | +makeTabs( | 
					
						
							|  |  |  |    `router/ts/app/crisis-center/crisis-center.component.ts, | 
					
						
							|  |  |  |    router/ts/app/crisis-center/crisis-list.component.1.ts, | 
					
						
							|  |  |  |    router/ts/app/crisis-center/crisis-detail.component.1.ts, | 
					
						
							|  |  |  |    router/ts/app/crisis-center/crisis.service.ts | 
					
						
							|  |  |  |   `, | 
					
						
							|  |  |  |   null, | 
					
						
							|  |  |  |    `crisis-center.component.ts, | 
					
						
							|  |  |  |    crisis-list.component.ts, | 
					
						
							|  |  |  |    crisis-detail.component.ts, | 
					
						
							|  |  |  |    crisis.service.ts, | 
					
						
							|  |  |  |   `) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  | <a id="matrix-parameters"></a> | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  | <a id="query-parameter"></a> | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## Milestone #4: Query Parameters | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  |   We use [*route parameters*](#positional-parameters) to specify a *required* parameterized value *within* the route URL | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   as we do when navigating to the `HeroDetailComponent` in order to view-and-edit the hero with *id:15*. | 
					
						
							|  |  |  | code-example(format="." language="bash"). | 
					
						
							|  |  |  |   localhost:3000/hero/15 | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   Sometimes we wish to add *optional* information to a route request.  | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   For example, the `HeroListComponent` doesn't need help to display a list of heroes.  | 
					
						
							|  |  |  |   But it might be nice if the previously-viewed hero were pre-selected when returning from the `HeroDetailComponent`. | 
					
						
							|  |  |  | figure.image-display | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero") | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   That becomes possible if we can include hero Magneta's `id` in the URL when we | 
					
						
							|  |  |  |   return from the `HeroDetailComponent`, a scenario we'll pursue in a moment.  | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   Optional information takes other forms. Search criteria are often loosely structured, e.g., `name='wind*'`. | 
					
						
							|  |  |  |   Multiple values are common — `after='12/31/2015' & before='1/1/2017'` — in no particular order — | 
					
						
							|  |  |  |    `before='1/1/2017' & after='12/31/2015'` — in a variety of formats — `during='currentYear'` . | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   These kinds of parameters don't fit easily in a URL *path*. Even if we could define a suitable URL token scheme,  | 
					
						
							|  |  |  |   doing so greatly complicates the pattern matching required to translate an incoming URL to a named route. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The **URL query string** is the ideal vehicle for conveying arbitrarily complex information during navigation.  | 
					
						
							|  |  |  |   The query string isn't involved in pattern matching and affords enormous flexiblity of expression. | 
					
						
							|  |  |  |   Almost anything serializable can appear in a query string. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The Component Router supports navigation with query strings as well as route parameters. | 
					
						
							|  |  |  |   We define query string parameters in the *route parameters object* just like we do with route parameters. | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |   <a id="route-or-query-parameter"></a> | 
					
						
							|  |  |  |   ### Route Parameters or Query Parameters? | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   There is no hard-and-fast rule. In general, | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   *prefer a route parameter when* | 
					
						
							|  |  |  |   * the value is required. | 
					
						
							|  |  |  |   * the value is necessary to distinguish one route path from another. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   *prefer a query parameter when*  | 
					
						
							|  |  |  |   * the value is optional. | 
					
						
							|  |  |  |   * the value is complex and/or multi-variate.   | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2016-05-03 12:19:50 -06:00
										 |  |  |   <a id="positional-parameters-object"></a> | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   ### Route parameters object | 
					
						
							|  |  |  |   When navigating to the `HeroDetailComponent` we specified the `id` of the hero-to-edit in the  | 
					
						
							| 
									
										
										
										
											2016-01-24 16:04:42 +00:00
										 |  |  |   *route parameters object* and made it the second item of the [*link parameters array*](#link-parameters-array).  | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   The router embedded the `id` value in the navigation URL because we had defined it | 
					
						
							|  |  |  |   as a route parameter with an  `:id` placeholder token in the route `path`: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.2.ts','hero-detail-route')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array* | 
					
						
							|  |  |  |   which it uses to navigate back to the `HeroListComponent`. | 
					
						
							|  |  |  | +makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   This array lacks a route parameters object because we had no reason to send information to the `HeroListComponent`. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   Now we have a reason. We'd like to send the id of the current hero with the navigation request so that the | 
					
						
							|  |  |  |   `HeroListComponent` can highlight that hero in its list. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   We do that with a route parameters object in the same manner as before.  | 
					
						
							|  |  |  |   We also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore. | 
					
						
							|  |  |  |   Here's the revised navigation statement: | 
					
						
							|  |  |  | +makeExample('router/ts/app/heroes/hero-detail.component.ts','gotoHeroes-navigate')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   The application still works. Clicking "back" returns to the hero list view.  | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   Look at the browser address bar. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | .l-sub-section | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px") | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |     When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner. | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |  It should look something like this, depending on where you run it: | 
					
						
							|  |  |  | code-example(format="." language="bash"). | 
					
						
							|  |  |  |   localhost:3000/heroes?id=15&foo=foo | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   The `id` value appears in the query string (`?id=15&foo=foo`), not in the URL path. | 
					
						
							|  |  |  |   The path for the "Heroes" route doesn't have an `:id` token. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .alert.is-helpful | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     The router replaces route path tokens with corresponding values from the route parameters object. | 
					
						
							|  |  |  |     **Every parameter _not_ consumed by a route path goes in the query string.** | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Query parameters in the *RouteParams* service | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The list of heroes is unchanged. No hero row is highlighted.  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     The [live example](/resources/live-examples/router/ts/plnkr.html) *does* highlight the selected | 
					
						
							|  |  |  |     row because it demonstrates the final state of the application which includes the steps we're *about* to cover. | 
					
						
							|  |  |  |     At the moment we're describing the state of affairs *prior* to those steps. | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   The `HeroListComponent` isn't expecting any parameters at all and wouldn't know what to do with them. | 
					
						
							|  |  |  |   Let's change that. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   When navigating from the `HeroListComponent` to the `HeroDetailComponent`  | 
					
						
							|  |  |  |   the router picked up the route parameter object and made it available to the `HeroDetailComponent` | 
					
						
							|  |  |  |   in the `RouteParams` service. We injected that service in the constructor of the `HeroDetailComponent`. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`. | 
					
						
							|  |  |  |   This time we'll inject the `RouteParams` service in the constructor of the `HeroListComponent`. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   First we extend the router import statement to include the `RouteParams` service symbol; | 
					
						
							|  |  |  | +makeExample('router/ts/app/heroes/hero-list.component.ts','import-route-params', 'hero-list.component.ts (import)')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-05-03 14:06:32 +02:00
										 |  |  |   Then we extend the constructor to inject the `RouteParams` service and extract the `id` parameter as the `selectedId`: | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.ts','ctor', 'hero-list.component.ts (constructor)')(format=".") | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     All route parameters are strings.  | 
					
						
							|  |  |  |     The (+) in front of the `routeParameters.get` expression is a JavaScript trick to convert the string to an integer. | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   We add an `isSelected` method that returns true when a hero's id matches the selected id. | 
					
						
							|  |  |  | +makeExample('router/ts/app/heroes/hero-list.component.ts','isSelected', 'hero-list.component.ts (constructor)')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-27 13:48:24 -08:00
										 |  |  |   Finally, we update our template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method.  | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   The binding adds the `selected` CSS class when the method returns `true` and removes it when `false`. | 
					
						
							|  |  |  |   Look for it within the repeated `<li>` tag as shown here: | 
					
						
							|  |  |  | +makeExample('router/ts/app/heroes/hero-list.component.ts','template', 'hero-list.component.ts (template)')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected: | 
					
						
							|  |  |  | figure.image-display | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected List" ) | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   The `foo` query string parameter is harmless and continues to be ignored. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   ### Child Routers and Query Parameters | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   We can define query parameters for child routers too. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The technique is precisely the same.  | 
					
						
							|  |  |  |   In fact, we made exactly the same changes to the *Crisis Center* feature. | 
					
						
							|  |  |  |   Confirm the similarities in these *Hero* and *CrisisCenter* components, | 
					
						
							|  |  |  |   arranged side-by-side for easy comparison: | 
					
						
							|  |  |  | +makeTabs( | 
					
						
							|  |  |  |     `router/ts/app/heroes/hero-list.component.ts, | 
					
						
							|  |  |  |     router/ts/app/crisis-center/crisis-list.component.ts, | 
					
						
							|  |  |  |     router/ts/app/heroes/hero-detail.component.ts, | 
					
						
							|  |  |  |     router/ts/app/crisis-center/crisis-detail.component.ts | 
					
						
							|  |  |  |     `, | 
					
						
							|  |  |  |     null, | 
					
						
							|  |  |  |     `hero-list.component.ts, | 
					
						
							|  |  |  |     crisis-list.component.ts, | 
					
						
							|  |  |  |     hero-detail.component.ts, | 
					
						
							|  |  |  |     crisis-detail.component.ts | 
					
						
							|  |  |  |     `) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   When we navigate back from a `CrisisDetailComponent` that is showing the *Asteroid* crisis, | 
					
						
							|  |  |  |   we see that crisis properly selected in the list like this: | 
					
						
							|  |  |  | figure.image-display | 
					
						
							|  |  |  |   img(src='/resources/images/devguide/router/selected-crisis.png' alt="Selected crisis" ) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   **Look at the browser address bar again**. It's *different*. It looks something like this: | 
					
						
							|  |  |  | code-example(format="." language="bash"). | 
					
						
							|  |  |  |   localhost:3000/crisis-center/;id=3;foo=foo | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   The query string parameters are no longer separated by "?" and "&". | 
					
						
							|  |  |  |   They are **separated by semicolons (;)**  | 
					
						
							|  |  |  |   This is *matrix URL* notation — something we may not have seen before. | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     *Matrix URL* notation is an idea first floated | 
					
						
							|  |  |  |     in a [1996 proposal](http://www.w3.org/DesignIssues/MatrixURIs.html) by the founder of the web, Tim Berners-Lee. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     Although matrix notation never made it into the HTML standard, it is legal and | 
					
						
							|  |  |  |     it became popular among browser routing systems as a way to isolate parameters | 
					
						
							|  |  |  |     belonging to parent and child routes. The Angular Component Router is such a system. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     The syntax may seem strange to us but users are unlikely to notice or care | 
					
						
							|  |  |  |     as long as the URL can be emailed and pasted into a browser address bar | 
					
						
							|  |  |  |     as this one can. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | <a id="final-app"></a> | 
					
						
							|  |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   ## Wrap Up | 
					
						
							| 
									
										
										
										
											2015-12-19 14:16:27 -08:00
										 |  |  |   As we end our chapter, we take a parting look at | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   the entire application. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-22 15:22:14 +00:00
										 |  |  |   We can always try the [live example](/resources/live-examples/router/ts/plnkr.html) and download the source code from there. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Our final project folder structure looks like this: | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  | .filetree | 
					
						
							|  |  |  |   .file router-sample | 
					
						
							|  |  |  |   .children | 
					
						
							|  |  |  |     .file app | 
					
						
							|  |  |  |     .children | 
					
						
							|  |  |  |       .file crisis-center/... | 
					
						
							|  |  |  |       .file heroes/... | 
					
						
							|  |  |  |       .file app.component.ts | 
					
						
							|  |  |  |       .file dialog.service.ts | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |       .file main.ts       | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |     .file node_modules ... | 
					
						
							|  |  |  |     .file typings ... | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  |     .file index.html | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |     .file package.json | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  |     .file styles.css | 
					
						
							|  |  |  |     .file tsconfig.json | 
					
						
							| 
									
										
										
										
											2016-02-11 15:08:06 -08:00
										 |  |  |     .file typings.json | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   The pertinent top level application files are | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | +makeTabs( | 
					
						
							|  |  |  |   `router/ts/app/app.component.ts, | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |    router/ts/app/main.ts, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |    router/ts/app/dialog.service.ts, | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |    router/ts/index.html | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   `, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   null, | 
					
						
							|  |  |  |   `app.component.ts, | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  |    main.ts, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |    dialog.service.ts, | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |    index.html | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   `) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   <a id="crisis-center-structure-and-code"></id> | 
					
						
							|  |  |  |   ### Crisis Center | 
					
						
							|  |  |  |   The *Crisis Center* feature area within the `crisis-center` folder follows: | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  | .filetree | 
					
						
							|  |  |  |   .file app | 
					
						
							|  |  |  |   .children | 
					
						
							|  |  |  |     .file crisis-center | 
					
						
							|  |  |  |     .children | 
					
						
							|  |  |  |       .file crisis-center.component.ts | 
					
						
							|  |  |  |       .file crisis-detail.component.ts | 
					
						
							|  |  |  |       .file crisis-list.component.ts | 
					
						
							|  |  |  |       .file crisis.service.ts | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  | +makeTabs( | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |    `router/ts/app/crisis-center/crisis-center.component.ts, | 
					
						
							|  |  |  |    router/ts/app/crisis-center/crisis-list.component.ts, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |    router/ts/app/crisis-center/crisis-detail.component.ts, | 
					
						
							|  |  |  |    router/ts/app/crisis-center/crisis.service.ts | 
					
						
							|  |  |  |   `, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   null, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |    `crisis-center.component.ts, | 
					
						
							|  |  |  |    crisis-list.component.ts, | 
					
						
							|  |  |  |    crisis-detail.component.ts, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |    crisis.service.ts, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   `) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Heroes | 
					
						
							|  |  |  |   The *Heroes* feature area within the `heroes` folder is next: | 
					
						
							| 
									
										
										
										
											2015-12-15 11:23:25 -08:00
										 |  |  | .filetree | 
					
						
							|  |  |  |   .file app | 
					
						
							|  |  |  |   .children | 
					
						
							|  |  |  |     .file heroes | 
					
						
							|  |  |  |     .children | 
					
						
							|  |  |  |       .file hero-detail.component.ts | 
					
						
							|  |  |  |       .file hero-list.component.ts | 
					
						
							|  |  |  |       .file hero.service.ts | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  | +makeTabs( | 
					
						
							|  |  |  |    `router/ts/app/heroes/hero-list.component.ts, | 
					
						
							|  |  |  |    router/ts/app/heroes/hero-detail.component.ts, | 
					
						
							|  |  |  |    router/ts/app/heroes/hero.service.ts | 
					
						
							|  |  |  |   `, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   null, | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |    `hero-list.component.ts, | 
					
						
							|  |  |  |    hero-detail.component.ts, | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |    hero.service.ts | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   `) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## Appendices | 
					
						
							|  |  |  |   The balance of this chapter is a set of appendices that | 
					
						
							|  |  |  |   elaborate some of the points we covered quickly above. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   The appendix material isn't essential. Continued reading is for the curious. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | .l-main-section | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | <a id="link-parameters-array"></a> | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   ## Link Parameters Array | 
					
						
							|  |  |  |   We've mentioned the *Link Parameters Array* several times. We've used it several times. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   We've bound the `RouterLink` directive to such an array like this: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.3.ts', 'h-anchor')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   We've written a two element array when specifying a route parameter like this | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | +makeExample('router/ts/app/heroes/hero-list.component.1.ts', 'nav-to-detail')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | :marked | 
					
						
							|  |  |  |   These two examples cover our needs for an app with one level routing. | 
					
						
							|  |  |  |   The moment we add a child router, such as the *Crisis Center*, we create new link array possibilities. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   Recall that we specified a default child route for *Crisis Center* so this simple `RouterLink` is fine. | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | +makeExample('router/ts/app/app.component.3.ts', 'cc-anchor-w-default')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   *If we had not specified a default route*, our single item array would fail | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   because we didn't tell the router which child route to use. | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.3.ts', 'cc-anchor-fail')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   We'd need to write our anchor with a link array like this: | 
					
						
							|  |  |  | +makeExample('router/ts/app/app.component.3.ts', 'cc-anchor-no-default')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   Let's parse it out. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   * The first item in the array identifies the parent route ('CrisisCenter'). | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   * There are no parameters for this parent route so we're done with it. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   * There is no default for the child route so we need to pick one. | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   * We decide to go to the `CrisisListComponent` whose route name is 'CrisisList' | 
					
						
							|  |  |  |   * So we add that 'CrisisList' as the second item in the array. | 
					
						
							|  |  |  |   * Voila! `['CrisisCenter', 'CrisisList']`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   Let's take it a step further. | 
					
						
							|  |  |  |   This time we'll build a link parameters array that navigates from the root of the application | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   down to the "Dragon Crisis". | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   * The first item in the array identifies the parent route ('CrisisCenter'). | 
					
						
							|  |  |  |   * There are no parameters for this parent route so we're done with it. | 
					
						
							|  |  |  |   * The second item identifies the child route for details about a particular crisis ('CrisisDetail'). | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   * The details child route requires an `id` route parameter | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  |   * We add `id` of the *Dragon Crisis* as the third item in the array (`{id:1}`) | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   It looks like this! | 
					
						
							| 
									
										
										
										
											2016-02-28 17:59:57 -08:00
										 |  |  | +makeExample('router/ts/app/app.component.3.ts', 'Dragon-anchor')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   If we wanted to, we could redefine our `AppComponent` template with *Crisis Center* routes exclusively: | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  | +makeExample('router/ts/app/app.component.3.ts', 'template')(format=".") | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-02-16 09:18:46 -08:00
										 |  |  |   In sum, we can write applications with one, two or more levels of routing. | 
					
						
							| 
									
										
										
										
											2016-01-04 09:40:38 -08:00
										 |  |  |   The link parameters array affords the flexibility to represent any routing depth and | 
					
						
							| 
									
										
										
										
											2015-12-14 18:19:17 -08:00
										 |  |  |   any legal sequence of route names and (optional) route parameter objects. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | <a id="onInit"></a> | 
					
						
							|  |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ## Appendix: Why use an *ngOnInit* method | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   We implemented an `ngOnInit` method in many of our Component classes. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We did so, for example, in the [HeroDetailComponent](#hero-detail-ctor). | 
					
						
							|  |  |  |   We might have put the `ngOnInit` logic inside the constructor instead. We didn't for a reason. The reason is *testability*. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   A constructor that has major side-effects can be difficult to test because it starts doing things as soon as | 
					
						
							|  |  |  |   we create a test instance. In this case, it might have made a request to a remote server, something it shouldn't | 
					
						
							|  |  |  |   do under test. It may even be impossible to reach the server in the test environment. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The better practice is to limit what the constructor can do. Mostly it should stash parameters in | 
					
						
							|  |  |  |   local variables and perform simple instance configuration. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Yet we want an instance of this class to get the hero data from the `HeroService` soon after it is created. | 
					
						
							|  |  |  |   How do we ensure that happens if not in the constructor? | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Angular detects when a component has certain lifecycle methods like | 
					
						
							| 
									
										
										
										
											2016-03-16 21:42:55 -07:00
										 |  |  |   [ngOnInit](../api/core/OnInit-interface.html) and | 
					
						
							|  |  |  |   [ngOnDestroy](../api/core/OnDestroy-interface.html) and calls | 
					
						
							| 
									
										
										
										
											2016-03-16 20:04:42 -07:00
										 |  |  |   them | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   at the appropriate moment. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Angular will call `ngOnInit` when we navigate to the `HeroDetailComponent`, we'll get the `id` from the `RouteParams` | 
					
						
							|  |  |  |   and ask the server for the hero with that `id`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   We too can call that `ngOnInit` method in our tests if we wish ... after taking control of the injected | 
					
						
							|  |  |  |   `HeroService` and (perhaps) mocking it. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <a name="browser-url-styles"></a> | 
					
						
							| 
									
										
										
										
											2016-03-26 12:18:13 -04:00
										 |  |  | <a id="location-strategy"></a> | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | .l-main-section | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-03-26 12:18:13 -04:00
										 |  |  |   ## Appendix: *LocationStrategy* and browser URL styles | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   When the router navigates to a new component view, it updates the browser's location and history | 
					
						
							|  |  |  |   with a URL for that view. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   This is a strictly local URL. The browser shouldn't send this URL to the server | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   and should not reload the page. | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Modern HTML 5 browsers support | 
					
						
							|  |  |  |   [history.pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries), | 
					
						
							|  |  |  |   a technique that changes a browser's location and history without triggering a server page request. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   The router can compose a "natural" URL that is indistinguishable from | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   one that would otherwise require a page load. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Here's the *Crisis Center* URL in this "HTML 5 pushState" style: | 
					
						
							|  |  |  | code-example(format=".", language="bash"). | 
					
						
							|  |  |  |   localhost:3002/crisis-center/ | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Older browsers send page requests to the server when the location URL changes ... | 
					
						
							|  |  |  |   unless the change occurs after a "#" (called the "hash"). | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   Routers can take advantage of this exception by composing in-application route | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   URLs with hashes.  Here's a "hash URL" that routes to the *Crisis Center* | 
					
						
							|  |  |  | code-example(format=".", language="bash"). | 
					
						
							|  |  |  |   localhost:3002/src/#/crisis-center/ | 
					
						
							|  |  |  | :marked | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   The Angular Component Router supports both styles with two `LocationStrategy` providers: | 
					
						
							|  |  |  |   1. `PathLocationStrategy` - the default "HTML 5 pushState" style. | 
					
						
							|  |  |  |   1. `HashLocationStrategy` - the "hash URL" style. | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |   The router's `ROUTER_PROVIDERS` array sets the `LocationStrategy` to the `PathLocationStrategy`, | 
					
						
							|  |  |  |   making it the default strategy.  | 
					
						
							|  |  |  |   We can switch to the `HashLocationStrategy` with an override during the bootstrapping process if we prefer it. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							|  |  |  |     Learn about "providers" and the bootstrap process in the | 
					
						
							|  |  |  |     [Dependency Injection chapter](dependency-injection#bootstrap) | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### Which Strategy is Best? | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   We must choose a strategy and we need to make the right call early in the project. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   It won't be easy to change later once the application is in production | 
					
						
							|  |  |  |   and there are lots of application URL references in the wild. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Almost all Angular 2 projects should use the default HTML 5 style. | 
					
						
							|  |  |  |   It produces URLs that are easier for users to understand. | 
					
						
							|  |  |  |   And it preserves the option to do **server-side rendering** later. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Rendering critical pages on the server is a technique that can greatly improve | 
					
						
							|  |  |  |   perceived responsiveness when the app first loads. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   An app that would otherwise take ten or more seconds to start | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   could be rendered on the server and delivered to the user's device | 
					
						
							|  |  |  |   in less than a second. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   This option is only available if application URLs look like normal web URLs | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   without hashes (#) in the middle. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Stick with the default unless you have a compelling reason to | 
					
						
							|  |  |  |   resort to hash routes. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   ### HTML 5 URLs and the  *<base href>* | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   While the router uses the "[HTML 5 pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries)" | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   style by default, we *must* configure that strategy with a **base href** | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   The preferred way to configure the strategy is to add a | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   [<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   in the `<head>` of the `index.html`. | 
					
						
							| 
									
										
										
										
											2016-05-02 16:53:25 -07:00
										 |  |  | +makeExample('router/ts/index.1.html','base-href')(format=".") | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | :marked | 
					
						
							| 
									
										
										
										
											2016-01-05 16:41:47 +01:00
										 |  |  |   Without that tag, the browser may not be able to load resources | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   (images, css, scripts) when "deep linking" into the app. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  |   Bad things could happen when someone pastes an application link into the | 
					
						
							|  |  |  |   browser's address bar or clicks such a link in an email link. | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Some developers may not be able to add the `<base>` element, perhaps because they don't have | 
					
						
							|  |  |  |   access to `<head>` or the `index.html`. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   Those developers may still use HTML 5 URLs by taking two remedial steps: | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |   1. Provide the router with an appropriate `APP_BASE_HREF` value. | 
					
						
							|  |  |  |   1. Use **absolute URLs** for all web resources: css, images, scripts, and template html files. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .l-sub-section | 
					
						
							|  |  |  |   :marked | 
					
						
							| 
									
										
										
										
											2016-03-16 21:42:55 -07:00
										 |  |  |     Learn about the [APP_BASE_HREF](../api/router/APP_BASE_HREF-let.html) | 
					
						
							| 
									
										
										
										
											2015-12-10 09:40:54 -08:00
										 |  |  |     in the API Guide. | 
					
						
							|  |  |  | :marked | 
					
						
							|  |  |  |   ### *HashLocationStrategy* | 
					
						
							|  |  |  |   We can go old-school with the `HashLocationStrategy` by | 
					
						
							|  |  |  |   providing it as the router's `LocationStrategy` during application bootstrapping. | 
					
						
							| 
									
										
										
										
											2015-12-17 13:49:33 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 20:04:22 -08:00
										 |  |  |   First, import the `provide` symbol for Dependency Injection and the | 
					
						
							|  |  |  |   `Location` and `HashLocationStrategy` symbols from the router. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   Then *override* the default strategy defined in `ROUTE_PROVIDERS` by | 
					
						
							|  |  |  |   providing the `HashLocationStrategy` later in the `bootstrap` providers array argument: | 
					
						
							| 
									
										
										
										
											2016-01-28 16:15:26 -08:00
										 |  |  | +makeExample('router/ts/app/main.2.ts','', 'main.ts (hash URL strategy)') |