<ahref="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries"target="_blank"title="HTML5 browser history push-state">history.pushState</a>
for navigation. Thanks to `pushState`, you can make in-app URL paths look the way you want them to
look, e.g. `localhost:3000/crisis-center`. The 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.
HTML 5 style navigation is the router default.
In the [Browser URL Styles](#browser-url-styles) Appendix,
learn why HTML 5 style is preferred, how to adjust its behavior, and how to switch to the
The corresponding component template looks like this:
{@a router-outlet}
### *RouterOutlet*
The `RouterOutlet` is a directive from the router library that marks
the spot in the template where the router should display the views for that outlet.
The router adds the `<router-outlet>` element to the DOM
and subsequently inserts the navigated view element
immediately _after_ the `<router-outlet>`.
{@a router-link}
### *RouterLink* binding
Above the outlet, within the anchor tags, you see
[attribute bindings](template-syntax.html#attribute-binding) to
the `RouterLink` directive that look like `routerLink="..."`.
The links in this example each have a string path, the path of a route that
you configured earlier. There are no route parameters yet.
You can also add more contextual information to the `RouterLink` by providing query string parameters
or a URL fragment for jumping to different areas on the 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.
Learn about the how you can also use the _link parameters array_ in the [appendix below](#link-parameters-array).
{@a router-link-active}
### *RouterLinkActive* binding
On each anchor tag, you 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 a space-delimited string of CSS classes
that the Router will add when this link is active (and remove when the link is inactive).
You can also set the `RouterLinkActive` directive to a string of classes such as `[routerLinkActive]="active fluffy"`
or bind it to a component property that returns such a string.
The `RouterLinkActive` directive toggles css classes for active `RouterLink`s based on the current `RouterState`.
This cascades down through each level of the route tree, so parent and child router links can be active at the same time.
To override this behavior, you 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.
{@a router-directives}
### *Router directives*
`RouterLink`, `RouterLinkActive` and `RouterOutlet` are directives provided by the Angular `RouterModule` package.
They are readily available for you to use in the template.
The current state of `app.component.ts` looks like this:
### Wildcard route
You've created two routes in the app so far, one to `/crisis-center` and the other to `/heroes`.
Any other URL causes the router to throw an error and crash the app.
Add a **wildcard** route to intercept invalid URLs and handle them gracefully.
A _wildcard_ route has a path consisting of two asterisks. It matches _every_ URL.
The router will select _this_ route if it can't match a route earlier in the configuration.
A wildcard route can navigate to a custom "404 Not Found" component or [redirect](#redirect) to an existing route.
The router selects the route with a [_first match wins_](#example-config) strategy.
Wildcard routes are the least specific routes in the route configuration.
Be sure it is the _last_ route in the configuration.
To test this feature, add a button with a `RouterLink` to the `HeroListComponent` template and set the link to `"/sidekicks"`. The application will fail if the user clicks that button because you haven't defined a `"/sidekicks"` route yet.
Instead of adding the `"/sidekicks"` route, define a `wildcard` route instead and have it navigate to a simple `PageNotFoundComponent`.Create the `PageNotFoundComponent` to display when users visit invalid URLs.As with the other components, add the `PageNotFoundComponent` to the `AppModule` declarations.
Now when the user visits `/sidekicks`, or any other invalid URL, the browser displays the "Page not found".
The browser address bar continues to point to the invalid URL.
{@a default-route}
### The _default_ route to heroes
When the application launches, the initial URL in the browser bar is something like:
<code-example>
localhost:3000
</code-example>
That doesn't match any of the configured routes which means that the application won't display any component when it's launched.
The user must click one of the links to trigger a navigation and display a component.
It would be nicer if the application had a **default route** that displayed the list of heroes immediately,
just as it will when the user clicks the "Heroes" link or pastes `localhost:3000/heroes` into the address bar.
{@a redirect}
### Redirecting routes
The preferred solution is to add a `redirect` route that translates the initial relative URL (`''`)
to the desired default path (`/heroes`). The browser address bar shows `.../heroes` as if you'd navigated there directly.
Add the default route somewhere _above_ the wildcard route.
It's just above the wildcard route in the following excerpt showing the complete `appRoutes` for this milestone.
A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route.
The router throws an error if you don't.
In this app, the router should select the route to the `HeroListComponent` only when the *entire URL* matches `''`,
so set the `pathMatch` value to `'full'`.
Technically, `pathMatch = 'full'` results in a route hit when the *remaining*, unmatched segments of the URL match `''`.
In this example, the redirect is in a top level route 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.
Don't do that here.
If the `pathMatch` value were `'prefix'`, _every_ URL would match `''`.
Try setting it to `'prefix'` then click the `Go to sidekicks` button.
Remember that's a bad URL and you should see the "Page not found" page.
Instead, you're still on the "Heroes" page.
Enter a bad URL in the browser address bar.
You're instantly re-routed to `/heroes`.
_Every_ URL, good or bad, that falls through to _this_ route definition
will be a match.
The default route should redirect to the `HeroListComponent`_only_ when the _entire_ url is `''`.
Remember to restore the redirect to `pathMatch = 'full'`.
Learn more in Victor Savkin's
[post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes).
A future update to this guide will cover redirects in more detail.### "Getting Started" wrap-up
You've got a very basic, navigating app, one that can switch between two views
when the user clicks a link.
You'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
* handle invalid routes with a `wildcard` route
* navigate to the default route when the app launches with an empty path
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.
It has a great deal of useful information including:
**`url`**: An `Observable` of the route path(s), represented 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.
Import the `Router`, `ActivatedRoute`, and `Params` tokens from the router package.
Import the `switchMap` operator because you need it later to process the `Observable` route parameters.
{@a hero-detail-ctor}
As usual, you write a constructor that asks Angular to inject services
that the component requires and reference them as private variables.
Later, in the `ngOnInit` method, you use the `ActivatedRoute` service to retrieve the parameters for the route,
pull the hero `id` from the parameters and retrieve the hero to display.
Put this data access logic in the `ngOnInit` method rather than inside the constructor to improve the component's testability.
Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`
so the hero will be retrieved in time to use it.
Learn more about the `ngOnInit` method and other component lifecycle hooks in the [Lifecycle Hooks](lifecycle-hooks.html) guide.
Since the parameters are provided as an `Observable`, you use the _switchMap_ operator to
provide them for the `id` parameter by name and tell the `HeroService` to fetch the hero with that `id`.
The `switchMap` operator allows you to perform an action with the current value of the `Observable`,
and map it to a new `Observable`. As with many `rxjs` operators, `switchMap` handles
an `Observable` as well as a `Promise` to retrieve the value they emit.
The `switchMap` operator will also cancel any in-flight requests if the user re-navigates to the route
while still retrieving a hero.
Use the `subscribe` method to detect `id` changes and to (re)set the retrieved `Hero`.
<h4id='reuse'>
Observable <i>params</i> and component re-use
</h4>
In this example, you 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 re-uses a component instance when it re-navigates to the same component type
without visiting a different component first. The route parameters could change each time.
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`.
You 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.
Unfortunately, `ngOnInit` is only called once per component instantiation.
You need a way to detect when the route parameters change from _within the same instance_.
The observable `params` property handles that beautifully.
When subscribing to an observable in a component, you almost always arrange to unsubscribe when the component is destroyed.
There are a few exceptional observables where this is not necessary.
The `ActivatedRoute` observables are among the exceptions.
The `ActivatedRoute` and its observables are insulated from the `Router` itself.
The `Router` destroys a routed component when it is no longer needed and the injected `ActivatedRoute` dies with it.
Feel free to unsubscribe anyway. It is harmless and never a bad practice.
{@a snapshot}
#### _Snapshot_: the _no-observable_ alternative
_This_ application won't re-use the `HeroDetailComponent`.
The user always returns to the hero list to select another hero to view.
There's no way to navigate from one hero detail to another hero detail
without visiting the list component in between.
Therefore, the router creates a new `HeroDetailComponent` instance every time.
When you know for certain that a `HeroDetailComponent` instance will *never, never, ever*
be re-used, you can simplify the code with the *snapshot*.
The `route.snapshot` provides the initial value of the route parameters.
You can access the parameters directly without subscribing or adding observable operators.
It's much simpler to write and read:
**Remember:** you only get the _initial_ value of the parameters with this technique.
Stick with the observable `params` approach if there's even a chance that the router
could re-use the component.
This sample stays with the observable `params` strategy just in case.
{@a nav-to-list}
### 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 you can bind to a `[routerLink]` directive.
It holds the _path to the `HeroListComponent`_:
### Route Parameters: Required or optional?
Use [*route parameters*](#route-parameters) to specify a *required* parameter value *within* the route URL
as you do when navigating to the `HeroDetailComponent` in order to view the hero with *id* 15:
<code-exampleformat="nocode">
localhost:3000/hero/15
</code-example>
You can also add *optional* information to a route request.
For example, when returning to the heroes list from the hero detail view,
it would be nice if the viewed hero was preselected in the list.
You'll implement this feature in a moment by including the viewed hero's `id`
in the URL as an optional parameter when returning from the `HeroDetailComponent`.
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 you 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 flexibility of expression.
The router supports navigation with optional parameters as well as required route parameters.
Define _optional_ parameters in a separate object _after_ you define the required route parameters.
In general, prefer a *required route parameter* when
the value is mandatory (for example, if necessary to distinguish one route path from another);
prefer an *optional parameter* when the value is optional, complex, and/or multi-variate.
### Heroes list: optionally selecting a hero
When navigating to the `HeroDetailComponent` you 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).
The router embedded the `id` value in the navigation URL because you had defined it
as a route parameter with an `:id` placeholder token in the route `path`:
When the user clicks the back button, the `HeroDetailComponent` constructs another _link parameters array_
which it uses to navigate back to the `HeroListComponent`.
This array lacks a route parameter because you had no reason to send information to the `HeroListComponent`.
Now you have a reason. You'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.
Send the `id` with an object that contains an _optional_`id` parameter.
For demonstration purposes, there's an extra junk parameter (`foo`) in the object that the `HeroListComponent` should ignore.
Here's the revised navigation statement:
The application still works. Clicking "back" returns to the hero list view.
Look at the browser address bar.
It should look something like this, depending on where you run it:
<code-examplelanguage="bash">
localhost:3000/heroes;id=15;foo=foo
</code-example>
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 you may not have seen before.
*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 you 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.
### Route parameters in the *ActivatedRoute* service
The list of heroes is unchanged. No hero row is highlighted.
The <live-example></live-example>*does* highlight the selected
row because it demonstrates the final state of the application which includes the steps you're *about* to cover.
At the moment you're describing the state of affairs *prior* to those steps.The `HeroListComponent` isn't expecting any parameters at all and wouldn't know what to do with them.
You can change that.
Previously, when navigating from the `HeroListComponent` to the `HeroDetailComponent`,
you subscribed to the route params `Observable` and made it available to the `HeroDetailComponent`
in the `ActivatedRoute` service.
You injected that service in the constructor of the `HeroDetailComponent`.
This time you'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`.
First you extend the router import statement to include the `ActivatedRoute` service symbol;
Import the `switchMap` operator to perform an operation on the `Observable` of route parameters.
Then you inject the `ActivatedRoute` in the `HeroListComponent` constructor.
The ActivatedRoute.params property is an Observable of route parameters. The params emits new id values
when the user navigates to the component. In ngOnInit you subscribe to those values, set the selectedId,
and get the heroes.
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.Add an `isSelected` method that returns true when a hero's id matches the selected id.
Finally, you update the 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:
When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
The optional `foo` route parameter is harmless and continues to be ignored.
<h3id='route-animation'>
Adding animations to the routed component
</h3>
The heroes feature module is almost complete, but what is a feature without some smooth transitions?
In this section you'll add some [animations](../guide/animations.html) to the *Hero Detail* component.
Create an `animations.ts` file in the root `src/app/` folder. The contents look like this:This file does the following:
* Imports the animation symbols that build the animation triggers, control state, and manage transitions between states.
* Exports a constant named `slideInDownAnimation` set to an animation trigger named *routeAnimation*;
animated components will refer to this name.
* Specifies the _wildcard state_ that matches any animation state that the route component is in.
* Defines two *transitions*, one to ease the component in from the left of the screen as it enters the application view (`:enter`),
the other to animate the component down as it leaves the application view (`:leave`).
You could create more triggers with different transitions for other route components. This trigger is sufficient for the current milestone.
Back in the `HeroDetailComponent`, import the `slideInDownAnimation` from `'./animations.ts`.
Add the `HostBinding` decorator to the imports from `@angular/core`; you'll need it in a moment.
Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`.
Then add three `@HostBinding` properties to the class to set the animation and styles for the route component's element.The `'@routeAnimation'` passed to the first `@HostBinding` matches the name of the `slideInDownAnimation`_trigger_.
Set the `routeAnimation` property to `true` because you only care about the `:enter` and `:leave` states.
The other two `@HostBinding` properties style the display and position of the component.
The `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away.
Applying route animations to individual components is something you'd rather not do throughout the entire application.
It would be better to animate routes based on _route paths_, a topic to cover in a future update to this guide.
### Milestone 3 wrap-up
You've learned how to
* organize the app into *feature areas*
* navigate imperatively from one component to another
* pass information along in route parameters and subscribe to them in the component
* import the feature area NgModule into the `AppModule`
* apply animations to the route component
After these changes, the folder structure looks like this:
- Copy the files from `!{_appDir}/heroes` into the new crisis center folder, but
- Change every mention of "hero" to "crisis", and "heroes" to "crises".
You'll turn the `CrisisService` into a purveyor of mock crises instead of mock heroes:
The resulting crisis center is a foundation for introducing a new concept —**child routing**.
You can leave *Heroes* in its current state as a contrast with the *Crisis Center*
and decide later if the differences are worthwhile.
~~~ {.alert.is-helpful}
In keeping with the
<ahref="https://blog.8thlight.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html"target="_blank"title="Separation of Concerns">*Separation of Concerns* principle</a>,
changes to the *Crisis Center* won't affect the `!{_AppModuleVsAppComp}` or
any other feature's component.
~~~
### A Crisis center with child routes
You'll organize the crisis center to conform to the following recommended pattern for Angular applications:
* Each feature area resides in its own folder
* Each feature has its own Angular feature module.
* Each area has its own area root component.
* Each area root component has its own router outlet and child routes.
* Feature area routes rarely (if ever) cross with routes of other features.
If your app had many feature areas, the app component trees might look like this:
The absolute URL for the latter example, including the `localhost` origin, is
<code-example>
localhost:3000/crisis-center/2
</code-example>
Here's the complete `crisis-center-routing.module.ts` file with its imports.
{@a import-crisis-module}
### Import crisis center module into the *AppModule* routes
As with the `HeroesModule`, you must add the `CrisisCenterModule` to the `imports` array of the `AppModule`
_before_ the `AppRoutingModule`:
Remove the initial crisis center route from the `app-routing.module.ts`.
The feature routes are now provided by the `HeroesModule` and the `CrisisCenter` modules.
The `app-routing.module.ts` file retains the top-level application routes such as the default and wildcard routes.
{@a relative-navigation}
### Relative navigation
While building out the crisis center feature, you navigated to the
crisis detail route using an **absolute path** that begins with a _slash_.
The router matches such _absolute_ paths to routes starting from the top of the route configuration.
You could continue to use absolute paths like this to navigate inside the *Crisis Center*
feature, but that pins the links to the parent routing structure.
If you changed the parent `/crisis-center` path, you would have to change the link parameters array.
You can free the links from this dependency by defining paths that are **relative** to the current URL segment.
Navigation _within_ the feature area remains intact even if you change the parent route path to the feature.
Here's an example
The router supports directory-like syntax in a _link parameters list_ to help guide route name lookup:
`./` or `no leading slash` is relative to the current level.
`../` to go up one level in the route path.
You can combine relative navigation syntax with an ancestor path.
If you must navigate to a sibling route, you could use the `../<sibling>` convention to go up
one level, then over and down the sibling route path.
To navigate a relative path with the `Router.navigate` method, you must supply the `ActivatedRoute`
to give the router knowledge of where you are in the current route tree.
After the _link parameters array_, add an object with a `relativeTo` property set to the `ActivatedRoute`.
The router then calculates the target URL based on the active route's location.
**Always** specify the complete _absolute_ path when calling router's `navigateByUrl` method.
### Navigate to crisis detail with a relative URL
Update the *Crisis List*`onSelect` method to use relative navigation so you don't have
to start from the top of the route configuration.
You've already injected the `ActivatedRoute` that you need to compose the relative navigation path.When you visit the *Crisis Center*, the ancestor path is `/crisis-center`,
so you only need to add the `id` of the *Crisis Center* to the existing path.
If you were using a `RouterLink` to navigate instead of the `Router` service, you'd use the _same_
link parameters array, but you wouldn't provide the object with the `relativeTo` property.
The `ActivatedRoute` is implicit in a `RouterLink` directive.
Update the `gotoCrises` method of the `CrisisDetailComponent` to navigate back to the *Crisis Center* list using relative path navigation.
Notice that the path goes up a level (`../`) syntax.
If the current crisis `id` is `3`, the resulting path back to the crisis list is `/crisis-center/;id=3;foo=foo`.
{@a named-outlets}
### Displaying multiple routes in named outlets
You decide to give users a way to contact the crisis center.
When a user clicks a "Contact" button, you want to display a message in a popup view.
The popup should stay open, even when switching between pages in the application, until the user closes it
by sending the message or canceling.
Clearly you can't put the popup in the same outlet as the other pages.
Until now, you've defined a single outlet and you've nested child routes
under that outlet to group routes together.
The router only supports one primary _unnamed_ outlet per template,
A template can also have any number of _named_ outlets.
Each named outlet has its own set of routes with their own components.
Multiple outlets can be displaying different content, determined by different routes, all at the same time.
Add an outlet named "popup" in the `AppComponent`, directly below the unnamed outlet.
That's where a popup will go, once you learn how to route a popup component to it.
{@a secondary-routes}
#### Secondary routes
Named outlets are the targets of _secondary routes_.
Secondary routes look like primary routes and you configure them the same way.
They differ in a few key respects.
* They are independent of each other
* They work in combination with other routes.
* They are displayed in named outlets.
Create a new component named `ComposeMessageComponent` in `src/app/compose-message.component.ts`.
It displays a simple form with a header, an input box for the message,
It looks about the same as any other component you've seen in this guide.
There are two noteworthy differences
Note that the `send` method simulates latency by waiting a second before "sending" the message and closing the popup.
The `closePopup` method closes the popup view by navigating to the "popup" outlet with a `null`.
That's a peculiarity covered [below](#clear-secondary-routes).
As with other application components, you add the `ComposeMessageComponent` to the `declarations` of an `NgModule`.
Do so in the `AppModule`.
#### Add a secondary route
Open the `AppRoutingModule` and add a new `compose` route to the `appRoutes`.The `path` and `component` properties should be familiar.
There's a new property `outlet` set to `'popup'`.
This route now targets the "popup" outlet and the `ComposeMessageComponent` will display there.
The user needs a way to open the popup.
Open the `AppComponent` and add a "Contact" link.Although the `compose` route is pinned to the "popup" outlet, that's not sufficient for wiring the route to a `RouterLink` directive.
You have to specify the named outlet in a _link parameters array_ and bind it to the `RouterLink` with a property binding.
The _link parameters array_ contains an object with a single `outlets` property whose value
is another object keyed by one (or more) outlet names.
In this case there is only the "popup" outlet property and its value is another _link parameters array_ that specifies the `compose` route.
You are in effect saying, _when the user clicks this link, display the component associated with the `compose` route in the `popup` outlet_.
This `outlets` object within an outer object was completely unnecessary
when there was only one route and one _unnamed_ outlet to think about.
The router assumed that your route specification targeted the _unnamed_ primary outlet
and created these objects for you.
Routing to a named outlet has revealed a previously hidden router truth:
you can target multiple outlets with multiple routes in the same `RouterLink` directive.
You're not actually doing that here.
But to target a named outlet, you must use the richer, more verbose syntax.
<h3id='secondary-route-navigation'>
<i>Secondary Route Navigation</i>: merging routes during navigation
</h3>
Navigate to the _Crisis Center_ and click "Contact".
you should see something like the following URL in the browser address bar.
<code-example>
http://.../crisis-center(popup:compose)
</code-example>
The interesting part of the URL follows the `...`:
* The `crisis-center` is the primary navigation.
* Parentheses surround the secondary route.
* The secondary route consist of an outlet name (`popup`), then a `colon` separator, followed with the secondary route path (`compose`)
Click the _Heroes_ link and look at the URL again.
<code-example>
http://.../heroes(popup:compose)
</code-example>
The primary navigation part has changed; the secondary route is the same.
The router is keeping track of two separate branches in a navigation tree and generating a representation of that tree in the URL.
You can add many more outlets and routes, at the top level and in nested levels, creating a navigation tree with many branches.
The router will generate the URL to go with it.
You can tell the router to navigate an entire tree at once by filling out the `outlets` object mentioned above.
Then pass that object inside a _link parameters array_ to the `router.navigate` method.
Experiment with these possibilities at your leisure.
{@a clear-secondary-routes}
#### Clearing secondary routes
As you've learned, a component in an outlet persists until you navigate away to a new component.
Secondary outlets are no different in this regard.
Each secondary outlet has its own navigation, independent of the navigation driving the primary outlet.
Changing a current route that displays in the primary outlet has no effect on the "popup" outlet.
That's why the "popup" stays visible as you navigate among the crises and heroes.
Clicking the "send" or "cancel" buttons _does_ clear the popup view.
To see how, look at the `ComposeMessageComponent.closePopup` method again:
## 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 you should fetch some data before you display the target component.
* You might want to save pending changes before leaving a component.
* You might ask the user if it's OK to discard pending changes rather than save them.
You can add _guards_ to the 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
The guard can also tell the router to navigate elsewhere, effectively canceling the current navigation.
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_.
You 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.
You'll see several examples over the next few sections.
{@a can-activate-guard}
### *CanActivate*: requiring authentication
Applications often restrict access to a feature area based on who the user is.
You could permit access only to authenticated users or to users with a specific role.
You 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
In this next section, you'll extend the crisis center with some new *administrative* features.
Those features aren't defined yet.
But you can start by adding a new feature module named `AdminModule`.
Create an `admin` folder with a feature module file, a routing configuration file, and supporting components.
The admin feature file structure looks like this:
<aio-filetree>
<aio-folder>
src/app/admin
<aio-file>
admin-dashboard.component.ts
</aio-file>
<aio-file>
admin.component.ts
</aio-file>
<aio-file>
admin.module.ts
</aio-file>
<aio-file>
admin-routing.module.ts
</aio-file>
<aio-file>
manage-crises.component.ts
</aio-file>
<aio-file>
manage-heroes.component.ts
</aio-file>
</aio-folder>
</aio-filetree>
The admin feature module contains the `AdminComponent` used for routing within the
feature module, a dashboard route and two unfinished components to manage crises and heroes.
You could try this now and confirm that the `CrisisCenterModule` loads after you click the "Crisis Center" button.
To enable preloading of all lazy loaded modules, import the `PreloadAllModules` token from the Angular router package.
The second argument in the `RouterModule.forRoot` method takes an object for additional configuration options.
The `preloadingStrategy` is one of those options.
Add the `PreloadAllModules` token to the `forRoot` call:This tells the `Router` preloader to immediately load _all_ lazy-loaded routes (routes with a `loadChildren` property).
When you visit `http://localhost:3000`, the `/heroes` route loads immediately upon launch.
and the router starts loading the `CrisisCenterModule` right after the `HeroesModule` loads.
Surprisingly, the `AdminModule` does _not_ preload. Something is blocking it.
{@a preload-canload}
#### CanLoad blocks preload
The `PreloadAllModules` strategy does not load feature areas protected by a [CanLoad](#can-load-guard) guard.
This is by design.
You added a `canLoad` guard to the route to the `AdminModule` a few steps back
to block loading of that module until the user is authorized.
That `canLoad` guard takes precedence over the preload strategy.
If you want both to preload a module and guard against unauthorized access,
drop the `canLoad` guard and rely on the [CanActivate](#can-activate-guard) guard alone.
{@a custom-preloading}
### Custom Preloading Strategy
Preloading every lazy loaded modules works well in many situations,
but it isn't always the right choice, especially on mobile devices and over low bandwidth connections.
You may choose to preload only certain feature modules, based on user metrics and other business and technical factors.
You can control what and how the router preloads with a custom preloading strategy.
In this section, you'll add a custom strategy that _only_ preloads routes whose `data.preload` flag is set to `true`.
Recall that you can add anything to the `data` property of a route.
Set the `data.preload` flag in the `crisis-center` route in the `AppRoutingModule`.
Add a new file to the project called `selective-preloading-strategy.ts`
and define a `SelectivePreloadingStrategy` service class as follows:`SelectivePreloadingStrategy` implements the `PreloadingStrategy`, which has one method, `preload`.
The router calls the `preload` method with two arguments
1. The route to consider.
1. A loader function that can load the routed module asynchronously.
An implementation of `preload`must return an `Observable`.
If the route should preload, it returns the observable returned by calling the loader function.
If the route should _not_ preload, it returns an `Observable` of `null`.
In this sample, the `preload` method loads the route if the route's `data.preload` flag is truthy.
It also has a side-effect.
`SelectivePreloadingStrategy` logs the `path` of a selected route in its public `preloadedModules` array.
Shortly, you'll extend the `AdminDashboardComponent` to inject this service and display its `preloadedModules` array.
But first, make a few changes to the `AppRoutingModule`.
1. Import `SelectivePreloadingStrategy` into `AppRoutingModule`.
1. Replace the `PreloadAllModules` strategy in the call to `forRoot` with this `SelectivePreloadingStrategy`.
1. Add the `SelectivePreloadingStrategy` strategy to the `AppRoutingModule` providers array so it can be injected
elsewhere in the app.
Now edit the `AdminDashboardComponent` to display the log of preloaded routes.
1. Import the `SelectivePreloadingStrategy` (it's a service)
1. Inject it into the dashboard's constructor.
1. Update the template to display the strategy service's `preloadedModules` array.
When you're done it looks like this.
Once the application loads the initial route, the `CrisisCenterModule` is preloaded.
Verify this by logging in to the `Admin` feature area and noting that the `crisis-center` is listed in the `Preloaded Modules`.
It's also logged to the browser's console.
{@a inspect-config}
## Inspect the router's configuration
You put a lot of effort into configuring the router in several routing module files
and were careful to list them [in the proper order](#routing-module-order).
Are routes actually evaluated as you planned?
How is the router really configured?
You can inspect the router's current configuration any time by injecting it and
examining its `config` property.
For example, update the `AppModule` as follows and look in the browser console window
to see the finished route configuration.
{@a final-app}
## Wrap Up
You've covered a lot of ground in this guide and the application is too big to reprint here.
Please visit the <live-exampletitle="Router Sample in Plunker"></live-example> and
where you can download the final source code.
## Appendices
The balance of this guide is a set of appendices that
elaborate some of the points you covered quickly above.
The appendix material isn't essential. Continued reading is for the curious.
## Appendix: Link parameters array
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
You can bind the `RouterLink` directive to such an array like this:
You've written a two element array when specifying a route parameter like this
You can provide optional route parameters in an object like this:
These three examples cover the need for an app with one level routing.
The moment you add a child router, such as the crisis center, you create new link array possibilities.
Recall that you specified a default child route for crisis center so this simple `RouterLink` is fine.
Parse it out.
* The first item in the array identifies the parent route (`/crisis-center`).
* There are no parameters for this parent route so you're done with it.
* There is no default for the child route so you need to pick one.
* You're navigating to the `CrisisListComponent`, whose route path is `/`, but you don't need to explicitly add the slash
* Voila! `['/crisis-center']`.
Take it a step further. Consider the following router link 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 you're done with it.
* The second item identifies the child route details about a particular crisis (`/:id`).
* The details child route requires an `id` route parameter.
* You added the `id` of the *Dragon Crisis* as the second item in the array (`1`).
* The resulting path is `/crisis-center/1`.
If you wanted to, you could redefine the `AppComponent` template with *Crisis Center* routes exclusively:
In sum, you 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.
{@a browser-url-styles}
## 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
<ahref="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries"target="_blank"title="HTML5 browser history push-state">history.pushState</a>,
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-exampleformat="nocode">
localhost:3002/crisis-center/
</code-example>
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-exampleformat="nocode">
localhost:3002/src/#/crisis-center/
</code-example>
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.
You can switch to the `HashLocationStrategy` with an override during the bootstrapping process if you prefer it.
Learn about "providers" and the bootstrap process in the
You must choose a strategy and you 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
<ahref="https://developer.mozilla.org/en-US/docs/Web/API/History_API#Adding_and_modifying_history_entries"target="_blank"title="Browser history push-state">HTML 5 pushState</a>
style by default, you *must* configure that strategy with a **base href**
The preferred way to configure the strategy is to add a