2446 lines
		
	
	
		
			113 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			2446 lines
		
	
	
		
			113 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| include ../_util-fns
 | |
| 
 | |
| :marked
 | |
|   The Angular ***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 <live-example>run live</live-example>.
 | |
| .l-sub-section
 | |
|   img(src='/resources/images/devguide/plunker-separate-window-button.png' alt="pop out the window" align="right" style="margin-right:-20px")
 | |
|   :marked
 | |
|     To see the URL changes in the browser address bar,
 | |
|     pop out the preview window by clicking the blue 'X' button in the upper right corner.
 | |
| 
 | |
| .l-main-section
 | |
| :marked
 | |
|   ## Overview
 | |
| 
 | |
|   The browser is a familiar model of application navigation.
 | |
|   We enter a URL in the address bar and the browser navigates to a corresponding page.
 | |
|   We click links on the page and the browser navigates to a new page.
 | |
|   We click the browser's back and forward buttons and the browser navigates
 | |
|   backward and forward through the history of pages we've seen.
 | |
| 
 | |
|   The Angular ***Router*** ("the router") borrows from this model.
 | |
|   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
 | |
|   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.
 | |
|   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.
 | |
| 
 | |
|   We'll learn many router details in this chapter which covers
 | |
| 
 | |
|   * Setting the [base href](#base-href)
 | |
|   * Importing from the [router library](#import)
 | |
|   * [configuring the router](#route-config)
 | |
|   * the [link parameters array](#link-parameters-array) that propels router navigation
 | |
|   * navigating when the user clicks a data-bound [RouterLink](#router-link)
 | |
|   * navigating under [program control](#navigate)
 | |
|   * retrieving information from the [route](#activated-route)
 | |
|   * [animating](#route-animation) transitions for route components
 | |
|   * navigating [relative](#relative-navigation) to our current URL
 | |
|   * toggling css classes for the [active router link](#router-link-active)
 | |
|   * embedding critical information in the URL with [route parameters](#route-parameters)
 | |
|   * providing non-critical information in [optional route parameters](#optional-route-parameters)
 | |
|   * refactoring routing into a [routing module](#routing-module)
 | |
|   * add [child routes](#child-routing-component) under a feature section
 | |
|   * [grouping child routes](#component-less-route) without a component
 | |
|   * [redirecting](#redirect) from one route to another
 | |
|   * confirming or canceling navigation with [guards](#guards)
 | |
|     * [CanActivate](#can-activate-guard) to prevent navigation to a route
 | |
|     * [CanActivateChild](#can-activate-child-guard) to prevent navigation to a child route
 | |
|     * [CanDeactivate](#can-deactivate-guard) to prevent navigation away from the current route
 | |
|     * [Resolve](#resolve-guard) to pre-fetch data before activating a route
 | |
|     * [CanLoad](#can-load-guard) to prevent asynchronous routing
 | |
|   * providing optional information across routes with [query parameters](#query-parameters)
 | |
|   * jumping to anchor elements using a [fragment](#fragment)
 | |
|   * loading feature areas [asynchronously](#asynchronous-routing)
 | |
|   * pre-loading feature areas [during navigation](#preloading)
 | |
|   * using a [custom strategy](#custom-preloading) to only pre-load certain features
 | |
|   * choosing the "HTML5" or "hash" [URL style](#browser-url-styles)
 | |
| 
 | |
|   We proceed in phases marked by milestones building from a simple two-pager with placeholder views
 | |
|   up to a modular, multi-view design with child routes.
 | |
| 
 | |
|   But first, an overview of router basics.
 | |
| 
 | |
| .l-main-section
 | |
| :marked
 | |
|   ## The Basics
 | |
|   Let's begin with a few core concepts of the Router.
 | |
|   Then we can explore the details through a sequence of examples.
 | |
| 
 | |
| :marked
 | |
|   ### *<base href>*
 | |
|   Most routing applications should add a `<base>` element to the **`index.html`** as the first child in the  `<head>` tag
 | |
|   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.
 | |
| 
 | |
| +makeExcerpt('index.1.html', 'base-href')
 | |
| 
 | |
| :marked
 | |
|   ### Router imports
 | |
|   The Angular Router is an optional service that presents a particular component view for a given URL.
 | |
|   It is not part of the Angular 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.
 | |
| 
 | |
| +makeExcerpt('app/app.module.1.ts (import)', 'import-router')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     We cover other options in the [details below](#browser-url-styles).
 | |
| :marked
 | |
|   ### Configuration
 | |
|   The application will have one *`router`*. When the browser's URL changes, the router looks for a corresponding **`Route`**
 | |
|   from which it can determine the component to display.
 | |
| 
 | |
|   A router has no routes until we configure it.
 | |
|   We bootstrap our application with an array of routes that we'll provide to our **`RouterModule.forRoot`** function.
 | |
| 
 | |
|   In the following example, we configure our application with four route definitions. The configured `RouterModule` is
 | |
|   add to the `AppModule`'s `imports` array.
 | |
| 
 | |
| +makeExcerpt('app/app.module.0.ts (excerpt)', 'route-config')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The `RouterModule` is provided an array of *routes* that describe how to navigate.
 | |
|     Each *Route* maps a URL `path` to a component.
 | |
| 
 | |
|     There are no **leading slashes** in our **path**. The router parses and builds the URL for us,
 | |
|     allowing us to use relative and absolute paths when navigating between application views.
 | |
| 
 | |
|     The `:id` in the first 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`
 | |
|     will use that value to find and present the hero whose `id` is 42.
 | |
|     We'll learn more about route parameters later in this chapter.
 | |
| 
 | |
|     The `data` property in the third route is a place to store arbitrary data associated with each
 | |
|     specific route. This data is accessible within each activated route and can be used to store
 | |
|     items such as page titles, breadcrumb text and other read-only data. We'll use the [resolve guard](#resolve-guard)
 | |
|     to retrieve additional data later in the chapter.
 | |
| 
 | |
|     The `empty path` in the fourth route matches as the default path for each level of routing. It
 | |
|     also allows for adding routes without extending the URL path.
 | |
| 
 | |
|     The `**` in the last route denotes a **wildcard** path for our route. The router will match this route
 | |
|     if the URL requested doesn't match any paths for routes defined in our configuration. This is useful for
 | |
|     displaying a 404 page or redirecting to another route.
 | |
| 
 | |
|     **The order of the routes in the configuration matters** and this is by design. The router uses a **first-match wins**
 | |
|     strategy when matching routes, so more specific routes should be placed above less specific routes. In our
 | |
|     configuration above, the routes with a static path are listed first, followed by an empty path route,
 | |
|     that matches as the default route. The wildcard route is listed last as it's the most generic route and should be
 | |
|     matched **only** if no other routes are matched first.
 | |
| 
 | |
| :marked
 | |
|   ### Router Outlet
 | |
|   Given this configuration, when the browser URL for this application becomes `/heroes`,
 | |
|   the router matches that URL to the `Route` path `/heroes` and displays the `HeroListComponent`
 | |
|   in a **`RouterOutlet`** that we've placed in the host view's HTML.
 | |
| code-example(language="html").
 | |
|   <!-- Routed views go here -->
 | |
|   <router-outlet></router-outlet>
 | |
| :marked
 | |
|   ### Router Links
 | |
|   Now we have routes configured and a place to render them, but
 | |
|   how do we navigate? The URL could arrive directly from the browser address bar.
 | |
|   But most of the time we navigate as a result of some user action such as the click of
 | |
|   an anchor tag.
 | |
| 
 | |
|   We add a **`RouterLink`** directive to the anchor tag. Since
 | |
|   we know our link doesn't contain any dynamic information, we can use a one-time binding to our route *path*.
 | |
| 
 | |
|   If our `RouterLink` needed to be more dynamic we could bind to a template expression that
 | |
|   returns an array of route link parameters (the **link parameters array**). The router ultimately resolves that array
 | |
|   into a URL and a component view.
 | |
| 
 | |
|   We also add a **`RouterLinkActive`** directive to each anchor tag to add or remove CSS classes to the
 | |
|   element when the associated *RouterLink* becomes active. The directive can be added directly on the element
 | |
|   or on its parent element.
 | |
| 
 | |
|   We see such bindings in the following `AppComponent` template:
 | |
| 
 | |
| +makeExcerpt('app/app.component.1.ts', 'template', '')
 | |
| 
 | |
| .l-sub-section
 | |
|  :marked
 | |
|    We're adding two anchor tags with `RouterLink` and `RouterLinkActive` directives.
 | |
|    We bind each `RouterLink` to a string containing the path of a route.
 | |
|    '/crisis-center' and '/heroes' are the paths of the `Routes` we configured above.
 | |
| 
 | |
|    We'll learn to write link expressions — and why they are arrays —
 | |
|    [later](#link-parameters-array) in the chapter.
 | |
| 
 | |
|    We define `active` as the CSS class we want toggled to each `RouterLink` when they become
 | |
|    the current route using the `RouterLinkActive ` directive. We could add multiple classes to
 | |
|    the `RouterLink` if we so desired.
 | |
| 
 | |
| :marked
 | |
|   ### Router State
 | |
|   After the end of each successful navigation lifecycle, the router builds a tree of `ActivatedRoute` objects
 | |
|   that make up the current state of the router. We can access the current `RouterState` from anywhere in our
 | |
|   application using the `Router` service and the `routerState` property.
 | |
| 
 | |
|   Each `ActivatedRoute` in the `RouterState` provides methods to traverse up and down the route tree
 | |
|   to get information we may need from parent, child and sibling routes.
 | |
| 
 | |
| :marked
 | |
|   ### Let's summarize
 | |
| 
 | |
|   The application is provided with a configured router.
 | |
|   The component has a `RouterOutlet` where it can display views produced by the router.
 | |
|   It has `RouterLink`s that users can click to navigate via the router.
 | |
| 
 | |
|   Here are the key *Router* terms and their meanings:
 | |
| table
 | |
|   tr
 | |
|     th Router Part
 | |
|     th Meaning
 | |
|   tr
 | |
|     td <code>Router</code>
 | |
|     td.
 | |
|       Displays the application component for the active URL.
 | |
|       Manages navigation from one component to the next.
 | |
|   tr
 | |
|     td <code>RouterModule</code>
 | |
|     td.
 | |
|       A separate Angular module that provides the necessary service providers
 | |
|       and directives for navigating through application views.
 | |
|   tr
 | |
|     td <code>Routes</code>
 | |
|     td.
 | |
|       Defines an array of Routes, each mapping a URL path to a component.
 | |
|   tr
 | |
|     td <code>Route</code>
 | |
|     td.
 | |
|       Defines how the router should navigate to a component based on a URL pattern.
 | |
|       Most routes consist of a path 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>string</i> or a <i>Link Parameters Array</i> triggers a navigation.
 | |
|   tr
 | |
|     td <code>RouterLinkActive</code>
 | |
|     td.
 | |
|       The directive for adding/removing classes from an HTML element when an associated
 | |
|       routerLink contained on or inside the element becomes active/inactive.
 | |
|   tr
 | |
|     td <code>ActivatedRoute</code>
 | |
|     td.
 | |
|       A service that is provided to each route component that contains route specific
 | |
|       information such as route parameters, static data, resolve data, global query params and the global fragment.
 | |
|   tr
 | |
|     td <code>RouterState</code>
 | |
|     td.
 | |
|       The current state of the router including a tree of the currently activated
 | |
|       routes in our application along convenience methods for traversing the route tree.
 | |
|   tr
 | |
|     td <code><i>Link Parameters Array</i></code>
 | |
|     td.
 | |
|       An array that the router interprets into a routing instruction.
 | |
|       We can bind a <code>RouterLink</code> to that array or pass the array as an argument to
 | |
|       the <code>Router.navigate</code> method.
 | |
|   tr
 | |
|     td <code><i>Routing Component</i></code>
 | |
|     td.
 | |
|       An Angular component with a <code>RouterOutlet</code> that displays views based on router navigations.
 | |
| :marked
 | |
|   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.
 | |
| 
 | |
| .l-main-section
 | |
| :marked
 | |
|   ## The Sample Application
 | |
|   We have an application in mind as we move from milestone to milestone.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     While we make incremental progress toward the ultimate sample application, this chapter is not a tutorial.
 | |
|     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></live-example>.
 | |
| 
 | |
| :marked
 | |
|   Our client is the Hero Employment Agency.
 | |
|   Heroes need work and The Agency finds Crises for them to solve.
 | |
| 
 | |
|   The application has three main feature areas:
 | |
|   1. A *Crisis Center* where we maintain the list of crises for assignment to heroes.
 | |
|   1. A *Heroes* area where we maintain the list of heroes employed by The Agency.
 | |
|   1. An *Admin* area where we manage the list of crises and heroes displayed.
 | |
| 
 | |
|   Run the <live-example></live-example>.
 | |
|   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
 | |
|   We select one and the application takes us to a hero editing screen.
 | |
| figure.image-display
 | |
|   img(src='/resources/images/devguide/router/hero-detail.png' alt="Crisis Center Detail" width="250")
 | |
| :marked
 | |
|   Our changes take effect immediately. We click the "Back" button and the
 | |
|   app returns us to the Heroes list.
 | |
| 
 | |
|   We could have clicked the browser's back button instead.
 | |
|   That would have returned us to the Heroes List as well.
 | |
|   Angular app navigation updates the browser history as normal web navigation does.
 | |
| 
 | |
|   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
 | |
|   We select one and the application takes us to a crisis editing screen.
 | |
| figure.image-display
 | |
|   img(src='/resources/images/devguide/router/crisis-center-detail.png' alt="Crisis Center Detail")
 | |
| :marked
 | |
|   This is a bit different from the *Hero Detail*. *Hero Detail* saves the changes as we type.
 | |
|   In *Crisis Detail* our changes are temporary until we either save or discard them by pressing the "Save" or "Cancel" buttons.
 | |
|   Both buttons navigate back to the *Crisis Center* and its list of crises.
 | |
| 
 | |
|   Suppose we click a crisis, make a change, but ***do not click either button***.
 | |
|   Maybe we click the browser back button instead. Maybe we click the "Heroes" link.
 | |
| 
 | |
|   Do either. Up pops a dialog box.
 | |
| 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.
 | |
| 
 | |
|   The router supports a `CanDeactivate` guard that gives us a chance to clean-up
 | |
|   or ask the user's permission before navigating away from the current view.
 | |
| 
 | |
|   Here we see an entire user session that touches all of these features.
 | |
| <a id="full-app-demo"></a>
 | |
| 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
 | |
| 
 | |
|   * organizing the application features into modules
 | |
|   * 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)
 | |
|   * the `CanActivate` guard (checking route access)
 | |
|   * the `CanActivateChild` guard (checking child route access)
 | |
|   * the `CanDeactivate` guard (ask permission to discard unsaved changes)
 | |
|   * the `Resolve` guard (pre-fetching route data)
 | |
|   * lazy loading feature modules
 | |
|   * the `CanLoad` guard (check before loading feature module assets)
 | |
| 
 | |
| <a id="getting-started"></a>
 | |
| .l-main-section
 | |
| :marked
 | |
|   ## Milestone #1: Getting Started with the Router
 | |
| 
 | |
|   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" )
 | |
| 
 | |
| a#base-href
 | |
| :marked
 | |
|   ### Set the *<base href>*
 | |
|   The Router uses the browser's
 | |
|   [history.pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries)
 | |
|   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.
 | |
| 
 | |
|   We must **add a [<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag**
 | |
|   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
 | |
|   css files, scripts, and images.
 | |
| 
 | |
|   Add the base element just after the  `<head>` tag.
 | |
|   If the `app` folder is the application root, as it is for our application,
 | |
|   set the `href` value in **`index.html`** *exactly* as shown here.
 | |
| 
 | |
| +makeExcerpt('index.1.html', 'base-href')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     HTML 5 style navigation is the Router default.
 | |
|     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.
 | |
| 
 | |
| :marked
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     #### Live example note
 | |
|     We have to get tricky when we run the live example because the host service sets
 | |
|     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.
 | |
| 
 | |
| :marked
 | |
|   ### Configure the routes for the Router
 | |
| 
 | |
|   We begin by importing some symbols from the router library.
 | |
| 
 | |
|   The Router is in its own `@angular/router` package.
 | |
|   It's not part of the Angular core. The router is an optional service because not all applications
 | |
|   need routing and, depending on your requirements, you may need a different routing library.
 | |
| 
 | |
|   We teach our router how to navigate by configuring it with routes.
 | |
| 
 | |
| a#route-config
 | |
| h4#define-routes Define routes
 | |
| :marked
 | |
|   A router must be configured with a list of route definitions.
 | |
| 
 | |
|   Our first configuration defines an array of two routes with simple paths leading to the
 | |
|   `CrisisListComponent` and `HeroListComponent` components.
 | |
| 
 | |
|   Each definition translates to a [Route](../api/router/index/Route-interface.html) object which has a
 | |
|   `path`, the URL path segment for this route, and a
 | |
|   `component`, the component associated with this route.
 | |
| 
 | |
|   The router draws upon its registry of such route definitions when the browser URL changes
 | |
|   or when our code tells the router to navigate along a route path.
 | |
| 
 | |
|   In plain English, we might say of the first route:
 | |
|   * *When the browser's location URL changes to match the path segment `/crisis-center`, create or retrieve an instance of
 | |
|   the `CrisisListComponent` and display its view.*
 | |
| 
 | |
|   * *When the application requests navigation to the path `/crisis-center`, create or retrieve an instance of
 | |
|   the `CrisisListComponent`, display its view, and update the browser's address location and history with the URL
 | |
|   for that path.*
 | |
| 
 | |
| :marked
 | |
|   Here is our first configuration. We pass the array of routes to the `RouterModule.forRoot` method
 | |
|   which returns a module containing the configured `Router` service provider ... and some other,
 | |
|   unseen providers that the routing library requires. Once our application is bootstrapped, the `Router`
 | |
|   will perform the initial navigation based on the current browser URL.
 | |
| 
 | |
| +makeExcerpt('app/app.module.1.ts')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Adding the configured `RouterModule` to the `AppModule` is sufficient for simple route configurations.
 | |
|     As our application grows, we'll want to refactor our routing configuration into a separate file
 | |
|     and create a **[Routing Module](#routing-module)**, a special type of `Service Module` dedicating for the purpose
 | |
|     of routing in feature modules.
 | |
| 
 | |
| :marked
 | |
|   Providing the `RouterModule` in our `AppModule` makes the Router available everywhere in our application.
 | |
| 
 | |
| h3#shell The <i>AppComponent</i> shell
 | |
| :marked
 | |
|   The root `AppComponent` is the application shell. It has a 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:
 | |
| figure.image-display
 | |
|   img(src='/resources/images/devguide/router/shell-and-outlet.png' alt="Shell" width="300" )
 | |
| 
 | |
| a#shell-template
 | |
| :marked
 | |
|   The corresponding component template looks like this:
 | |
| 
 | |
| +makeExcerpt('app/app.component.1.ts', 'template', '')
 | |
| 
 | |
| a#router-outlet
 | |
| :marked
 | |
|   ### *RouterOutlet*
 | |
| 
 | |
|   `RouterOutlet` is a component from the router library.
 | |
|   The router displays views within the bounds of the `<router-outlet>` tags.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     A template may hold exactly one ***unnamed*** `<router-outlet>`.
 | |
|     The router supports multiple *named* outlets, a feature we'll cover in future.
 | |
| 
 | |
| a#router-link
 | |
| :marked
 | |
|   ### *RouterLink* binding
 | |
| 
 | |
|   Above the outlet, within the anchor tags, we see [Property Bindings](template-syntax.html#property-binding) to
 | |
|   the `RouterLink` directive that look like `routerLink="..."`. We use the `RouterLink` from the router library.
 | |
| 
 | |
|   The links in this example each have a string path, the path of a route that
 | |
|   we configured earlier. We don't have route parameters yet.
 | |
| 
 | |
|   We can also add more contextual information to our `RouterLink` by providing query string parameters
 | |
|   or a URL fragment for jumping to different areas on our page. Query string parameters
 | |
|   are provided through the `[queryParams]` binding which takes an object (e.g. `{ name: 'value' }`), while the URL fragment
 | |
|   takes a single value bound to the `[fragment]` input binding.
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Learn about the how we can also use the **link parameters array** in the [appendix below](#link-parameters-array).
 | |
| 
 | |
| a#router-link-active
 | |
| h3#router-link <i>RouterLinkActive</i> binding
 | |
| :marked
 | |
|   On each anchor tag, we also see [Property Bindings](template-syntax.html#property-binding) to
 | |
|   the `RouterLinkActive` directive that look like `routerLinkActive="..."`.
 | |
| 
 | |
|   The template expression to the right of the equals (=) contains our space-delimited string of CSS classes.
 | |
|   We can also bind to the `RouterLinkActive` directive using an array of classes
 | |
|   such as `[routerLinkActive]="['...']"`.
 | |
| 
 | |
|   The `RouterLinkActive` directive toggles css classes for active `RouterLink`s based on the current `RouterState`.
 | |
|   This cascades down through each level in our route tree, so parent and child router links can be active at the same time.
 | |
|   To override this behavior, we can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression.
 | |
|   By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL.
 | |
| 
 | |
| h3#router-directives <i>Router Directives</i>
 | |
| :marked
 | |
|   `RouterLink`, `RouterLinkActive` and `RouterOutlet` are directives provided by the Angular `RouterModule` package.
 | |
|   They are readily available for us to use in our template.
 | |
| :marked
 | |
|   The current state of `app.component.ts` looks like this:
 | |
| 
 | |
| +makeExcerpt('app/app.component.1.ts')
 | |
| 
 | |
| :marked
 | |
|   ### "Getting Started" wrap-up
 | |
| 
 | |
|   We've got a very basic, navigating app, one that can switch between two views
 | |
|   when the user clicks a link.
 | |
| 
 | |
|   We've learned how to
 | |
|   * load the router library
 | |
|   * add a nav bar to the shell template with anchor tags, `routerLink`  and `routerLinkActive` directives
 | |
|   * add a `router-outlet` to the shell template where views will be displayed
 | |
|   * configure the router module with `RouterModule.forRoot`
 | |
|   * set the router to compose "HTML 5" browser URLs.
 | |
| 
 | |
|   The rest of the starter app is mundane, with little interest from a router perspective.
 | |
|   Here are the details for readers inclined to build the sample through to this milestone.
 | |
| 
 | |
|   Our starter app's structure looks like this:
 | |
| .filetree
 | |
|   .file router-sample
 | |
|   .children
 | |
|     .file app
 | |
|       .children
 | |
|         .file app.component.ts
 | |
|         .file app.module.ts
 | |
|         .file crisis-list.component.ts
 | |
|         .file hero-list.component.ts
 | |
|         .file main.ts
 | |
|     .file node_modules ...
 | |
|     .file index.html
 | |
|     .file package.json
 | |
|     .file styles.css
 | |
|     .file tsconfig.json
 | |
| :marked
 | |
|   Here are the files discussed in this milestone
 | |
| 
 | |
| +makeTabs(
 | |
|   `router/ts/app/app.component.1.ts,
 | |
|   router/ts/app/app.module.1.ts,
 | |
|   router/ts/app/main.ts,
 | |
|   router/ts/app/hero-list.component.ts,
 | |
|   router/ts/app/crisis-list.component.ts,
 | |
|   router/ts/index.html`,
 | |
|   ',,,,',
 | |
|   `app.component.ts,
 | |
|   app.module.ts,
 | |
|   main.ts,
 | |
|   hero-list.component.ts,
 | |
|   crisis-list.component.ts,
 | |
|   index.html`)
 | |
| 
 | |
| .l-main-section#routing-module
 | |
| :marked
 | |
|   ## Milestone #2: The *Routing Module*
 | |
| 
 | |
|   In our initial route configuration, we provided a simple setup with two routes used
 | |
|   to configure our application for routing. This is perfectly fine for simple routing.
 | |
|   As our application grows and we make use of more *Router* features, such as guards,
 | |
|   resolvers, and child routing, we'll naturally want to refactor our routing. We
 | |
|   recommend moving the routing into a separate file using a special-purpose
 | |
|   service called a *Routing Module*.
 | |
| 
 | |
|   The **Routing Module**
 | |
|   * separates our routing concerns from our feature module
 | |
|   * provides a module to replace or remove when testing our feature module
 | |
|   * provides a common place for require routing service providers including guards and resolvers
 | |
|   * is **not** concerned with feature [module declarations](../cookbook/ngmodule-faq.html#!#routing-module)
 | |
| 
 | |
| :marked
 | |
|   ### Refactor routing into a module
 | |
| 
 | |
|   We'll create a file named `app-routing.module.ts` in our `/app` folder to
 | |
|   contain our `Routing Module`. The routing module will import our `RouterModule` tokens
 | |
|   and configure our routes. We'll follow the convention of our filename and name
 | |
|   the Angular module `AppRoutingModule`.
 | |
| 
 | |
|   We import the `CrisisListComponent` and the `HeroListComponent` components
 | |
|   just like we did in the `app.module.ts`. Then we'll move the `Router` imports
 | |
|   and routing configuration including `RouterModule.forRoot` into our routing module.
 | |
| 
 | |
|   We'll also export the `AppRoutingModule` so we can add it to our `AppModule` imports.
 | |
| 
 | |
|   Our last step is to re-export the `RouterModule`. By re-exporting the `RouterModule`,
 | |
|   our feature module will be provided with the `Router Directives` when using our `Routing Module`.
 | |
| 
 | |
|   Here is our first `Routing Module`:
 | |
| 
 | |
| +makeExcerpt('app/app-routing.module.1.ts')
 | |
| 
 | |
| :marked
 | |
|    Next, we'll update our `app.module.ts` file by importing our `AppRoutingModule` token
 | |
|    from the `app-routing.module.ts` and replace our `RouterModule.forRoot` with our newly
 | |
|    created `AppRoutingModule`.
 | |
| 
 | |
| +makeExcerpt('app/app.module.2.ts')
 | |
| 
 | |
| :marked
 | |
|   Our application continues to work just the same, and we can use our routing module as
 | |
|   the central place to maintain our routing configuration for each feature module.
 | |
| 
 | |
| a#why-routing-module
 | |
| :marked
 | |
|   ### Do you need a _Routing Module_?
 | |
| 
 | |
|   The _Routing Module_ *replaces* the routing configuration in the root or feature module.
 | |
|   _Either_ configure routes in the Routing Module _or_ within the module itself but not in both.
 | |
| 
 | |
|   The Routing Module is a design choice whose value is most obvious when the configuration is complex
 | |
|   and includes specialized guard and resolver services.
 | |
|   It can seem like overkill when the actual configuration is dead simple.
 | |
| 
 | |
|   Some developers skip the Routing Module (e.g., `AppRoutingModule`) when the configuration is simple and
 | |
|   merge the routing configuration directly into the companion module (e.g., `AppModule`).
 | |
| 
 | |
|   We recommend that you choose one pattern or the other and follow that pattern consistently.
 | |
| 
 | |
|   Most developers should always implement a Routing Module for the sake of consistency.
 | |
|   It keeps the code clean when configuration becomes complex.
 | |
|   It makes testing the feature module easier.
 | |
|   Its existence calls attention to the fact that a module is routed.
 | |
|   It is where developers expect to find and expand routing configuration.
 | |
| 
 | |
| .l-main-section#heroes-feature
 | |
| :marked
 | |
|   ## Milestone #3: The Heroes Feature
 | |
| 
 | |
|   We've seen how to navigate using the `RouterLink` directive.
 | |
| 
 | |
|   Now we'll learn some new tricks such as how to
 | |
|   * organize our app and routes into *feature areas* using modules
 | |
|   * navigate imperatively from one component to another
 | |
|   * pass required and optional information in route parameters
 | |
| 
 | |
|   To demonstrate, we'll build out the *Heroes* feature.
 | |
| 
 | |
|   ### The Heroes "feature area"
 | |
| 
 | |
|   A typical application has multiple *feature areas*, each an island of functionality
 | |
|   with its own workflow(s), dedicated to a particular business purpose.
 | |
| 
 | |
|   We could continue to add files to the `app/` folder.
 | |
|   That's unrealistic and ultimately not maintainable.
 | |
|   We think it's better to put each feature area in its own folder.
 | |
| 
 | |
|   Our first step is to **create a separate `app/heroes/` folder**
 | |
|   and add *Hero Management* feature files there.
 | |
| 
 | |
|   We won't be creative about it. Our example is pretty much a
 | |
|   copy of the code and capabilities in the "[Tutorial: Tour of Heroes](../tutorial/index.html)".
 | |
| 
 | |
|   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
 | |
| 
 | |
|   We want to break our app out into different *feature modules* that we then import
 | |
|   into our main module so it can make use of them. First, we'll create a `heroes.module.ts`
 | |
|   in our heroes folder.
 | |
| 
 | |
|   We delete the placeholder `hero-list.component.ts` that's in
 | |
|   the `app/` folder.
 | |
| 
 | |
|   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.
 | |
|   We copy the `hero-detail.component.ts` and the `hero.service.ts` files
 | |
|   into the `heroes/` folder.
 | |
| 
 | |
|   We provide the `HeroService` in the `providers` array of our `Heroes` module
 | |
|   so its available to all components within our module.
 | |
| 
 | |
|   Our `Heroes` module is ready for routing.
 | |
| 
 | |
| +makeExcerpt('app/heroes/heroes.module.1.ts')
 | |
| 
 | |
| :marked
 | |
|   When we're done organizing, we have four *Hero Management* files:
 | |
| 
 | |
| .filetree
 | |
|   .file app/heroes
 | |
|   .children
 | |
|     .file hero-detail.component.ts
 | |
|     .file hero-list.component.ts
 | |
|     .file hero.service.ts
 | |
|     .file heroes.module.ts
 | |
| 
 | |
| :marked
 | |
|   Now it's time for some surgery to bring these files and the rest of the app
 | |
|   into alignment with our application router.
 | |
| 
 | |
|   ### *Hero* feature routing requirements
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   The detail view is different. It displays a particular hero. It can't know which hero on its own.
 | |
|   That information must come from outside.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   ### *Hero* feature route configuration
 | |
| 
 | |
|   We recommend giving each feature area its own route configuration file.
 | |
| 
 | |
|   Create a new `heroes-routing.module.ts` in the `heroes` folder like this:
 | |
| 
 | |
| +makeExcerpt('app/heroes/heroes-routing.module.ts')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Keep the Routing Module file in the same folder as its companion module file.
 | |
|     Here both `heroes-routing.module.ts` and `heroes.module.ts` are in the same `app/heroes` folder.
 | |
| 
 | |
| :marked
 | |
|   We use the same techniques we learned in creating the `app-routing.module.ts`.
 | |
| 
 | |
|   We import the two components from their new locations in the `app/heroes/` folder, define the two hero routes.
 | |
|   and add export our `HeroRoutingModule` that returns our `RoutingModule` for the hero feature module.
 | |
| 
 | |
| :marked
 | |
|   Now that we have routes for our `Heroes` module, we'll need to register them with the *Router*.
 | |
|   We'll import the *RouterModule* like we did in the `app-routing.module.ts`, but there is a slight difference here.
 | |
|   In our `app-routing.module.ts`, we used the static **forRoot** method to register our routes and application level
 | |
|   service providers. In a feature module we use static **forChild** method.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The **RouterModule.forRoot** should only be provided for the `AppModule`. Since we are in a feature
 | |
|     module, we'll use **RouterModule.forChild** method to only register additional routes.
 | |
| 
 | |
| :marked
 | |
|   We import our `HeroRoutingModule` token from `heroes-routing.module.ts` into our `Heroes` module and register the routing.
 | |
| 
 | |
| +makeExcerpt('app/heroes/heroes.module.ts (heroes routing)', 'heroes-routes')
 | |
| 
 | |
| :marked
 | |
|   ### Route definition with a parameter
 | |
|   The route to `HeroDetailComponent` has a twist.
 | |
| 
 | |
| +makeExcerpt('app/heroes/heroes-routing.module.ts (excerpt)', 'hero-detail-route')
 | |
| 
 | |
| :marked
 | |
|   Notice the `:id` token in the path. That creates a slot in the path for a **Route Parameter**.
 | |
|   In this case, we're expecting the router to insert the `id` of a hero into that slot.
 | |
| 
 | |
|   If we tell the router to navigate to the detail component and display "Magneta", we expect hero `id` (15) to appear in the
 | |
|   browser URL like this:
 | |
| code-example(format="." language="bash").
 | |
|   localhost:3000/hero/15
 | |
| :marked
 | |
|   If a user enters that URL into the browser address bar, the router should recognize the
 | |
|   pattern and go to the same "Magneta" detail view.
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     #### Route parameter: Required or optional?
 | |
|     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.
 | |
| 
 | |
|     An [optional-route-parameter](#optional-route-parameters) might be a better choice if we were passing an *optional* value to `HeroDetailComponent`.
 | |
| 
 | |
| a#navigate
 | |
| :marked
 | |
|   ### Navigate to hero detail imperatively
 | |
| 
 | |
|   *We won't navigate to the detail component by clicking a link*
 | |
|   so we won't be adding a new `RouterLink` anchor tag to the shell.
 | |
| 
 | |
|   Instead, when the user *clicks* a hero in the list, we'll *command* the router
 | |
|   to navigate to the hero detail view for the selected hero.
 | |
| 
 | |
|   We'll adjust the `HeroListComponent` to implement these tasks, beginning with its constructor
 | |
|   which acquires the router service and the `HeroService` by dependency injection:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.1.ts (constructor)', 'ctor')
 | |
| 
 | |
| :marked
 | |
|   We make a few changes to the template:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.1.ts', 'template', '')
 | |
| 
 | |
| :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:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.1.ts', 'select')
 | |
| 
 | |
| :marked
 | |
|   It calls the router's **`navigate`** method with a **Link Parameters Array**. We can use this same syntax
 | |
|   with a `RouterLink` if we want to use it in HTML rather than code.
 | |
| 
 | |
| h3#route-parameters Setting the route parameters in the list view
 | |
| :marked
 | |
|   We're navigating to the `HeroDetailComponent` where we expect to see the details of the selected hero.
 | |
|   We'll need *two* pieces of information: the destination and the hero's `id`.
 | |
| 
 | |
|   Accordingly, the *link parameters array* has *two* items:  the **path** of the destination route and a **route parameter** that specifies the
 | |
|   `id` of the selected hero.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array')
 | |
| 
 | |
| :marked
 | |
|   The router composes the appropriate two-part destination URL from this array:
 | |
| 
 | |
| code-example(language="bash").
 | |
|   localhost:3000/hero/15
 | |
| 
 | |
| a#get-route-parameter
 | |
| :marked
 | |
|   ### Getting the route parameter in the details view
 | |
| 
 | |
|   How does the target `HeroDetailComponent` learn about that `id`?
 | |
|   Certainly not by analyzing the URL!  That's the router's job.
 | |
| 
 | |
|   The router extracts the route parameter (`id:15`) from the URL and supplies it to
 | |
|   the `HeroDetailComponent` via the **ActivatedRoute** service.
 | |
| 
 | |
| <a id="activated-route"></a>
 | |
| h3#activated-route ActivatedRoute: the one-stop-shop for route information
 | |
| :marked
 | |
|   Each route contains information about its path, data parameters, URL segment and much more.
 | |
|   All of this information is available in an injected service provided by the router called the [ActivatedRoute](../api/router/index/ActivatedRoute-interface.html).
 | |
| 
 | |
|   The `ActivatedRoute` contains all the information you need from the current route component as well as ways to get information
 | |
|   about other activated routes in the `RouterState`.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     **`url`**: An `Observable` of the route path(s). The value is provided as an array of strings for each part of the route path.
 | |
| 
 | |
|     **`data`**: An `Observable` that contains the `data` object provided for the route. Also contains any resolved values from the [resolve guard](#resolve-guard).
 | |
| 
 | |
|     **`params`**: An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route.
 | |
| 
 | |
|     **`queryParams`**: An `Observable` that contains the [query parameters](#query-parameters) available to all routes.
 | |
| 
 | |
|     **`fragment`**:  An `Observable` of the URL [fragment](#fragment) available to all routes.
 | |
| 
 | |
|     **`outlet`**: The name of the `RouterOutlet` used to render the route. For an unnamed outlet, the outlet name is **primary**.
 | |
| 
 | |
|     **`routeConfig`**: The route configuration used for the route that contains the origin path.
 | |
| 
 | |
|     **`parent`**: an `ActivatedRoute` that contains the information from the parent route when using [child routes](#child-routing-component).
 | |
| 
 | |
|     **`firstChild`**: contains the first `ActivatedRoute` in the list of child routes.
 | |
| 
 | |
|     **`children`**: contains all the [child routes](#child-routing-component) activated under the current route.
 | |
| 
 | |
| :marked
 | |
|   We import the `Router`, `ActivatedRoute`, and `Params` tokens from the router package.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.1.ts (activated route)', 'imports')
 | |
| 
 | |
| a#hero-detail-ctor
 | |
| :marked
 | |
|   As usual, we write a constructor that asks Angular to inject services
 | |
|   that the component requires and reference them as private variables.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.ts (constructor)', 'ctor')
 | |
| 
 | |
| :marked
 | |
|   Later, in the `ngOnInit` method,
 | |
|   we use the `ActivatedRoute` service to retrieve the parameters for our route.
 | |
|   Since our parameters are provided as an `Observable`, we use the _forEach_ method to retrieve them for the `id` parameter by name and
 | |
|   tell the `HeroService` to fetch the hero with that `id`.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.ts (ngOnInit)', 'ngOnInit')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`.
 | |
| 
 | |
|     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.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Learn about the `ngOnInit` method in the
 | |
|     [Lifecycle Hooks](lifecycle-hooks.html) chapter.
 | |
| 
 | |
| h4#reuse Observable <i>params</i> and component re-use
 | |
| :marked
 | |
|   In this example, we retrieve the route params from an `Observable`.
 | |
|   That implies that the route params can change during the lifetime of this component.
 | |
| 
 | |
|   They might. By default, the router reuses a component instance when it re-navigates to the same component type
 | |
|   without visiting a different component first. The parameters can change between each re-use.
 | |
| 
 | |
|   Suppose a parent component navigation bar had "forward" and "back" buttons
 | |
|   that scrolled through the list of heroes.
 | |
|   Each click navigated imperatively to the `HeroDetailComponent` with the next or previous `id`.
 | |
| 
 | |
|   We don't want the router to remove the current `HeroDetailComponent` instance from the
 | |
|   DOM only to re-create it for the next `id`.
 | |
|   That could be visibly jarring.
 | |
|   Better to simply re-use the same component instance and update the parameter.
 | |
| 
 | |
|   But `ngOnInit` is only called once per instantiation.
 | |
|   We need a way to detect when the route parameters change from _within the same instance_.
 | |
|   The observable `params` property handles that beautifully.
 | |
| 
 | |
| h4#snapshot <i>Snapshot</i>: the no-observable alternative
 | |
| :marked
 | |
|   This application won't reuse the `HeroDetailComponent`.
 | |
|   We always return to the hero list to select another hero to view.
 | |
|   There's no way to navigate from hero detail to hero detail
 | |
|   without visiting the list component in between.
 | |
|   That means we get a new `HeroDetailComponent` instance every time.
 | |
| 
 | |
|   Suppose we know for certain that `HeroDetailComponent` will *never, never, ever*
 | |
|   be re-used. We'll always re-create the component each time we navigate to it.
 | |
| 
 | |
|   The router offers a *Snapshot* alternative that gives us the initial value of the route parameters.
 | |
|   We don't need to subscribe or unsubscribe.
 | |
|   It's much simpler to write and read:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.2.ts (ngOnInit snapshot)', 'snapshot')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     **Remember:** we only get the _initial_ value of the parameters with this technique.
 | |
|     Stick with the observable `params` approach if there's even a chance that we might navigate
 | |
|     to this component multiple times in a row.
 | |
|     We are leaving the observable `params` strategy in place just in case.
 | |
| 
 | |
| a#nav-to-list
 | |
| :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`.
 | |
| 
 | |
|   The router `navigate` method takes the same one-item *link parameters array*
 | |
|   that we can bind to a `[routerLink]` directive.
 | |
|   It holds the **path to the `HeroListComponent`**:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.1.ts (excerpt)', 'gotoHeroes')
 | |
| 
 | |
| .l-main-section#optional-route-parameters
 | |
| :marked
 | |
|   ### Route Parameters
 | |
| 
 | |
|   We use [*route parameters*](#route-parameters) to specify a *required* parameter value *within* the route URL
 | |
|   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
 | |
|   Sometimes we wish to add *optional* information to a route request.
 | |
|   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
 | |
|   img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected hero")
 | |
| :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.
 | |
| 
 | |
|   Optional parameters are the ideal vehicle for conveying arbitrarily complex information during navigation.
 | |
|   Optional parameters aren't involved in pattern matching and afford enormous flexibility of expression.
 | |
| 
 | |
|   The Router supports navigation with optional parameters as well as required route parameters.
 | |
|   We define _optional_ parameters in an *object* after we define our required route parameters.
 | |
| 
 | |
|   ### Route Parameters: Required or Optional?
 | |
| 
 | |
|   There is no hard-and-fast rule. In general,
 | |
| 
 | |
|   *prefer a required route parameter when*
 | |
|   * the value is required.
 | |
|   * the value is necessary to distinguish one route path from another.
 | |
| 
 | |
|   *prefer an optional parameter when*
 | |
|   * the value is optional, complex, and/or multi-variate.
 | |
| 
 | |
|   <a id="route-parameters-object"></a>
 | |
|   ### Route parameter
 | |
| 
 | |
|   When navigating to the `HeroDetailComponent` we specified the _required_ `id` of the hero-to-edit in the
 | |
|   *route parameter* and made it the second item of the [*link parameters array*](#link-parameters-array).
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array')
 | |
| 
 | |
| :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`:
 | |
| 
 | |
| +makeExcerpt('app/heroes/heroes-routing.module.ts', 'hero-detail-route')
 | |
| 
 | |
| :marked
 | |
|   When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array*
 | |
|   which it uses to navigate back to the `HeroListComponent`.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.1.ts', 'gotoHeroes')
 | |
| 
 | |
| :marked
 | |
|   This array lacks a route parameter 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.
 | |
|   This is a _nice-to-have_ feature; the list will display perfectly well without it.
 | |
| 
 | |
|   We do that with an object that contains an _optional_ `id` parameter.
 | |
|   For demonstration purposes, we also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore.
 | |
|   Here's the revised navigation statement:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.ts (go to heroes)', 'gotoHeroes-navigate')
 | |
| 
 | |
| :marked
 | |
|   The application still works. Clicking "back" returns to the hero list view.
 | |
| 
 | |
|   Look at the browser address bar.
 | |
| .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
 | |
|     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(language="bash").
 | |
|   localhost:3000/heroes;id=15;foo=foo
 | |
| 
 | |
| :marked
 | |
|   The `id` value appears in the URL as (`;id=15;foo=foo`), not in the URL path.
 | |
|   The path for the "Heroes" route doesn't have an `:id` token.
 | |
| 
 | |
|   The optional route parameters are not separated by "?" and "&" as they would be in the URL query string.
 | |
|   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 Router is such a system and provides
 | |
|     support for the matrix notation across browsers.
 | |
| 
 | |
|     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.
 | |
| 
 | |
| :marked
 | |
|   ### Route parameters in the *ActivatedRoute* service
 | |
| 
 | |
|   The list of heroes is unchanged. No hero row is highlighted.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The <live-example></live-example> *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.
 | |
| 
 | |
|   Previously, when navigating from the `HeroListComponent` to the `HeroDetailComponent`,
 | |
|   we subscribed to the route params `Observable` and made it available to the `HeroDetailComponent`
 | |
|   in the `ActivatedRoute` 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`.
 | |
| 
 | |
|   First we extend the router import statement to include the `ActivatedRoute` service symbol;
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.ts (import)', 'import-router')
 | |
| 
 | |
| :marked
 | |
|   Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe
 | |
|   and extract the `id` parameter as the `selectedId`:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.ts (constructor)', 'ctor')
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     All route/query parameters are strings.
 | |
|     The (+) in front of the `params['id']` 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.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.ts', 'isSelected')
 | |
| 
 | |
| :marked
 | |
|   Finally, we update our template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method.
 | |
|   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:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.ts', 'template')
 | |
| 
 | |
| :marked
 | |
|   When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
 | |
| figure.image-display
 | |
|   img(src='/resources/images/devguide/router/selected-hero.png' alt="Selected List" )
 | |
| :marked
 | |
|   The optional `foo` route parameter is harmless and continues to be ignored.
 | |
| 
 | |
| h3#route-animation Adding animations to the route component
 | |
| :marked
 | |
|   Our heroes feature module is almost complete, but what is a feature without some smooth transitions?
 | |
|   We already know that Angular supports [animations](../guide/animations.html) and we want to take
 | |
|   advantage of them by adding some animation to our *Hero Detail* component.
 | |
| 
 | |
|   First, we'll start by importing our animation functions that build our animation triggers,
 | |
|   control state and manage transitions between states. We'll use these functions to add transitions
 | |
|   to our route component as it moves between states our application view. We'll also import the
 | |
|   `HostBinding` decorator for binding to our route component.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.ts (animation imports)', 'route-animation-imports')
 | |
| 
 | |
| :marked
 | |
|   Next, we'll use a **host binding** for route animations named *@routeAnimation*. There is nothing special
 | |
|   about the choice of the binding name, but since we are controlling route animation, we'll go with `routeAnimation`.
 | |
|   The binding value is set to `true` because we only care about the `:enter` and `:leave` states which are
 | |
|   [entering and leaving](../api/core/index/transition-function.html#transition-aliases-enter-and-leave-) transition aliases.
 | |
| 
 | |
|   We'll also add some display and positioning bindings for styling.
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.ts (route animation binding)', 'route-animation-host-binding')
 | |
| 
 | |
| :marked
 | |
|   Now we can build our animation trigger, which we'll call *routeAnimation* to match the binding we previously
 | |
|   setup. We'll use the **wildcard state** that matches any animation state our route component is in, along with
 | |
|   two *transitions*. One transition animates the component as it enters the application view (`:enter`), while the other
 | |
|   animates the component as it leaves the application view (`:leave`).
 | |
| 
 | |
|   We could add different transitions to different route components depending on our needs. We'll just animate our `HeroDetailComponent` for this milestone.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Using route animations on individual components is something we don't want to do throughout our entire application.
 | |
|     It would be better to animate routes based on **route paths**, a topic to cover in a future update to this chapter.
 | |
| 
 | |
| :marked
 | |
|   Our route component animation looks as such:
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-detail.component.ts (route animation)', 'route-animation')
 | |
| 
 | |
| :marked
 | |
|   Simply stated, our `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away.
 | |
|   We could add more complex animations here, but we'll leave our `HeroDetailComponent` as is for now.
 | |
| 
 | |
| h3#merge-hero-routes Import hero module into AppModule
 | |
| :marked
 | |
|   Our heroes feature module is ready, but application doesn't know about our heroes module yet.
 | |
|   We'll need to import it into the `AppModule` we defined in `app.module.ts`.
 | |
| 
 | |
|   Update `app.module.ts` as follows:
 | |
| 
 | |
| +makeExcerpt('app/app.module.3.ts (heroes module import)', 'hero-import')
 | |
| 
 | |
| :marked
 | |
|   We imported the `HeroesModule` and added it to our `AppModule`'s `imports`.
 | |
| 
 | |
|   We removed the `HeroListComponent` from the `AppModule`'s `declarations` because its being provided by the `HeroesModule`
 | |
|   now. This is important because there can be only **one** owner for a declared component. In our case, the `Heroes` module is
 | |
|   the owner of the `Heroes` components and is making them available to the `AppModule`.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Routes provided by feature modules will be combined together into their imported module's routes by
 | |
|     the router. This allows us to continue defining our feature module routes without
 | |
|     modifying our main route configuration.
 | |
| 
 | |
| :marked
 | |
|   As a result, the `AppModule` no longer has specific knowledge of the hero feature, its components, or its route details.
 | |
|   We can evolve the hero feature with more components and different routes.
 | |
|   That's a key benefit of creating a separate module for each feature area.
 | |
| 
 | |
|   Since our `Heroes` routes are defined within our feature module, we can also remove our initial `heroes` route from the `app-routing.module.ts`.
 | |
| 
 | |
| +makeExcerpt('app/app-routing.module.2.ts (v2)', '')
 | |
| 
 | |
| :marked
 | |
|   ### Heroes App Wrap-up
 | |
| 
 | |
|   We've reached the second milestone in our router education.
 | |
| 
 | |
|   We've learned how to
 | |
|   * organize our app into *feature areas*
 | |
|   * navigate imperatively from one component to another
 | |
|   * pass information along in route parameters and subscribe to them in our component
 | |
|   * import our feature area NgModule into our `AppModule`
 | |
|   * apply animations to our route component
 | |
| 
 | |
|   After these changes, the folder structure looks like this:
 | |
| .filetree
 | |
|   .file router-sample
 | |
|   .children
 | |
|     .file app
 | |
|     .children
 | |
|       .file heroes
 | |
|       .children
 | |
|         .file hero-detail.component.ts
 | |
|         .file hero-list.component.ts
 | |
|         .file hero.service.ts
 | |
|         .file heroes.module.ts
 | |
|         .file heroes-routing.module.ts
 | |
|       .file app.component.ts
 | |
|       .file app.module.ts
 | |
|       .file app-routing.module.ts
 | |
|       .file crisis-list.component.ts
 | |
|       .file main.ts
 | |
|     .file node_modules ...
 | |
|     .file index.html
 | |
|     .file package.json
 | |
|     .file styles.css
 | |
|     .file tsconfig.json
 | |
| :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.1.ts,
 | |
|    router/ts/app/app.module.3.ts,
 | |
|    router/ts/app/app-routing.module.3.ts,
 | |
|    router/ts/app/heroes/hero-list.component.ts,
 | |
|    router/ts/app/heroes/hero-detail.component.ts,
 | |
|    router/ts/app/heroes/hero.service.ts,
 | |
|    router/ts/app/heroes/heroes.module.ts,
 | |
|    router/ts/app/heroes/heroes-routing.module.ts`,
 | |
|    null,
 | |
|   `app.component.ts,
 | |
|   app.module.ts,
 | |
|   app-routing.module.ts,
 | |
|   hero-list.component.ts,
 | |
|   hero-detail.component.ts,
 | |
|   hero.service.ts,
 | |
|   heroes.module.ts,
 | |
|   heroes-routing.module.ts`)
 | |
| 
 | |
| .l-main-section#crisis-center-feature
 | |
| :marked
 | |
|   ## Milestone #4: The Crisis Center
 | |
| 
 | |
|   The *Crisis Center* is a fake view at the moment. Time to make it useful.
 | |
| 
 | |
|   The new *Crisis Center* begins as a virtual copy of the *Heroes* module.
 | |
|   We create a new `app/crisis-center` folder, copy the Hero files,
 | |
|   and change every mention of "hero" to "crisis".
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   Voilà, another feature module!
 | |
| 
 | |
|   There's no point to this exercise unless we can learn something.
 | |
|   We do have new ideas and techniques in mind:
 | |
| 
 | |
|   * We'd like our route URLs to branch in to child route trees that reflect the component trees in our feature areas.
 | |
| 
 | |
|   * The application should navigate to the *Crisis Center* by default.
 | |
| 
 | |
|   * The router should prevent navigation away from the detail view while there are pending changes.
 | |
| 
 | |
|   * The user should be able to cancel unwanted changes.
 | |
| 
 | |
|   * The router should block access to certain features until the user logs-in.
 | |
| 
 | |
|   * Changes to a feature module such as *Crisis Center* shouldn't provoke changes to the `AppModule` or
 | |
|   any other feature's component.
 | |
|   We need to [*separate our concerns*](https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html).
 | |
| 
 | |
|   We'll address all of these issues in the *Crisis Center*
 | |
|   starting with the introduction of **child routes**
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     We'll leave *Heroes* in its less-than-perfect state to
 | |
|     serve as a contrast with what we believe to be a superior *Crisis Center* design.
 | |
| 
 | |
| :marked
 | |
|   ### A Crisis Center with child routes
 | |
| 
 | |
|   We'll organize the *Crisis Center* to conform to the following recommended pattern for Angular applications.
 | |
|   * each feature area in its own folder within a defined module
 | |
|   * each area with its own area root component
 | |
|   * each area root component with its own router-outlet and child routes
 | |
|   * area routes rarely (if ever) cross
 | |
| 
 | |
|   If we had many feature areas, their component trees might look like this:
 | |
| 
 | |
| figure.image-display
 | |
|   img(src='/resources/images/devguide/router/component-tree.png' alt="Component Tree" )
 | |
| 
 | |
| a#child-routing-component
 | |
| :marked
 | |
|   ### Child Routing Component
 | |
| 
 | |
|   Add the following `crisis-center.component.ts` to the `crisis-center` folder:
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center.component.ts (minus imports)', 'minus-imports')
 | |
| 
 | |
| :marked
 | |
|   The `CrisisCenterComponent` is much like the `AppComponent` shell.
 | |
| 
 | |
|   * It is the root of the *Crisis Center* area
 | |
|   just as `AppComponent` is the root of the entire application.
 | |
| 
 | |
|   * It is a shell for the crisis management feature area
 | |
|   just as the `AppComponent` is a shell to manage the high-level workflow.
 | |
| 
 | |
|   * It 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.
 | |
| 
 | |
|   Unlike `AppComponent` (and most other components), it **lacks a selector**.
 | |
|   It doesn't need one. We don't *embed* this component in a parent template.
 | |
|   We *navigate* to it from the outside, via the router.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     We *can* give it a selector. There's no harm in it.
 | |
|     Our point is that we don't *need* one because we only *navigate* to it.
 | |
| 
 | |
| :marked
 | |
|   ### Child Route Configuration
 | |
| 
 | |
|   The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`.
 | |
|   It has its own `RouterOutlet` and its own child routes.
 | |
| 
 | |
|   Add the following `crisis-center-home.component.ts` to the `crisis-center` folder.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-home.component.ts (minus imports)', 'minus-imports')
 | |
| 
 | |
| :marked
 | |
|   We create a `crisis-center-routing.module.ts` file as we did the `heroes-routing.module.ts` file.
 | |
|   But this time we define **child routes** *within* the parent `crisis-center` route.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-routing.module.1.ts (Routes)', 'routes')
 | |
| 
 | |
| :marked
 | |
|   Notice that the parent `crisis-center` route has a `children` property
 | |
|   with a single route containing our `CrisisListComponent`. The `CrisisListComponent` route
 | |
|   also has a `children` array with two routes.
 | |
| 
 | |
|   These two routes navigate to the two *Crisis Center* child components,
 | |
|   `CrisisCenterHomeComponent` and `CrisisDetailComponent`.
 | |
| 
 | |
|   There are some *important differences* in the treatment of these routes.
 | |
| 
 | |
|   The router displays the components of these routes in the `RouterOutlet`
 | |
|   of the `CrisisCenterComponent`, not in the `RouterOutlet` of the `AppComponent` shell.
 | |
| 
 | |
|   The `CrisisListComponent` contains the crisis list and a `RouterOutlet` to
 | |
|   display the `Crisis Center Home` and `Crisis Detail` route components.
 | |
| 
 | |
|   The `Crisis Detail` route is a child of the `Crisis List`. Since the router [reuses components](#reuse)
 | |
|   by default, the `Crisis Detail` component will be re-used as we select different crises.
 | |
| 
 | |
|   In contrast, back in the `Hero Detail` route, the component was recreated each time we selected a different hero.
 | |
| 
 | |
|   At the top level, paths that begin with `/` refer to the root of the application.
 | |
|   But these are child routes.
 | |
|   They *extend* the path of the parent route.
 | |
|   With each step down the route tree, we add a slash followed by the route path (unless the route path is _empty_).
 | |
| 
 | |
|   For example, the parent path to the `CrisisCenterComponent` is `/crisis-center`
 | |
|   The router appends these child paths to the parent path to the `CrisisCenterComponent` (`/crisis-center`).
 | |
| 
 | |
|   * to navigate to the `CrisisCenterHomeComponent`, the full URL is `/crisis-center` (`/crisis-center` + `''` + `''`).
 | |
| 
 | |
|   * to navigate to the `CrisisDetailComponent` for a crisis with `id=2`, the full URL is
 | |
|   `/crisis-center/2` (`/crisis-center` + `''` + `'/2'`).
 | |
| 
 | |
|   The absolute URL for the latter example, including the origin, is
 | |
| code-example.
 | |
|   localhost:3000/crisis-center/2
 | |
| 
 | |
| :marked
 | |
|   Here's the complete `crisis-center-routing.module.ts` file with its imports.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-routing.module.1.ts', '')
 | |
| 
 | |
| h3#import-crisis-module Import crisis center module into the AppModule routes
 | |
| :marked
 | |
|   As with the `Heroes` module, we must import the `Crisis Center` module into the `AppModule`:
 | |
| 
 | |
| +makeExcerpt('app/app.module.4.ts (import CrisisCenterModule)', 'crisis-center-module')
 | |
| 
 | |
| :marked
 | |
|   We also remove the initial crisis center route from our `app-routing.module.ts`. Our routes
 | |
|   are now being provided by our `HeroesModule` and our `CrisisCenter` feature modules. We'll keep our `app-routing.module.ts` file
 | |
|   for general routes which we'll cover later in the chapter.
 | |
| 
 | |
| +makeExcerpt('app/app-routing.module.3.ts (v3)', '')
 | |
| 
 | |
| a#redirect
 | |
| :marked
 | |
|   ### Redirecting routes
 | |
| 
 | |
|   When the application launches, the initial URL in the browser bar is something like:
 | |
| 
 | |
| code-example.
 | |
|   localhost:3000
 | |
| 
 | |
| :marked
 | |
|   That doesn't match any of our configured routes which means that our application won't display any component when it's launched.
 | |
|   The user must click one of the navigation links to trigger a navigation and display something.
 | |
| 
 | |
|   We prefer that the application display the list of crises as it would if the user clicked the "Crisis Center" link or pasted `localhost:3000/crisis-center/` into the address bar.
 | |
|   This is our intended default route.
 | |
| 
 | |
|   The preferred solution is to add a `redirect` route that transparently translates from the initial relative URL (`''`)
 | |
|   to the desired default path (`/crisis-center`):
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-routing.module.2.ts' , 'redirect', '')
 | |
| 
 | |
| :marked
 | |
|   A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route.
 | |
|   In this app, the router should select the route to the `CrisisListComponent` when the *entire URL* matches `''`,
 | |
|   so we set the `pathMatch` value to `'full'`.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Technically, `pathMatch = 'full'` results in a route hit when the *remaining*, unmatched segments of the URL match `''`.
 | |
|     In our example, the redirect is at the top level of the route configuration tree so the *remaining* URL and the *entire* URL
 | |
|     are the same thing.
 | |
| 
 | |
|     The other possible `pathMatch` value is `'prefix'` which tells the router
 | |
|     to match the redirect route when the *remaining* URL ***begins*** with the redirect route's _prefix_ path.
 | |
| 
 | |
|     That's not what we want to do here. If the `pathMatch` value were `'prefix'`,
 | |
|     _every_ URL would match `''`.
 | |
|     We could never navigate to `/crisis-center/1` because the redirect route would match first and
 | |
|     send us to the `CrisisListComponent`.
 | |
| 
 | |
|     We should redirect to the `CrisisListComponent` _only_ when the _entire (remaining)_ url is  `''`.
 | |
| 
 | |
|     Learn more in Victor Savkin's blog
 | |
|     [post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes).
 | |
| 
 | |
|     We'll discuss redirects in more detail in a future update to this chapter.
 | |
| 
 | |
| :marked
 | |
|   The updated route definitions look like this:
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-routing.module.2.ts (routes v2)' , 'routes')
 | |
| 
 | |
| .l-main-section
 | |
| h2#relative-navigation Relative Navigation
 | |
| :marked
 | |
|   While building out our *Crisis Center* feature, we've navigated to the
 | |
|   *Crisis Detail* route using an **absolute path** that begins with a **slash**.
 | |
|   This navigation starts from the top of our route configuration to find the
 | |
|   matching path to our route.
 | |
| 
 | |
|   We could continue to use absolute paths to navigate inside our *Crisis Center*
 | |
|   feature, but that makes our links very rigid. If we changed our parent `/crisis-center`
 | |
|   path, we would have to change our link parameters array.
 | |
| 
 | |
|   We can make our links more flexible by using **relative** navigation with the router.
 | |
|   * The full path to the route is not required.
 | |
|   * Navigation within our feature area remains intact if the parent route path is changed.
 | |
|   * The *link parameters array* only contains navigation relative to the current URL.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The **link parameters array** supports a directory-like syntax for relative navigation.
 | |
| 
 | |
|     `./` or `no leading slash` is relative to the current level.
 | |
| 
 | |
|     `../` to go up one level in the route path.
 | |
| 
 | |
|     The relative navigation syntax can be used in combination with a *path*. If we wanted to navigate
 | |
|     from one route path to another sibling route path we could use `../path` convention to go up
 | |
|     one level and down to the sibling route path.
 | |
| 
 | |
| :marked
 | |
|   In order to navigate relatively using the `Router` service, we use the `ActivatedRoute`
 | |
|   to give the router knowledge of where we are in the *RouterState*, which is our tree of
 | |
|   activated routes. We do this by adding an object as the second argument in our
 | |
|   `router.navigate` method after the *link parameters array* specifying the **relativeTo** property.
 | |
|   We set the `relativeTo` property to our `ActivatedRoute` and the router will merge our
 | |
|   navigation information into to the current URL.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     When using router's `navigateByUrl` method, the navigation is **always** absolute.
 | |
| 
 | |
| :marked
 | |
|   ### Navigate to Crisis Detail relatively
 | |
| 
 | |
|   Let's update our *Crisis List* `onSelect` method to use relative navigation so we don't have
 | |
|   to start from the top of our route configuration. We've already injected the `ActivatedRoute`
 | |
|   into our constructor that we'll need for the relative navigation.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-list.component.1.ts (constructor)', 'relative-navigation-ctor')
 | |
| 
 | |
| :marked
 | |
|   When we visit the *Crisis Center*, our path is `/crisis-center`, so we just want to add the `id` of the *Crisis Center*
 | |
|   to our existing path. When the router navigates, it will use the current path `/crisis-center`,
 | |
|   adding on our `id`. If our `id` were `1`, the resulting path would be `/crisis-center/1`.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-list.component.ts (relative navigation)', 'relative-navigation')
 | |
| 
 | |
| :marked
 | |
|   We'll also update the *Crisis Detail* component to navigate back to our *Crisis Center* list. We want to go back up a level
 | |
|   in the path, so we use to the `../` syntax. If our current `id` is `1`, the resulting path coming from `/crisis-center/1`
 | |
|   would be `/crisis-center`.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (relative navigation)', 'relative-navigation')
 | |
| 
 | |
| :marked
 | |
|   If we are using a `RouterLink` to navigate instead of the `Router` service, we can use the **same**
 | |
|   link parameters array, but we don't have to provide the object with the `relativeTo` property. The `ActivatedRoute`
 | |
|   is implicit in the `RouterLink` directive.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-list.component.1.ts (relative routerLink)', 'relative-navigation-router-link')
 | |
| 
 | |
| <a id="guards"></a>
 | |
| .l-main-section
 | |
| h2#guards Route Guards
 | |
| :marked
 | |
|   ## Milestone #5: Route Guards
 | |
| 
 | |
|   At the moment, *any* user can navigate *anywhere* in the application *anytime*.
 | |
| 
 | |
|   That's not always the right thing to do.
 | |
|   * Perhaps the user is not authorized to navigate to the target component.
 | |
|   * Maybe the user must login (*authenticate*) first.
 | |
|   * Maybe we should fetch some data before we display the target component.
 | |
|   * We might want to save pending changes before leaving a component.
 | |
|   * We might ask the user if it's OK to discard pending changes rather than save them.
 | |
| 
 | |
|   We can add ***guards*** to our route configuration to handle these scenarios.
 | |
| 
 | |
|   A guard's return value controls the router's behavior:
 | |
|   * if it returns `true`, the navigation process continues
 | |
|   * if it returns `false`, the navigation process stops and the user stays put
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The guard can also tell the router to navigate elsewhere, effectively canceling the current navigation.
 | |
| :marked
 | |
|   The guard *might* return its boolean answer synchronously.
 | |
|   But in many cases, the guard can't produce an answer synchronously.
 | |
|   The guard could ask the user a question, save changes to the server, or fetch fresh data.
 | |
|   These are all asynchronous operations.
 | |
| 
 | |
|   Accordingly, a routing guard can return an `Observable<boolean>` or a `Promise<boolean>` and the
 | |
|   router will wait for the observable to resolve to `true` or `false`.
 | |
| 
 | |
|   The router supports multiple kinds of guards:
 | |
| 
 | |
|   1. [CanActivate](../api/router/index/CanActivate-interface.html) to mediate navigation *to* a route.
 | |
| 
 | |
|   2. [CanActivateChild](../api/router/index/CanActivateChild-interface.html) to mediate navigation *to* a child route.
 | |
| 
 | |
|   3. [CanDeactivate](../api/router/index/CanDeactivate-interface.html) to mediate navigation *away* from the current route.
 | |
| 
 | |
|   4. [Resolve](../api/router/index/Resolve-interface.html) to perform route data retrieval *before* route activation.
 | |
| 
 | |
|   5. [CanLoad](../api/router/index/CanLoad-interface.html) to mediate navigation *to* a feature module loaded _asynchronously_.
 | |
| 
 | |
| :marked
 | |
|   We can have multiple guards at every level of a routing hierarchy.
 | |
|   The router checks the `CanDeactivate` and `CanActivateChild` guards first, from deepest child route to the top.
 | |
|   Then it checks the `CanActivate` guards from the top down to the deepest child route. If the feature module
 | |
|   is loaded asynchronously, the `CanLoad` guard is checked before the module is loaded.
 | |
|   If _any_ guard returns false, pending guards that have not completed will be canceled,
 | |
|   and the entire navigation is canceled.
 | |
| 
 | |
|   Let's look at some examples.
 | |
| 
 | |
| a#can-activate-guard
 | |
| :marked
 | |
|   ### *CanActivate*: requiring authentication
 | |
| 
 | |
|   Applications often restrict access to a feature area based on who the user is.
 | |
|   We could permit access only to authenticated users or to users with a specific role.
 | |
|   We might block or limit access until the user's account is activated.
 | |
| 
 | |
|   The `CanActivate` guard is the tool to manage these navigation business rules.
 | |
| 
 | |
|   #### Add an admin feature module
 | |
| 
 | |
|   We intend to extend the Crisis Center with some new *administrative* features.
 | |
|   Those features aren't defined yet. So we add a new feature module named `AdminModule`.
 | |
|   We'll follow our same convention by creating an `admin` folder with a feature
 | |
|   module file, route file and supporting components.
 | |
| 
 | |
|   Our admin feature module file structure looks like this:
 | |
| 
 | |
| .filetree
 | |
|   .file app/admin
 | |
|   .children
 | |
|     .file admin-dashboard.component.ts
 | |
|     .file admin.component.ts
 | |
|     .file admin.module.ts
 | |
|     .file admin-routing.module.ts
 | |
|     .file manage-crises.component.ts
 | |
|     .file manage-heroes.component.ts
 | |
| 
 | |
| :marked
 | |
|   Our admin feature module contains our `AdminComponent` used for routing within our
 | |
|   feature module, a dashboard route and two unfinished components to manage crises and heroes.
 | |
| 
 | |
| +makeTabs(
 | |
|    `router/ts/app/admin/admin-dashboard.component.1.ts,
 | |
|    router/ts/app/admin/admin.component.ts,
 | |
|    router/ts/app/admin/admin.module.ts,
 | |
|    router/ts/app/admin/manage-crises.component.ts,
 | |
|    router/ts/app/admin/manage-heroes.component.ts
 | |
|   `,
 | |
|   null,
 | |
|    `app/admin/admin-dashboard.component.ts,
 | |
|    app/admin/admin.component.ts,
 | |
|    app/admin/admin.module.ts,
 | |
|    app/admin/manage-crises.component.ts,
 | |
|    app/admin/manage-heroes.component.ts
 | |
|   `)
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Since our admin dashboard `RouterLink` is an empty path route in our `AdminModule`, it
 | |
|     is considered a match to any route within our admin feature area. We only want the `Dashboard`
 | |
|     link to be active when we visit that route. We've added an additional binding to our `Dashboard` routerLink,
 | |
|     `[routerLinkActiveOptions]="{ exact: true }"` which will only mark the `./` link as active when
 | |
|     we navigate the to `/admin` URL and not when we navigate to one the other child routes.
 | |
| 
 | |
| :marked
 | |
|   Our initial admin routing configuration:
 | |
| 
 | |
| +makeExcerpt('app/admin/admin-routing.module.1.ts (admin routing)', 'admin-routes')
 | |
| 
 | |
| h3#component-less-route <i>Component-Less Route</i>: grouping routes without a component
 | |
| :marked
 | |
|   Looking at our child route under the `AdminComponent`, we have a route with a **path** and a **children**
 | |
|   property but it's not using a **component**. We haven't made a mistake in our configuration, because we can
 | |
|   use a **component-less** route.
 | |
| 
 | |
|   We want to group our `Crisis Center` management routes under the `admin` path, but we don't need a component
 | |
|   just to group those routes under an additional `RouterOutlet`. This also allows us to [guard child routes](#can-activate-child-guard).
 | |
| 
 | |
| :marked
 | |
|   Next, we'll import the `AdminModule` into our `app.module.ts` and add it to the `imports` array
 | |
|   to register our admin routes.
 | |
| 
 | |
| +makeExcerpt('app/app.module.4.ts (admin module)', 'admin-module')
 | |
| 
 | |
| :marked
 | |
|   And we add a link to the `AppComponent` shell that users can click to get to this feature.
 | |
| 
 | |
| +makeExcerpt('app/app.component.4.ts', 'template')
 | |
| 
 | |
| :marked
 | |
|   #### Guard the admin feature
 | |
|   Currently every route within our *Crisis Center* is open to everyone.
 | |
|   The new *admin* feature should be accessible only to authenticated users.
 | |
| 
 | |
|   We could hide the link until the user logs in. But that's tricky and difficult to maintain.
 | |
| 
 | |
|   Instead we'll write a `CanActivate` guard to redirect anonymous users to the login page when they try to reach the admin component.
 | |
| 
 | |
|   This is a general purpose guard — we can imagine other features that require authenticated users —
 | |
|   so we create an `auth-guard.service.ts` in the application root folder.
 | |
| 
 | |
|   At the moment we're interested in seeing how guards work so our first version does nothing useful.
 | |
|   It simply logs to console and `returns` true immediately, allowing navigation to proceed:
 | |
| 
 | |
| +makeExcerpt('app/auth-guard.service.1.ts')
 | |
| 
 | |
| :marked
 | |
|   Next we open `admin-routing.module.ts `, import the `AuthGuard` class, and
 | |
|   update the admin route with a `CanActivate` guard property that references it:
 | |
| 
 | |
| +makeExcerpt('app/admin/admin-routing.module.2.ts (guarded admin route)', 'admin-route')
 | |
| 
 | |
| :marked
 | |
|   Our admin feature is now protected by the guard, albeit protected poorly.
 | |
| 
 | |
|   #### Teach *AuthGuard* to authenticate
 | |
|   Let's make our `AuthGuard` at least pretend to authenticate.
 | |
| 
 | |
|   The `AuthGuard` should call an application service that can login a user and retain information about the current user.
 | |
|   Here's a demo `AuthService`:
 | |
| 
 | |
| +makeExcerpt('app/auth.service.ts')
 | |
| 
 | |
| :marked
 | |
|   Although it doesn't actually log in, it has what we need for this discussion.
 | |
|   It has an `isLoggedIn` flag to tell us whether the user is authenticated.
 | |
|   Its `login` method simulates an API call to an external service by returning an observable that resolves successfully after a short pause.
 | |
|   The `redirectUrl` property will store our attempted URL so we can navigate to it after authenticating.
 | |
| 
 | |
|   Let's revise our `AuthGuard` to call it.
 | |
| 
 | |
| +makeExcerpt('app/auth-guard.service.2.ts (v2)', '')
 | |
| 
 | |
| :marked
 | |
|   Notice that we *inject* the `AuthService` and the `Router` in the constructor.
 | |
|   We haven't provided the `AuthService` yet but it's good to know that we can inject helpful services into our routing guards.
 | |
| 
 | |
|   This guard returns a synchronous boolean result.
 | |
|   If the user is logged in, it returns true and the navigation continues.
 | |
| 
 | |
|   The `ActivatedRouteSnapshot` contains the _future_ route that will be activated and the `RouterStateSnapshot`
 | |
|   contains the _future_ `RouterState` of our application, should we pass through our guard check.
 | |
| 
 | |
|   If the user is not logged in, we store the attempted URL the user came from using the `RouterStateSnapshot.url` and
 | |
|   tell the router to navigate to a login page — a page we haven't created yet.
 | |
|   This secondary navigation automatically cancels the current navigation; we return `false` just to be clear about that.
 | |
| 
 | |
|   #### Add the *LoginComponent*
 | |
|   We need a `LoginComponent` for the user to log in to the app. After logging in, we'll redirect
 | |
|   to our stored URL if available, or use the default URL.
 | |
|   There is nothing new about this component or the way we wire it into the router configuration.
 | |
| 
 | |
|   We'll register a `/login` route in our `login-routing.module.ts` and add the necessary providers to the `providers`
 | |
|   array. In our `app.module.ts`, we'll import the `LoginComponent` and add it to our `AppModule` `declarations`.
 | |
|   We'll also import and add the `LoginRoutingModule` to our `AppModule` imports.
 | |
| 
 | |
| +makeTabs(
 | |
|    `router/ts/app/app.module.ts,
 | |
|    router/ts/app/login.component.1.ts,
 | |
|    router/ts/app/login-routing.module.ts
 | |
|   `,
 | |
|   null,
 | |
|    `app/app.module.ts,
 | |
|    app/login.component.ts,
 | |
|    app/login-routing.module.ts
 | |
|   `)
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Guards and the service providers they require **must** be provided at the module-level. This allows
 | |
|     the Router access to retrieve these services from the `Injector` during the navigation process.
 | |
|     The same rule applies for feature modules loaded [asynchronously](#asynchronous-routing).
 | |
| 
 | |
| h3#can-activate-child-guard <i>CanActivateChild</i>: guarding child routes
 | |
| :marked
 | |
|   As we learned about guarding routes with `CanActivate`, we can also protect child routes with the `CanActivateChild`
 | |
|   guard. The `CanActivateChild` guard works similarly to the `CanActivate` guard, but the difference is its run _before_
 | |
|   each child route is activated. We protected our admin feature module from unauthorized access, but we could also
 | |
|   protect child routes within our feature module.
 | |
| 
 | |
|   Let's extend our `AuthGuard` to protect when navigating between our `admin` routes. First we'll open our
 | |
|   `auth-guard.service.ts` and add `CanActivateChild` interface to our imported tokens from the router package.
 | |
| 
 | |
|   Next, we'll implement the `canActivateChild` method with takes the same arguments as the `canActivate` method,
 | |
|   an `ActivatedRouteSnapshot` and `RouterStateSnapshot`. The `canActivateChild` behaves the same way the other
 | |
|   guards do, returning an `Observable<boolean>` or `Promise<boolean>` for async checks and `boolean` for sync checks.
 | |
|   We'll return a `boolean`
 | |
| 
 | |
| +makeExcerpt('app/auth-guard.service.3.ts (excerpt)', 'can-activate-child')
 | |
| 
 | |
| :marked
 | |
|   We add the same `AuthGuard` to our `component-less` admin route to protect all other child routes at one time
 | |
|   instead of adding the `AuthGuard` to each route individually.
 | |
| 
 | |
| +makeExcerpt('app/admin/admin-routing.module.3.ts (excerpt)', 'can-activate-child')
 | |
| 
 | |
| h3#can-deactivate-guard <i>CanDeactivate</i>: handling unsaved changes
 | |
| :marked
 | |
|   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.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   We need the `CanDeactivate` guard.
 | |
| 
 | |
|   ### Cancel and Save
 | |
| 
 | |
|   Our sample application doesn't talk to a server.
 | |
|   Fortunately, we have another way to demonstrate an asynchronous router hook.
 | |
| 
 | |
|   Users update crisis information in the `CrisisDetailComponent`.
 | |
|   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 the *Cancel* button.
 | |
| 
 | |
|   Both buttons navigate back to the crisis list after save or cancel.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save')
 | |
| 
 | |
| :marked
 | |
|   What if the user tries to navigate away without saving or canceling?
 | |
|   The user could push the browser back button or click the heroes link.
 | |
|   Both actions trigger a navigation.
 | |
|   Should the app save or cancel automatically?
 | |
| 
 | |
|   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
 | |
|   answer*.
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     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.
 | |
| :marked
 | |
|   The `DialogService` (provided in the `AppModule` for app-wide use) does the asking.
 | |
| 
 | |
|   It returns a [promise](http://exploringjs.com/es6/ch_promises.html) that
 | |
|   *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`).
 | |
| 
 | |
| a#CanDeactivate
 | |
| :marked
 | |
|   We create a `Guard` that will check for the presence of a `canDeactivate` function in our component, in this
 | |
|   case being `CrisisDetailComponent`. We don't need to know the details of how our `CrisisDetailComponent` confirms deactivation.
 | |
|   This makes our guard reusable, which is an easy win for us.
 | |
| 
 | |
| +makeExample('app/can-deactivate-guard.service.ts')
 | |
| 
 | |
| :marked
 | |
|   Alternatively, We could make a component-specific `CanDeactivate` guard for our `CrisisDetailComponent`. The `canDeactivate` method provides us
 | |
|   with the current instance of our `component`, the current `ActivatedRoute` and `RouterStateSnapshot` in case we needed to access
 | |
|   some external information. This would be useful if we only wanted to use this guard for this component and needed to ask the component's
 | |
|   properties in or to confirm whether the router should allow navigation away from it.
 | |
| 
 | |
| +makeExcerpt('app/can-deactivate-guard.service.1.ts (component-specific)', '')
 | |
| 
 | |
| :marked
 | |
|   Looking back at our `CrisisDetailComponent`, we have implemented our confirmation workflow for unsaved changes.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save-only')
 | |
| 
 | |
| :marked
 | |
|   Notice that the `canDeactivate` method *can* return synchronously;
 | |
|   it returns `true` immediately if there is no crisis or there are no pending changes.
 | |
|   But it can also return a `Promise` or an `Observable` and the router will wait for that
 | |
|   to resolve to truthy (navigate) or falsey (stay put).
 | |
| 
 | |
| :marked
 | |
|   We add the `Guard` to our crisis detail route in `crisis-center-routing.module.ts` using the `canDeactivate` array.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-routing.module.3.ts (can deactivate guard)', '')
 | |
| 
 | |
| :marked
 | |
|   We also need to add the `Guard` to our main `AppRoutingModule` `providers` so the `Router` can inject it during the navigation process.
 | |
| 
 | |
| +makeExample('app/app-routing.module.4.ts', '', '')
 | |
| 
 | |
| :marked
 | |
|   Now we have given our user a safeguard against unsaved changes.
 | |
| 
 | |
| <a id="Resolve"></a>
 | |
| h3#resolve-guard <i>Resolve</i>: pre-fetching component data
 | |
| :marked
 | |
|   In our `Hero Detail` and `Crisis Detail`, we waited until the route was activated to fetch our respective hero or crisis.
 | |
| 
 | |
|   This worked well for us, but we can always do better.
 | |
|   If we were using a real world api, there may be some delay in when the data we want to display gets returned.
 | |
|   We don't want to display a blank component until the data loads in this situation.
 | |
| 
 | |
|   We'd like to pre-fetch data from the server so it's ready the moment our route is activated.
 | |
|   We'd also like to handle the situation where our data fails to load or some other error condition occurs.
 | |
|   This would help us in our `Crisis Center` if we navigated to an `id` that doesn't return a record.
 | |
|   We could send the user back to the `Crisis List` where we only show valid crisis centers.
 | |
|   We want to delay rendering of our route component until all necessary data has been fetched or some action
 | |
|   has occurred.
 | |
| 
 | |
|   We need the `Resolve` guard.
 | |
| 
 | |
|   ### Fetch data before navigating
 | |
| 
 | |
|   We'll update our `Crisis Detail` route to resolve our Crisis before loading the route, or if the user happens to
 | |
|   navigate to an invalid crisis center `:id`, we'll navigate back to our list of existing crises.
 | |
| 
 | |
|   Like the `CanActivate` and `CanDeactivate` guards, the **`Resolve`** guard is an interface we can implement as a service
 | |
|   to resolve route data synchronously or asynchronously. In `CrisisDetailComponent`, we used the `ngOnInit` to retrieve the `Crisis`
 | |
|   information. We also navigated the user away from the route if the `Crisis` was not found. It would be more efficient to perform this
 | |
|   action before the route is ever activated.
 | |
| 
 | |
|   We'll create a `CrisisDetailResolve` service that will handle retrieving the `Crisis` and navigating the user away if the `Crisis` does
 | |
|   not exist. Then we can be assured that when we activate the `CrisisDetailComponent`, the associated Crisis will already be available
 | |
|   for display.
 | |
| 
 | |
|   Let's create our `crisis-detail-resolve.service.ts` file within our `Crisis Center` feature area.
 | |
| 
 | |
| +makeExample('app/crisis-center/crisis-detail-resolve.service.ts', '')
 | |
| 
 | |
| :marked
 | |
|   We'll take the relevant parts of the `ngOnInit` lifecycle hook in our `CrisisDetailComponent` and move them into our `CrisisDetailResolve` guard.
 | |
|   We import the `Crisis` model and `CrisisService` and also the `Router` for navigation from our resolve implementation. We want to be explicit about
 | |
|   the data we are resolving, so we implement the `Resolve` interface with a type of `Crisis`. This lets us know that what we will resolve will match our
 | |
|   `Crisis` model. We inject the `CrisisService` and `Router` and implement the `resolve` method that supports a `Promise`, `Observable` or a synchronous
 | |
|   return value.
 | |
| 
 | |
|   We'll use our `CrisisService.getCrisis` method that returns a promise to prevent our route from loading until the data is fetched. If we don't find a valid `Crisis`,
 | |
|   we navigate the user back to the `CrisisList`, canceling the previous in-flight navigation to the crisis details.
 | |
| 
 | |
|   Now that our guard is ready, we'll import it in our `crisis-center-routing.module.ts` and use the `resolve` object in our route configuration.
 | |
| 
 | |
|   We'll add the `CrisisDetailResolve` service to our `CrisisCenterRoutingModule`'s `providers`, so its available to the `Router` during the navigation process.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-center-routing.module.4.ts (resolve)', 'crisis-detail-resolve')
 | |
| 
 | |
| :marked
 | |
|   Now that we've added our `Resolve` guard to fetch data before the route loads, we no longer need to do this once we get into our `CrisisDetailComponent`.
 | |
|   We'll update the `CrisisDetailComponent` to use the `ActivatedRoute` data, which is where our `crisis` property from our `Resolve` guard will be provided.
 | |
|   Once activated, all we need to do is set our local `crisis` and `editName` properties from our resolved `Crisis` information. The `Crisis` is being provided
 | |
|   at the time the route component is activated.
 | |
| 
 | |
| +makeExcerpt('app/crisis-center/crisis-detail.component.ts (ngOnInit v2)', 'crisis-detail-resolve')
 | |
| 
 | |
| :marked
 | |
|   **Two critical points**
 | |
|   1. The router interface is optional. We don't inherit from a base class. We simply implement the interface method or not.
 | |
| 
 | |
|   1. We rely on the router to call the guard. We don't worry about all the ways that the user
 | |
|   could navigate away. That's the router's job.
 | |
|   We simply write this class and let the router take it from there.
 | |
| 
 | |
|   The relevant *Crisis Center* code for this milestone is
 | |
| 
 | |
| +makeTabs(
 | |
|    `router/ts/app/app.component.ts,
 | |
|    router/ts/app/crisis-center/crisis-center-home.component.ts,
 | |
|    router/ts/app/crisis-center/crisis-center.component.ts,
 | |
|    router/ts/app/crisis-center/crisis-center-routing.module.4.ts,
 | |
|    router/ts/app/crisis-center/crisis-list.component.ts,
 | |
|    router/ts/app/crisis-center/crisis-detail.component.ts,
 | |
|    router/ts/app/crisis-center/crisis-detail-resolve.service.ts,
 | |
|    router/ts/app/crisis-center/crisis.service.ts
 | |
|   `,
 | |
|   null,
 | |
|    `app.component.ts,
 | |
|    crisis-center-home.component.ts,
 | |
|    crisis-center.component.ts,
 | |
|    crisis-center-routing.module.ts,
 | |
|    crisis-list.component.ts,
 | |
|    crisis-detail.component.ts,
 | |
|    crisis-detail-resolve.service.ts,
 | |
|    crisis.service.ts
 | |
|   `)
 | |
| 
 | |
| +makeTabs(
 | |
|    `router/ts/app/auth-guard.service.3.ts,
 | |
|    router/ts/app/can-deactivate-guard.service.ts
 | |
|   `,
 | |
|   null,
 | |
|    `auth-guard.service.ts,
 | |
|    can-deactivate-guard.service.ts
 | |
|   `)
 | |
| 
 | |
| a#query-parameters
 | |
| a#fragment
 | |
| :marked
 | |
|   ### Query Parameters and Fragments
 | |
| 
 | |
|   In our [route parameters](#optional-route-parameters) example, we only dealt with parameters specific to
 | |
|   our route, but what if we wanted optional parameters available to all routes? This is where our
 | |
|   query parameters come into play and serve a special purpose in our application.
 | |
| 
 | |
|   [Fragments](https://en.wikipedia.org/wiki/Fragment_identifier) refer to certain elements on the page
 | |
|   identified with an `id` attribute.
 | |
| 
 | |
|   We'll update our `AuthGuard` to provide a `session_id` query that will remain after navigating to another route.
 | |
| 
 | |
|   We'll also provide an arbitrary `anchor` fragment, which we would use to jump to a certain point on our page.
 | |
| 
 | |
|   We'll add the `NavigationExtras` object to our `router.navigate` method that navigates us to our `/login` route.
 | |
| 
 | |
| +makeExcerpt('app/auth-guard.service.4.ts (v3)', '')
 | |
| 
 | |
| :marked
 | |
|   We can also **preserve** query parameters and fragments across navigations without having to re-provide them
 | |
|   when navigating. In our `LoginComponent`, we'll add an *object* as the second argument in our `router.navigate` function
 | |
|   and provide the `preserveQueryParams` and `preserveFragment` to pass along the current query parameters
 | |
|   and fragment to the next route.
 | |
| 
 | |
| +makeExcerpt('app/login.component.ts', 'preserve')
 | |
| 
 | |
| :marked
 | |
|   Since we'll be navigating to our *Admin Dashboard* route after logging in, we'll update it to handle our
 | |
|   query parameters and fragment.
 | |
| 
 | |
| +makeExcerpt('app/admin/admin-dashboard.component.2.ts (v2)', '')
 | |
| 
 | |
| :marked
 | |
|   *Query Parameters* and *Fragments* are also available through the `ActivatedRoute` service available to route components.
 | |
|   Just like our *route parameters*, query parameters and fragments are provided as an `Observable`.
 | |
|   For our updated *Crisis Admin* component we'll feed the `Observable` directly into our template using the `AsyncPipe`, which
 | |
|   will handle _unsubscribing_ from the `Observable` for us when the component is destroyed.
 | |
| 
 | |
| .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
 | |
|     When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner.
 | |
| 
 | |
| :marked
 | |
|   Following the steps in this process, we can click on the *Admin* button, that takes us to the *Login*
 | |
|   page with our provided `query params` and `fragment`. After we click the login button, we notice that
 | |
|   we have been redirected to the `Admin Dashboard` page with our `query params` and `fragment` still intact. We can use
 | |
|   these persistent bits of information for things that need to be provided with across pages interaction like
 | |
|   authentication tokens or session ids.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The `query params` and `fragment` can also be preserved using a `RouterLink` with
 | |
|     the **preserveQueryParams** and **preserveFragment** bindings respectively.
 | |
| 
 | |
| <a id="asynchronous-routing"></a>
 | |
| .l-main-section
 | |
| :marked
 | |
|   ## Milestone #6: Asynchronous Routing
 | |
| 
 | |
|   As we have completed our milestones, our application has naturally gotten larger. As we continue to build
 | |
|   out feature areas our overall application size will get larger also. At some point we'll reach a tipping
 | |
|   point in where our application takes a significant enough time to load. This is not a viable long term solution.
 | |
| 
 | |
|   So how do we combat this problem? We introduce asynchronous routing into our application and take advantage of loading
 | |
|   feature areas _lazily_. This buys us multiple things:
 | |
| 
 | |
|   * We can continue building out feature areas without increasing our initial bundle.
 | |
|   * We can load feature areas only when requested by the user.
 | |
|   * We can speed up load time for users that only visit certain areas of our application.
 | |
| 
 | |
|   These are all things we want to have in our application, so let's apply this to our current setup. We've already made
 | |
|   great strides by organizing our application into four modules: `AppModule`, `HeroesModule`, `AdminModule` and `CrisisCenterModule`.
 | |
|   Our `AdminModule` is the area of our application that would be scoped to a small set of users, so we'll take advantage
 | |
|   of asynchronous routing and only load the `Admin` feature area when requested.
 | |
| 
 | |
| :marked
 | |
|   ### Lazy-Loading route configuration
 | |
| 
 | |
|   We'll start by adding an `admin` route to our `app-routing.module.ts` file. We want to load our `Admin` module asynchronously,
 | |
|   so we'll use the `loadChildren` property in our route config where previously we used the `children` property to include our child routes.
 | |
| 
 | |
|   We'll also change our `admin` **path** in our `admin-routing.module.ts` to an empty path. The `Router` supports
 | |
|   *empty path* routes, which we can use for grouping routes together without adding anything additional paths to the URL. Our
 | |
|   users will still visit `/admin` and our `AdminComponent` still serves as our *Routing Component* which contains
 | |
|   our child routes.
 | |
| 
 | |
| +makeTabs(
 | |
|   `router/ts/app/app-routing.module.5.ts,
 | |
|   router/ts/app/admin/admin-routing.module.ts`,
 | |
|   'lazy-load-admin,',
 | |
|   `app-routing.module.ts (load children),
 | |
|   app/admin/admin-routing.module.ts (empty path admin)
 | |
|   `)
 | |
| 
 | |
| :marked
 | |
|   The `loadChildren` property is used by the `Router` to map to our bundle we want to lazy-load, in this case being the `AdminModule`.
 | |
| 
 | |
|   If we look closer at the `loadChildren` string, we can see that it maps directly to our `admin.module.ts` file where we previously built
 | |
|   out our `Admin` feature area. After the path to the file we use a `#` to denote where our file path ends and to tell the `Router` the name
 | |
|   of our `AdminModule`. If we look in our `admin.module.ts` file, we can see it matches name of our exported module class.
 | |
| 
 | |
| +makeExcerpt('app/admin/admin.module.ts (export)', 'admin-module-export')
 | |
| 
 | |
| :marked
 | |
|   The `loadChildren` property is used by the `Router` to map to our bundle we want to lazy-load, in this case being the `AdminModule`.
 | |
|   The router will take our loadChildren string and dynamically load in our `AdminModule`, add its routes to our configuration *dynamically*
 | |
|   and then load the requested route. This will only happen when the route is **first** requested and the module will be immediately be available
 | |
|   for subsequent requests.
 | |
| 
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Angular provides a built-in module loader that supports **`SystemJS`** to load modules asynchronously. If we were
 | |
|     using another bundling tool, such as **Webpack**, we would use the Webpack mechanism for asynchronously loading modules.
 | |
| 
 | |
| :marked
 | |
|   We've built our feature area, we've updated our route configuration to take advantage of lazy-loading, now we have to do the final step
 | |
|   to break our `AdminModule` into a completely separate module. In our `app.module.ts`, we'll remove our `AdminModule` from the
 | |
|   `imports` array since we'll be loading it on-demand an we'll remove the imported `AdminModule`.
 | |
| 
 | |
| +makeExcerpt('app/app.module.7.ts (async admin module)', '')
 | |
| 
 | |
| h3#can-load-guard <i>CanLoad Guard</i>: guarding against loading of feature modules
 | |
| :marked
 | |
|   We're already protecting our `AdminModule` with a `CanActivate` guard that prevents the user from
 | |
|   accessing the admin feature area unless authorized. We're currently loading the admin routing
 | |
|   asynchronously when requested, checking the user access and redirecting to the login page if not
 | |
|   authorized. Ideally, we only want to load the `AdminModule` if the user is logged in and prevent
 | |
|   the `AdminModule` and its routing from being loaded until then.
 | |
| 
 | |
|   The **CanLoad** guard covers this scenario.
 | |
| 
 | |
|   We can use the `CanLoad` guard to only load the `AdminModule` once the user is logged in **and** attempts
 | |
|   to access the admin feature area. We'll update our existing `AuthGuard` to support the `CanLoad` guard. We'll import
 | |
|   the `CanLoad` interface and the `Route` the guard provides when called that contains the requested path.
 | |
| 
 | |
|   We'll add the interface to our service, and then we'll implement the interface. Since our `AuthGuard` already
 | |
|   checks the user's logged in state, we can pass that access check to our `canLoad` method. The `Route` in
 | |
|   the `canLoad` method provides a **path** which comes from our route configuration.
 | |
| 
 | |
| +makeExcerpt('app/auth-guard.service.ts (can load guard)', '')
 | |
| 
 | |
| :marked
 | |
|   Next, we'll import the `AuthGuard` into our `app-routing.module.ts` and add the `AuthGuard` to the `canLoad` array for
 | |
|   our `admin` route. Now our `admin` feature area is only loaded when the proper access has been granted.
 | |
| 
 | |
| +makeExcerpt('app/app-routing.module.5.ts (can load guard)', 'can-load-guard')
 | |
| 
 | |
| h3#preloading <i>Pre-Loading</i>: background loading of feature areas
 | |
| :marked
 | |
|   We've learned how to load modules on-demand, but we can also take advantage of loading feature areas modules in *advance*. The *Router*
 | |
|   supports **pre-loading** of asynchronous feature areas prior to navigation to their respective URL. Pre-loading allows us to to load our initial route
 | |
|   quickly, while other feature modules are loaded in the background. Once we navigate to those areas, they will have already been loaded
 | |
|   as if they were included in our initial bundle.
 | |
| 
 | |
|   Each time a **successful** navigation happens, the *Router* will look through our configuration for lazy loaded feature areas
 | |
|   and react based on the provided strategy.
 | |
| 
 | |
|   The *Router* supports two pre-loading strategies by default:
 | |
| 
 | |
|   * No pre-loading at all which is the default. Lazy loaded feature areas are still loaded on demand.
 | |
|   * Pre-loading of all lazy loaded feature areas.
 | |
| 
 | |
|   The *Router* also supports [custom preloading strategies](#custom-preloading) for fine control over which modules to pre-load.
 | |
| 
 | |
|   We'll update our *CrisisCenterModule* to be loaded lazily by default and use the `PreloadAllModules` strategy 
 | |
|   to load _all_ lazy loaded modules as soon as possible.
 | |
| 
 | |
| <a id="preload-canload"></a>
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     The **PreloadAllModules** strategy does not load feature areas protected by a [CanLoad](#can-load-guard) guard and this is by design.
 | |
|     The *CanLoad* guard blocks loading of feature module assets until authorized to do so. If you want to both preload a module and guard
 | |
|     against unauthorized access, use the [CanActivate](#can-activate-guard) guard instead.
 | |
| 
 | |
| :marked
 | |
|   We'll update our route configuration to lazy load the *CrisisCenterModule*. We follow the same process as we did when we loaded the *AdminModule* asynchronously.
 | |
|   In the *crisis-center-routing.module.ts*, we'll change the *crisis-center* path to an *empty path* route.
 | |
| 
 | |
|   We'll move our redirect and *crisis-center* route to our `AppRoutingModule` routes and use the `loadChildren` string to load the *CrisisCenterModule*.
 | |
|   The redirect is also changed to load the `/heroes` route on initial load.
 | |
| 
 | |
|   Once we're finished, we'll remove the `CrisisCenterModule` from our `AppModule`'s imports.
 | |
| 
 | |
|   Here are the updated modules _before enabling preload_:
 | |
| 
 | |
| +makeTabs(
 | |
|    `router/ts/app/app.module.ts,
 | |
|     router/ts/app/app-routing.module.6.ts,
 | |
|     router/ts/app/crisis-center/crisis-center-routing.module.ts
 | |
|   `,
 | |
|   ',preload-v1,',
 | |
|    `app.module.ts,
 | |
|     app-routing.module.ts,
 | |
|     crisis-center-routing.module.ts
 | |
|   `)
 | |
| 
 | |
| :marked
 | |
|   The second argument in the `RouterModule.forRoot` method takes an object for additional configuration options. 
 | |
|   We import the `PreloadAllModules` token from the router package and set the configuration option's `preloadingStrategy` property
 | |
|   with this `PreloadAllModules` token. 
 | |
|   This tells the built-in *Router* pre-loader to immediately load **all** [unguarded](#preload-canload) feature areas that use `loadChildren`.
 | |
| 
 | |
| +makeExcerpt('app/app-routing.module.6.ts (preload all)', '')
 | |
| 
 | |
| :marked
 | |
|   Now when we visit `http://localhost:3000`, the `/heroes` route will load in the foreground, while the *CrisisCenterModule* and any other asynchronous feature
 | |
|   modules are _eagerly_ loaded in the background, waiting for us to navigate to them.
 | |
| 
 | |
| <a id="custom-preloading"></a>
 | |
| :marked
 | |
|   ### Custom Pre-Loading Strategy
 | |
| 
 | |
|   Pre-loading all modules works well in some situations, but in some cases we need more control over what gets loaded eagerly. This becomes more clear
 | |
|   as we load our application on a mobile device, or a low bandwidth connection. We may only want to preload certain feature modules based on user metrics
 | |
|   or other data points we gather over time. The *Router* lets us have more control with a **custom** preloading strategy.
 | |
| 
 | |
|   We can define our own strategy the same way the **PreloadAllModules** modules strategy was provided to our *RouterModule.forRoot* configuration object.
 | |
| 
 | |
|   Since we want to take advantage of this, we'll add a custom strategy that _only_ preloads the modules we select. We'll enable the preloading by using the *Route Data*,
 | |
|   which, as we learned, is an object to store arbitrary route data and and [resolve data](#resolve-guard).
 | |
| 
 | |
|   We'll add a custom `preload` boolean to our `crisis-center` route data that we'll use with our custom strategy. To see it in action, we'll add 
 | |
|   the `route.path` to the `preloadedModules` array in our custom strategy service. We'll also log a message
 | |
|   to the console for the preloaded module.
 | |
| 
 | |
| +makeExcerpt('app/app-routing.module.ts (route data preload)', 'preload-v2')
 | |
| 
 | |
| :marked
 | |
|   To create our custom strategy we'll need to implement the abstract `PreloadingStrategy` class and the `preload` method. The `preload` method is called for each route
 | |
|   that loads its feature module asynchronously and determines whether to preload it. The `preload` method takes two arguments, the first being the `Route` that provides
 | |
|   the route configuration and a function that preloads the feature module.
 | |
| 
 | |
|   We'll name our strategy **PreloadSelectedModules** since we _only_ want to preload based on certain criteria. Our custom strategy looks for the **`preload`** boolean
 | |
|   value in our `Route Data` and if its true, it calls the `load` function provided by the built-in `Router` pre-loader that eagerly loads feature modules.
 | |
| 
 | |
| +makeExcerpt('app/selective-preload-strategy.ts (preload selected modules)', '')
 | |
| 
 | |
| :marked
 | |
|   In order to use our custom preloading strategy, we import it into our `app-routing.module.ts` and replace the `PreloadAllModules` strategy. We also add
 | |
|   the `PreloadSelectedModules` strategy to the `AppRoutingModule` providers array. This allows the *Router* pre-loader to inject our custom strategy.
 | |
| 
 | |
|   To confirm our *CrisisCenterModule* is being pre-loaded, we'll display our `preloadedModules` in the `Admin` dashboard. We already know how to use
 | |
|   an *ngFor* loop, so we'll skip over the details here. Since the `PreloadSelectedModules` is just a service, we can inject it into the `AdminDashboardComponent`
 | |
|   and wire it up to our list.
 | |
| 
 | |
| +makeExcerpt('app/admin/admin-dashboard.component.ts (preloaded modules)', '')
 | |
| 
 | |
| :marked
 | |
|   Once our application is loaded to our initial route, the *CrisisCenterModule* is loaded eagerly. We can verify this by logging in to the `Admin` feature area and
 | |
|   noting that the `crisis-center` is listed in the `Preloaded Modules` and logged to the console. We can continue to add feature modules to be selectively loaded eagerly.
 | |
| 
 | |
| 
 | |
| <a id="final-app"></a>
 | |
| .l-main-section
 | |
| :marked
 | |
|   ## Wrap Up
 | |
|   We've covered a lot of ground in this chapter and the application is too big to reprint here.
 | |
|   Please visit the <live-example></live-example> and
 | |
|   where you can download the final source code.
 | |
| 
 | |
| .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.
 | |
| 
 | |
|   The appendix material isn't essential. Continued reading is for the curious.
 | |
| 
 | |
| .l-main-section#link-parameters-array
 | |
| :marked
 | |
|   ## Appendix: Link Parameters Array
 | |
| 
 | |
|   We've mentioned the *Link Parameters Array* several times. We've used it several times.
 | |
| 
 | |
|   A link parameters array holds the ingredients for router navigation:
 | |
|   * the *path* of the route to the destination component
 | |
|   * required and optional route parameters that go into the route URL
 | |
| 
 | |
|   We can bind the `RouterLink` directive to such an array like this:
 | |
| 
 | |
| +makeExcerpt('app/app.component.3.ts', 'h-anchor', '')
 | |
| 
 | |
| :marked
 | |
|   We've written a two element array when specifying a route parameter like this
 | |
| 
 | |
| +makeExcerpt('app/heroes/hero-list.component.1.ts', 'nav-to-detail', '')
 | |
| 
 | |
| :marked
 | |
|   We can provide optional route parameters in an object like this:
 | |
| 
 | |
| +makeExcerpt('app/app.component.3.ts', 'cc-query-params', '')
 | |
| 
 | |
| :marked
 | |
|   These three 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.
 | |
| 
 | |
|   Recall that we specified a default child route for *Crisis Center* so this simple `RouterLink` is fine.
 | |
| 
 | |
| +makeExcerpt('app/app.component.3.ts', 'cc-anchor-w-default', '')
 | |
| 
 | |
| :marked
 | |
|   Let's parse it out.
 | |
|   * The first item in the array identifies the parent route ('/crisis-center').
 | |
|   * There are no parameters for this parent route so we're done with it.
 | |
|   * There is no default for the child route so we need to pick one.
 | |
|   * We decide to go to the `CrisisListComponent` whose route path is '/' but we don't need to explicitly add it
 | |
|   * Voila! `['/crisis-center']`.
 | |
| 
 | |
|   Let's take it a step further.
 | |
|   This time we'll build a link parameters array that navigates from the root of the application
 | |
|   down to the "Dragon Crisis".
 | |
| 
 | |
|   * The first item in the array identifies the parent route ('/crisis-center').
 | |
|   * 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 ('/:id').
 | |
|   * The details child route requires an `id` route parameter
 | |
|   * We add `id` of the *Dragon Crisis* as the second item in the array (`1`)
 | |
| 
 | |
|   It looks like this!
 | |
| 
 | |
| +makeExcerpt('app/app.component.3.ts', 'Dragon-anchor', '')
 | |
| 
 | |
| :marked
 | |
|   If we wanted to, we could redefine our `AppComponent` template with *Crisis Center* routes exclusively:
 | |
| 
 | |
| +makeExcerpt('app/app.component.3.ts', 'template', '')
 | |
| 
 | |
| :marked
 | |
|   In sum, we can write applications with one, two or more levels of routing.
 | |
|   The link parameters array affords the flexibility to represent any routing depth and
 | |
|   any legal sequence of route paths, (required) router parameters and (optional) route parameter objects.
 | |
| 
 | |
| .l-main-section#onInit
 | |
| :marked
 | |
|   ## Appendix: Why use an *ngOnInit* method
 | |
| 
 | |
|   We implemented an `ngOnInit` method in many of our Component classes.
 | |
|   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*.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   The better practice is to limit what the constructor can do. Mostly it should stash parameters in
 | |
|   local variables and perform simple instance configuration.
 | |
| 
 | |
|   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?
 | |
| 
 | |
|   Angular detects when a component has certain lifecycle methods like
 | |
|   [ngOnInit](../api/core/index/OnInit-class.html) and
 | |
|   [ngOnDestroy](../api/core/index/OnDestroy-class.html) and calls
 | |
|   them
 | |
|   at the appropriate moment.
 | |
| 
 | |
|   Angular will call `ngOnInit` when we navigate to the `HeroDetailComponent`, we'll get the `id` from the `ActivatedRoute`
 | |
|   params and ask the server for the hero with that `id`.
 | |
| 
 | |
|   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#browser-url-styles
 | |
| .l-main-section#location-strategy
 | |
| :marked
 | |
|   ## Appendix: *LocationStrategy* and browser URL styles
 | |
| 
 | |
|   When the router navigates to a new component view, it updates the browser's location and history
 | |
|   with a URL for that view.
 | |
|   This is a strictly local URL. The browser shouldn't send this URL to the server
 | |
|   and should not reload the page.
 | |
| 
 | |
|   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.
 | |
|   The router can compose a "natural" URL that is indistinguishable from
 | |
|   one that would otherwise require a page load.
 | |
| 
 | |
|   Here's the *Crisis Center* URL in this "HTML 5 pushState" style:
 | |
| code-example(format=".", language="bash").
 | |
|   localhost:3002/crisis-center/
 | |
| :marked
 | |
|   Older browsers send page requests to the server when the location URL changes ...
 | |
|   unless the change occurs after a "#" (called the "hash").
 | |
|   Routers can take advantage of this exception by composing in-application route
 | |
|   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
 | |
|   The Router supports both styles with two `LocationStrategy` providers:
 | |
|   1. `PathLocationStrategy` - the default "HTML 5 pushState" style.
 | |
|   1. `HashLocationStrategy` - the "hash URL" style.
 | |
| 
 | |
|   The `RouterModule.forRoot` function 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.
 | |
| .l-sub-section
 | |
|   :marked
 | |
|     Learn about "providers" and the bootstrap process in the
 | |
|     [Dependency Injection chapter](dependency-injection.html#bootstrap)
 | |
| :marked
 | |
|   ### Which Strategy is Best?
 | |
|   We must choose a strategy and we need to make the right call early in the project.
 | |
|   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.
 | |
| 
 | |
|   Almost all Angular 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.
 | |
| 
 | |
|   Rendering critical pages on the server is a technique that can greatly improve
 | |
|   perceived responsiveness when the app first loads.
 | |
|   An app that would otherwise take ten or more seconds to start
 | |
|   could be rendered on the server and delivered to the user's device
 | |
|   in less than a second.
 | |
| 
 | |
|   This option is only available if application URLs look like normal web URLs
 | |
|   without hashes (#) in the middle.
 | |
| 
 | |
|   Stick with the default unless you have a compelling reason to
 | |
|   resort to hash routes.
 | |
| 
 | |
|   ### HTML 5 URLs and the  *<base href>*
 | |
|   While the router uses the "[HTML 5 pushState](https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries)"
 | |
|   style by default, we *must* configure that strategy with a **base href**
 | |
| 
 | |
|   The preferred way to configure the strategy is to add a
 | |
|   [<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag
 | |
|   in the `<head>` of the `index.html`.
 | |
| 
 | |
| +makeExcerpt('index.1.html', 'base-href', '')
 | |
| 
 | |
| :marked
 | |
|   Without that tag, the browser may not be able to load resources
 | |
|   (images, css, scripts) when "deep linking" into the app.
 | |
|   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.
 | |
| 
 | |
|   Some developers may not be able to add the `<base>` element, perhaps because they don't have
 | |
|   access to `<head>` or the `index.html`.
 | |
| 
 | |
|   Those developers may still use HTML 5 URLs by taking two remedial steps:
 | |
| 
 | |
|   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
 | |
|     Learn about the [APP_BASE_HREF](../api/common/index/APP_BASE_HREF-let.html)
 | |
|     in the API Guide.
 | |
| :marked
 | |
|   ### *HashLocationStrategy*
 | |
|   We can go old-school with the `HashLocationStrategy` by
 | |
|   providing the `useHash: true` in an object as the second argument of the `RouterModule.forRoot`
 | |
|   in our `AppModule`.
 | |
| 
 | |
| +makeExcerpt('app/app.module.6.ts (hash URL strategy)', '')
 |