docs(router): fix markdown, and example mixin cleanup (#2101)
* docs(router): fix markdown and example mixin cleanup - Fixed: markdown text not under `:marked` region (and so that text was not showing up in the generated html). - Fixed: code excerpt title `constructor` -> `isSelected`. - Cleanup of all makeExample mixin uses. This cleanup will help make it easier to record differences with the deprecated router chapter (which must have app-relative makeExample paths). * post-review updates Found another instance of markdown (a heading) outside of a `:marked` region.
This commit is contained in:
parent
a771a6e0d0
commit
ea457825b8
|
@ -98,14 +98,14 @@ mixin makeExample(_filePath, region, _title, stylePatterns)
|
||||||
//- ending is given or is just (), then the title will be suffixed with
|
//- ending is given or is just (), then the title will be suffixed with
|
||||||
//- either "(excerpt)", or "(#{_region})" when _region is defined.
|
//- either "(excerpt)", or "(#{_region})" when _region is defined.
|
||||||
mixin makeExcerpt(_filePath, _region, _title, stylePatterns)
|
mixin makeExcerpt(_filePath, _region, _title, stylePatterns)
|
||||||
- var matches = _filePath.match(/(.*)\s+\(([\w ]*)\)$/);
|
- var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/);
|
||||||
- var parenText;
|
- var parenText;
|
||||||
- if (matches) { _filePath = matches[1]; parenText = matches[2]; }
|
- if (matches) { _filePath = matches[1]; parenText = matches[2]; }
|
||||||
- var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title});
|
- var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title});
|
||||||
- var filePath = adjustments.filePath;
|
- var filePath = adjustments.filePath;
|
||||||
- var title = adjustments.title;
|
- var title = adjustments.title;
|
||||||
- var region = _region || parenText;
|
- var region = _region || (_region === '' ? '' : parenText);
|
||||||
- var excerpt = !region || parenText === '' ? 'excerpt' : parenText || region;
|
- var excerpt = parenText || region || 'excerpt';
|
||||||
- if (title) title = title + ' (' + excerpt + ')';
|
- if (title) title = title + ' (' + excerpt + ')';
|
||||||
+makeExample(filePath, region, title, stylePatterns)(format='.')
|
+makeExample(filePath, region, title, stylePatterns)(format='.')
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,8 @@ include ../_util-fns
|
||||||
|
|
||||||
If the `app` folder is the application root, as it is for our sample application,
|
If the `app` folder is the application root, as it is for our sample application,
|
||||||
set the `href` value *exactly* as shown here.
|
set the `href` value *exactly* as shown here.
|
||||||
+makeExample('router/ts/index.1.html','base-href', 'index.html (base href)')(format=".")
|
|
||||||
|
+makeExcerpt('index.1.html', 'base-href')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Router imports
|
### Router imports
|
||||||
|
@ -80,7 +81,8 @@ include ../_util-fns
|
||||||
It is not part of the Angular 2 core. It is in its own library package, `@angular/router`.
|
It is not part of the Angular 2 core. It is in its own library package, `@angular/router`.
|
||||||
We import what we need from it as we would from any other Angular package.
|
We import what we need from it as we would from any other Angular package.
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.routing.ts','import-router', 'app/app.routing.ts (import)')(format=".")
|
+makeExcerpt('app/app.routing.ts (import)', 'import-router')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We cover other options in the [details below](#browser-url-styles).
|
We cover other options in the [details below](#browser-url-styles).
|
||||||
|
@ -93,7 +95,8 @@ include ../_util-fns
|
||||||
We bootstrap our application with an array of routes that we'll provide to our **`RouterModule.forRoot`** function.
|
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.
|
In the following example, we configure our application with four route definitions.
|
||||||
+makeExample('router/ts/app/app.routing.1.ts','route-config','app/app.routing.ts')(format='.')
|
|
||||||
|
+makeExcerpt('app/app.routing.1.ts (excerpt)', 'route-config')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
|
@ -122,13 +125,15 @@ include ../_util-fns
|
||||||
a configured *Router* module to our root NgModule imports.
|
a configured *Router* module to our root NgModule imports.
|
||||||
:marked
|
:marked
|
||||||
Next we open `app.module.ts` where we must register our routing, routing providers, and declare our two route components.
|
Next we open `app.module.ts` where we must register our routing, routing providers, and declare our two route components.
|
||||||
+makeExample('router/ts/app/app.module.1.ts','router-basics','app/app.module.ts (basic setup)')(format='.')
|
|
||||||
|
+makeExcerpt('app/app.module.1.ts (basic setup)', 'router-basics')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Router Outlet
|
### Router Outlet
|
||||||
Given this configuration, when the browser URL for this application becomes `/heroes`,
|
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`
|
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.
|
in a **`RouterOutlet`** that we've placed in the host view's HTML.
|
||||||
code-example(format="", language="html").
|
code-example(language="html").
|
||||||
<!-- Routed views go here -->
|
<!-- Routed views go here -->
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
:marked
|
:marked
|
||||||
|
@ -150,7 +155,9 @@ code-example(format="", language="html").
|
||||||
or on its parent element.
|
or on its parent element.
|
||||||
|
|
||||||
We see such bindings in the following `AppComponent` template:
|
We see such bindings in the following `AppComponent` template:
|
||||||
+makeExample('router/ts/app/app.component.1.ts', 'template')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.1.ts', 'template', '')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We're adding two anchor tags with `RouterLink` and `RouterLinkActive` directives.
|
We're adding two anchor tags with `RouterLink` and `RouterLinkActive` directives.
|
||||||
|
@ -257,6 +264,7 @@ table
|
||||||
We gloss over everything in between.
|
We gloss over everything in between.
|
||||||
|
|
||||||
The full source is available in the <live-example></live-example>.
|
The full source is available in the <live-example></live-example>.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Our client is the Hero Employment Agency.
|
Our client is the Hero Employment Agency.
|
||||||
Heroes need work and The Agency finds Crises for them to solve.
|
Heroes need work and The Agency finds Crises for them to solve.
|
||||||
|
@ -336,7 +344,7 @@ figure.image-display
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" )
|
img(src='/resources/images/devguide/router/router-1-anim.gif' alt="App in action" )
|
||||||
|
|
||||||
<a id="base-href"></a>
|
a#base-href
|
||||||
:marked
|
:marked
|
||||||
### Set the *<base href>*
|
### Set the *<base href>*
|
||||||
The Component Router uses the browser's
|
The Component Router uses the browser's
|
||||||
|
@ -356,7 +364,8 @@ figure.image-display
|
||||||
If the `app` folder is the application root, as it is for our application,
|
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.
|
set the `href` value in **`index.html`** *exactly* as shown here.
|
||||||
|
|
||||||
+makeExample('router/ts/index.1.html','base-href', 'index.html (base href)')(format=".")
|
+makeExcerpt('index.1.html', 'base-href')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
HTML 5 style navigation is the Component Router default.
|
HTML 5 style navigation is the Component Router default.
|
||||||
|
@ -398,7 +407,7 @@ figure.image-display
|
||||||
which returns a module containing the configured `Router` service provider ... and some other,
|
which returns a module containing the configured `Router` service provider ... and some other,
|
||||||
unseen providers that the routing library requires. We export this as the `routing` token.
|
unseen providers that the routing library requires. We export this as the `routing` token.
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.routing.2.ts','', 'app/app.routing.ts')(format=".")
|
+makeExcerpt('app/app.routing.2.ts')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
|
@ -443,7 +452,9 @@ h4#register-providers Register routing in the root NgModule
|
||||||
so they will be registered within our root NgModule.
|
so they will be registered within our root NgModule.
|
||||||
|
|
||||||
We also import the `appRoutingProviders` array and add it to the `providers` array.
|
We also import the `appRoutingProviders` array and add it to the `providers` array.
|
||||||
+makeExample('router/ts/app/app.module.1.ts','', 'app.module.ts')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.module.1.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Providing the router module in our root NgModule makes the Router available everywhere in our application.
|
Providing the router module in our root NgModule makes the Router available everywhere in our application.
|
||||||
|
|
||||||
|
@ -457,10 +468,13 @@ figure.image-display
|
||||||
a#shell-template
|
a#shell-template
|
||||||
:marked
|
:marked
|
||||||
The corresponding component template looks like this:
|
The corresponding component template looks like this:
|
||||||
+makeExample('router/ts/app/app.component.1.ts','template')(format=".")
|
|
||||||
|
|
||||||
h3#router-outlet <i>RouterOutlet</i>
|
+makeExcerpt('app/app.component.1.ts', 'template', '')
|
||||||
|
|
||||||
|
a#router-outlet
|
||||||
:marked
|
:marked
|
||||||
|
### *RouterOutlet*
|
||||||
|
|
||||||
`RouterOutlet` is a component from the router library.
|
`RouterOutlet` is a component from the router library.
|
||||||
The router displays views within the bounds of the `<router-outlet>` tags.
|
The router displays views within the bounds of the `<router-outlet>` tags.
|
||||||
|
|
||||||
|
@ -469,8 +483,10 @@ h3#router-outlet <i>RouterOutlet</i>
|
||||||
A template may hold exactly one ***unnamed*** `<router-outlet>`.
|
A template may hold exactly one ***unnamed*** `<router-outlet>`.
|
||||||
The router supports multiple *named* outlets, a feature we'll cover in future.
|
The router supports multiple *named* outlets, a feature we'll cover in future.
|
||||||
|
|
||||||
h3#router-link <i>RouterLink</i> binding
|
a#router-link
|
||||||
:marked
|
:marked
|
||||||
|
### *RouterLink* binding
|
||||||
|
|
||||||
Above the outlet, within the anchor tags, we see [Property Bindings](template-syntax.html#property-binding) to
|
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 imported `RouterLink` from the router library.
|
the `RouterLink` directive that look like `routerLink="..."`. We imported `RouterLink` from the router library.
|
||||||
|
|
||||||
|
@ -506,7 +522,8 @@ h3#router-directives <i>Router Directives</i>
|
||||||
They are readily available for us to use in our template.
|
They are readily available for us to use in our template.
|
||||||
:marked
|
:marked
|
||||||
The current state of `app.component.ts` looks like this:
|
The current state of `app.component.ts` looks like this:
|
||||||
+makeExample('router/ts/app/app.component.1.ts','', 'app/app.component.ts')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.1.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### "Getting Started" wrap-up
|
### "Getting Started" wrap-up
|
||||||
|
@ -545,6 +562,7 @@ h3#router-directives <i>Router Directives</i>
|
||||||
.file typings.json
|
.file typings.json
|
||||||
:marked
|
:marked
|
||||||
Here are the files discussed in this milestone
|
Here are the files discussed in this milestone
|
||||||
|
|
||||||
+makeTabs(
|
+makeTabs(
|
||||||
`router/ts/app/app.component.1.ts,
|
`router/ts/app/app.component.1.ts,
|
||||||
router/ts/app/app.module.1.ts,
|
router/ts/app/app.module.1.ts,
|
||||||
|
@ -562,9 +580,10 @@ h3#router-directives <i>Router Directives</i>
|
||||||
crisis-list.component.ts,
|
crisis-list.component.ts,
|
||||||
index.html`)
|
index.html`)
|
||||||
|
|
||||||
h2#heroes-feature Milestone #2: The Heroes Feature
|
.l-main-section#heroes-feature
|
||||||
.l-main-section
|
|
||||||
:marked
|
:marked
|
||||||
|
## Milestone #2: The Heroes Feature
|
||||||
|
|
||||||
We've seen how to navigate using the `RouterLink` directive.
|
We've seen how to navigate using the `RouterLink` directive.
|
||||||
|
|
||||||
Now we'll learn some new tricks such as how to
|
Now we'll learn some new tricks such as how to
|
||||||
|
@ -611,7 +630,8 @@ figure.image-display
|
||||||
so its available to all components within our module.
|
so its available to all components within our module.
|
||||||
|
|
||||||
Our `Heroes` module is ready for routing.
|
Our `Heroes` module is ready for routing.
|
||||||
+makeExample('router/ts/app/heroes/heroes.module.1.ts','', 'app/heroes/heroes.module.ts')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/heroes.module.1.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When we're done organizing, we have four *Hero Management* files:
|
When we're done organizing, we have four *Hero Management* files:
|
||||||
|
@ -645,7 +665,9 @@ figure.image-display
|
||||||
We recommend giving each feature area its own route configuration file.
|
We recommend giving each feature area its own route configuration file.
|
||||||
|
|
||||||
Create a new `heroes.routing.ts` in the `heroes` folder like this:
|
Create a new `heroes.routing.ts` in the `heroes` folder like this:
|
||||||
+makeExample('router/ts/app/heroes/heroes.routing.ts','', 'app/heroes/heroes.routing.ts')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/heroes.routing.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We use the same techniques we learned for `app.routing.ts`.
|
We use the same techniques we learned for `app.routing.ts`.
|
||||||
|
|
||||||
|
@ -661,12 +683,15 @@ figure.image-display
|
||||||
our feature-specific routes without modifying our main route configuration.
|
our feature-specific routes without modifying our main route configuration.
|
||||||
|
|
||||||
We import our `heroesRouting` token from `heroes.routing.ts` into our `Heroes` module and register the routing.
|
We import our `heroesRouting` token from `heroes.routing.ts` into our `Heroes` module and register the routing.
|
||||||
+makeExample('router/ts/app/heroes/heroes.module.ts', 'heroes-routes', 'app/heroes/heroes.module.ts (Heroes routing)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/heroes.module.ts (heroes routing)', 'heroes-routes')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Route definition with a parameter
|
### Route definition with a parameter
|
||||||
The route to `HeroDetailComponent` has a twist.
|
The route to `HeroDetailComponent` has a twist.
|
||||||
+makeExample('router/ts/app/heroes/heroes.routing.ts','hero-detail-route')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/heroes.routing.ts (excerpt)', 'hero-detail-route', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice the `:id` token in the path. That creates a slot in the path for a **Route Parameter**.
|
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.
|
In this case, we're expecting the router to insert the `id` of a hero into that slot.
|
||||||
|
@ -688,8 +713,10 @@ code-example(format="." language="bash").
|
||||||
|
|
||||||
An [optional-route-parameter](#optional-route-parameter) might be a better choice if we were passing an *optional* value to `HeroDetailComponent`.
|
An [optional-route-parameter](#optional-route-parameter) might be a better choice if we were passing an *optional* value to `HeroDetailComponent`.
|
||||||
|
|
||||||
h3#navigate Navigate to hero detail imperatively
|
a#navigate
|
||||||
:marked
|
:marked
|
||||||
|
### Navigate to hero detail imperatively
|
||||||
|
|
||||||
*We won't navigate to the detail component by clicking a link*
|
*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.
|
so we won't be adding a new `RouterLink` anchor tag to the shell.
|
||||||
|
|
||||||
|
@ -698,15 +725,21 @@ h3#navigate Navigate to hero detail imperatively
|
||||||
|
|
||||||
We'll adjust the `HeroListComponent` to implement these tasks, beginning with its constructor
|
We'll adjust the `HeroListComponent` to implement these tasks, beginning with its constructor
|
||||||
which acquires the router service and the `HeroService` by dependency injection:
|
which acquires the router service and the `HeroService` by dependency injection:
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.1.ts','ctor', 'app/heroes/hero-list.component.ts (Constructor)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.1.ts (constructor)', 'ctor')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We make a few changes to the template:
|
We make a few changes to the template:
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.1.ts','template')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.1.ts', 'template', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The template defines an `*ngFor` repeater such as [we've seen before](displaying-data.html#ngFor).
|
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
|
There's a `(click)` [EventBinding](template-syntax.html#event-binding) to the component's `onSelect` method
|
||||||
which we implement as follows:
|
which we implement as follows:
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.1.ts','select')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.1.ts', 'select', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
It calls the router's **`navigate`** method with a **Link Parameters Array**. We can use this same syntax
|
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.
|
with a `RouterLink` if we want to use it in HTML rather than code.
|
||||||
|
@ -718,13 +751,19 @@ h3#route-parameters Setting the route parameters in the list view
|
||||||
|
|
||||||
Accordingly, the *link parameters array* has *two* items: the **path** of the destination route and a **route parameter** that specifies the
|
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.
|
`id` of the selected hero.
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The router composes the appropriate two-part destination URL from this array:
|
The router composes the appropriate two-part destination URL from this array:
|
||||||
code-example(format="." language="bash").
|
|
||||||
|
code-example(language="bash").
|
||||||
localhost:3000/hero/15
|
localhost:3000/hero/15
|
||||||
h3#get-route-parameter Getting the route parameter in the details view
|
|
||||||
|
a#get-route-parameter
|
||||||
:marked
|
:marked
|
||||||
|
### Getting the route parameter in the details view
|
||||||
|
|
||||||
How does the target `HeroDetailComponent` learn about that `id`?
|
How does the target `HeroDetailComponent` learn about that `id`?
|
||||||
Certainly not by analyzing the URL! That's the router's job.
|
Certainly not by analyzing the URL! That's the router's job.
|
||||||
|
|
||||||
|
@ -735,14 +774,18 @@ a#hero-detail-ctor
|
||||||
:marked
|
:marked
|
||||||
As usual, we write a constructor that asks Angular to inject services
|
As usual, we write a constructor that asks Angular to inject services
|
||||||
that the component requires and reference them as private variables.
|
that the component requires and reference them as private variables.
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.ts','ctor', 'app/heroes/hero-detail.component.ts (Constructor)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.ts (constructor)', 'ctor')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Later, in the `ngOnInit` method,
|
Later, in the `ngOnInit` method,
|
||||||
we use the `ActivatedRoute` service to retrieve the parameters for our route.
|
we use the `ActivatedRoute` service to retrieve the parameters for our route.
|
||||||
Since our parameters are provided as an `Observable`, we _subscribe_ to them for the `id` parameter by name and
|
Since our parameters are provided as an `Observable`, we _subscribe_ to them for the `id` parameter by name and
|
||||||
tell the `HeroService` to fetch the hero with that `id`. We'll keep a reference to this `Subscription` so we can
|
tell the `HeroService` to fetch the hero with that `id`. We'll keep a reference to this `Subscription` so we can
|
||||||
tidy things up later.
|
tidy things up later.
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.ts','ngOnInit')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.ts', 'ngOnInit', '')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`.
|
Angular calls the `ngOnInit` method shortly after creating an instance of the `HeroDetailComponent`.
|
||||||
|
@ -759,7 +802,8 @@ a#hero-detail-ctor
|
||||||
*Failure to do so could create a memory leak.*
|
*Failure to do so could create a memory leak.*
|
||||||
|
|
||||||
We unsubscribe from our `Observable` in the `ngOnDestroy` method.
|
We unsubscribe from our `Observable` in the `ngOnDestroy` method.
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.ts','ngOnDestroy')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.ts', 'ngOnDestroy', '')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
|
@ -801,7 +845,9 @@ h4#snapshot <i>Snapshot</i>: the no-observable alternative
|
||||||
The router offers a *Snapshot* alternative that gives us the initial value of the route parameters.
|
The router offers a *Snapshot* alternative that gives us the initial value of the route parameters.
|
||||||
We don't need to subscribe. We don't have to unsubscribe in `ngOnDestroy`.
|
We don't need to subscribe. We don't have to unsubscribe in `ngOnDestroy`.
|
||||||
It's much simpler to write and read:
|
It's much simpler to write and read:
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.2.ts','snapshot')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.2.ts (excerpt)', 'snapshot', '')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
**Remember:** we only get the _initial_ value of the parameters with this technique.
|
**Remember:** we only get the _initial_ value of the parameters with this technique.
|
||||||
|
@ -809,15 +855,18 @@ h4#snapshot <i>Snapshot</i>: the no-observable alternative
|
||||||
to this component multiple times in a row.
|
to this component multiple times in a row.
|
||||||
We are leaving the observable `params` strategy in place just in case.
|
We are leaving the observable `params` strategy in place just in case.
|
||||||
|
|
||||||
h3#nav-to-list Navigating back to the list component
|
a#nav-to-list
|
||||||
:marked
|
:marked
|
||||||
|
### Navigating back to the list component
|
||||||
|
|
||||||
The `HeroDetailComponent` has a "Back" button wired to its `gotoHeroes` method that navigates imperatively
|
The `HeroDetailComponent` has a "Back" button wired to its `gotoHeroes` method that navigates imperatively
|
||||||
back to the `HeroListComponent`.
|
back to the `HeroListComponent`.
|
||||||
|
|
||||||
The router `navigate` method takes the same one-item *link parameters array*
|
The router `navigate` method takes the same one-item *link parameters array*
|
||||||
that we can bind to a `[routerLink]` directive.
|
that we can bind to a `[routerLink]` directive.
|
||||||
It holds the **path to the `HeroListComponent`**:
|
It holds the **path to the `HeroListComponent`**:
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.1.ts (excerpt)', 'gotoHeroes', '')
|
||||||
|
|
||||||
h3#merge-hero-routes Import hero module into root NgModule
|
h3#merge-hero-routes Import hero module into root NgModule
|
||||||
:marked
|
:marked
|
||||||
|
@ -826,7 +875,7 @@ h3#merge-hero-routes Import hero module into root NgModule
|
||||||
|
|
||||||
Update `app.module.ts` as follows:
|
Update `app.module.ts` as follows:
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.module.2.ts','hero-import', 'app.module.ts (Heroes module import)')(format=".")
|
+makeExcerpt('app/app.module.2.ts (heroes module import)', 'hero-import')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We imported the `HeroesModule` and added it to our root NgModule `imports`.
|
We imported the `HeroesModule` and added it to our root NgModule `imports`.
|
||||||
|
@ -841,7 +890,7 @@ h3#merge-hero-routes Import hero module into root NgModule
|
||||||
|
|
||||||
Since our `Heroes` routes are defined within our submodule, we can also remove our initial `heroes` route from the `app.routing.ts`.
|
Since our `Heroes` routes are defined within our submodule, we can also remove our initial `heroes` route from the `app.routing.ts`.
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.routing.3.ts','', 'app.routing.ts (v.2)')(format=".")
|
+makeExcerpt('app/app.routing.3.ts (v2)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Heroes App Wrap-up
|
### Heroes App Wrap-up
|
||||||
|
@ -883,6 +932,7 @@ h3#merge-hero-routes Import hero module into root NgModule
|
||||||
<a id="heroes-app-code"></a>
|
<a id="heroes-app-code"></a>
|
||||||
### The Heroes App code
|
### The Heroes App code
|
||||||
Here are the relevant files for this version of the sample application.
|
Here are the relevant files for this version of the sample application.
|
||||||
|
|
||||||
+makeTabs(
|
+makeTabs(
|
||||||
`router/ts/app/app.component.1.ts,
|
`router/ts/app/app.component.1.ts,
|
||||||
router/ts/app/app.module.2.ts,
|
router/ts/app/app.module.2.ts,
|
||||||
|
@ -901,12 +951,11 @@ h3#merge-hero-routes Import hero module into root NgModule
|
||||||
hero.service.ts,
|
hero.service.ts,
|
||||||
heroes.module.ts,
|
heroes.module.ts,
|
||||||
heroes.routing.ts`)
|
heroes.routing.ts`)
|
||||||
:marked
|
|
||||||
|
|
||||||
<a id="crisis-center-feature"></a>
|
.l-main-section#crisis-center-feature
|
||||||
.l-main-section
|
|
||||||
:marked
|
:marked
|
||||||
## Milestone #3: The Crisis Center
|
## Milestone #3: The Crisis Center
|
||||||
|
|
||||||
The *Crisis Center* is a fake view at the moment. Time to make it useful.
|
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.
|
The new *Crisis Center* begins as a virtual copy of the *Heroes* module.
|
||||||
|
@ -962,10 +1011,14 @@ h3#merge-hero-routes Import hero module into root NgModule
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/router/component-tree.png' alt="Component Tree" )
|
img(src='/resources/images/devguide/router/component-tree.png' alt="Component Tree" )
|
||||||
|
|
||||||
h3#child-routing-component Child Routing Component
|
a#child-routing-component
|
||||||
:marked
|
:marked
|
||||||
|
### Child Routing Component
|
||||||
|
|
||||||
Add the following `crisis-center.component.ts` to the `crisis-center` folder:
|
Add the following `crisis-center.component.ts` to the `crisis-center` folder:
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.component.ts', 'minus-imports', 'crisis-center/crisis-center.component.ts (minus imports)')(format='.')
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.component.ts (minus imports)', 'minus-imports')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The `CrisisCenterComponent` is much like the `AppComponent` shell.
|
The `CrisisCenterComponent` is much like the `AppComponent` shell.
|
||||||
|
|
||||||
|
@ -981,6 +1034,7 @@ h3#child-routing-component Child Routing Component
|
||||||
Unlike `AppComponent` (and most other components), it **lacks a selector**.
|
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.
|
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.
|
We *navigate* to it from the outside, via the router.
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We *can* give it a selector. There's no harm in it.
|
We *can* give it a selector. There's no harm in it.
|
||||||
|
@ -993,7 +1047,9 @@ h3#child-routing-component Child Routing Component
|
||||||
Instead of registering it with the root NgModule's providers —
|
Instead of registering it with the root NgModule's providers —
|
||||||
which makes it visible everywhere —
|
which makes it visible everywhere —
|
||||||
we register the `CrisisService` in the `CrisisCenterModule` providers array.
|
we register the `CrisisService` in the `CrisisCenterModule` providers array.
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.module.1.ts', 'providers')(format='.')
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.module.1.ts', 'providers', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
This limits the scope of the `CrisisService` to the *Crisis Center* routes.
|
This limits the scope of the `CrisisService` to the *Crisis Center* routes.
|
||||||
No module outside of the *Crisis Center* can access it.
|
No module outside of the *Crisis Center* can access it.
|
||||||
|
@ -1011,12 +1067,15 @@ h3#child-routing-component Child Routing Component
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
### Child Route Configuration
|
### Child Route Configuration
|
||||||
|
|
||||||
The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`.
|
The `CrisisCenterComponent` is a *Routing Component* like the `AppComponent`.
|
||||||
It has its own `RouterOutlet` and its own child routes.
|
It has its own `RouterOutlet` and its own child routes.
|
||||||
|
|
||||||
We create a `crisis-center.routing.ts` file as we did the `heroes.routing.ts` file.
|
We create a `crisis-center.routing.ts` file as we did the `heroes.routing.ts` file.
|
||||||
But this time we define **child routes** *within* the parent `crisis-center` route.
|
But this time we define **child routes** *within* the parent `crisis-center` route.
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.1.ts', 'routes', 'app/crisis-center/crisis-center.routing.ts (Routes)' )(format='.')
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.routing.1.ts (Routes)', 'routes')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice that the parent `crisis-center` route has a `children` property
|
Notice that the parent `crisis-center` route has a `children` property
|
||||||
with an array of two routes.
|
with an array of two routes.
|
||||||
|
@ -1039,30 +1098,36 @@ h3#child-routing-component Child Routing Component
|
||||||
To write an URL that navigates to the `CrisisDetailComponent`, we'd append the child route path, `/`,
|
To write an URL that navigates to the `CrisisDetailComponent`, we'd append the child route path, `/`,
|
||||||
followed by the crisis id, yielding something like:
|
followed by the crisis id, yielding something like:
|
||||||
|
|
||||||
code-example(format="").
|
code-example.
|
||||||
localhost:3000/crisis-center/2
|
localhost:3000/crisis-center/2
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here's the complete `crisis-center.routing.ts` with its imports.
|
Here's the complete `crisis-center.routing.ts` with its imports.
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.1.ts', '', 'app/crisis-center/crisis-center.routing.ts' )(format='.')
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.routing.1.ts', '')
|
||||||
|
|
||||||
h3#import-crisis-module Import crisis center module into the root NgModule routes
|
h3#import-crisis-module Import crisis center module into the root NgModule routes
|
||||||
:marked
|
:marked
|
||||||
As with the `Heroes` module, we must import the `Crisis Center` module into the root NgModule:
|
As with the `Heroes` module, we must import the `Crisis Center` module into the root NgModule:
|
||||||
+makeExample('router/ts/app/app.module.3.ts', '', 'app/app.module.ts (Crisis Center Module)' )(format='.')
|
|
||||||
|
+makeExcerpt('app/app.module.3.ts (Crisis Center Module)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We also remove the initial crisis center route from our `app.routing.ts`. Our routes
|
We also remove the initial crisis center route from our `app.routing.ts`. Our routes
|
||||||
are now being provided by our `HeroesModule` and our `CrisisCenter` submodules. We'll keep our `app.routing.ts` file
|
are now being provided by our `HeroesModule` and our `CrisisCenter` submodules. We'll keep our `app.routing.ts` file
|
||||||
for general routes which we'll cover later in the chapter.
|
for general routes which we'll cover later in the chapter.
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.routing.4.ts', '', 'app/app.routing.ts (v.3)' )(format='.')
|
+makeExcerpt('app/app.routing.4.ts (v3)', '')
|
||||||
|
|
||||||
a#redirect
|
a#redirect
|
||||||
h3#redirect Redirecting routes
|
|
||||||
:marked
|
:marked
|
||||||
|
### Redirecting routes
|
||||||
|
|
||||||
When the application launches, the initial URL in the browser bar is something like:
|
When the application launches, the initial URL in the browser bar is something like:
|
||||||
code-example(format="").
|
|
||||||
|
code-example.
|
||||||
localhost:3000
|
localhost:3000
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
That doesn't match any of our configured routes which means that our application won't display any component when it's launched.
|
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.
|
The user must click one of the navigation links to trigger a navigation and display something.
|
||||||
|
@ -1072,7 +1137,8 @@ code-example(format="").
|
||||||
|
|
||||||
The preferred solution is to add a `redirect` route that transparently translates from the initial relative URL (`''`)
|
The preferred solution is to add a `redirect` route that transparently translates from the initial relative URL (`''`)
|
||||||
to the desired default path (`/crisis-center`):
|
to the desired default path (`/crisis-center`):
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.2.ts', 'redirect', 'app/crisis-center/crisis-center.routing.ts (redirect route)' )(format='.')
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.routing.2.ts' , 'redirect', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route.
|
A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route.
|
||||||
|
@ -1102,7 +1168,8 @@ code-example(format="").
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The updated route definitions look like this:
|
The updated route definitions look like this:
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.2.ts', 'routes', 'app/crisis-center/crisis-center.routing.ts (Routes v.2)' )(format='.')
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.routing.2.ts (routes v2)' , 'routes')
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
h2#guards Route Guards
|
h2#guards Route Guards
|
||||||
|
@ -1153,15 +1220,16 @@ h2#guards Route Guards
|
||||||
|
|
||||||
Let's look at some examples.
|
Let's look at some examples.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section#lifecycle-hooks
|
||||||
// :marked
|
:marked
|
||||||
<a id="lifecycle-hooks"></a>
|
|
||||||
## Router Lifecycle Hooks
|
## Router Lifecycle Hooks
|
||||||
|
|
||||||
TODO: Pausing activation
|
TODO: Pausing activation
|
||||||
|
|
||||||
h3#can-activate-guard <i>CanActivate</i>: requiring authentication
|
a#can-activate-guard
|
||||||
:marked
|
:marked
|
||||||
|
### *CanActivate*: requiring authentication
|
||||||
|
|
||||||
Applications often restrict access to a feature area based on who the user is.
|
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 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.
|
We might block or limit access until the user's account is activated.
|
||||||
|
@ -1173,13 +1241,17 @@ h3#can-activate-guard <i>CanActivate</i>: requiring authentication
|
||||||
We intend to extend the Crisis Center with some new *administrative* features.
|
We intend to extend the Crisis Center with some new *administrative* features.
|
||||||
Those features aren't defined yet. So we add the following placeholder component.
|
Those features aren't defined yet. So we add the following placeholder component.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-admin.component.1.ts', '', 'crisis-admin.component.ts')(format=".")
|
+makeExcerpt('app/crisis-center/crisis-admin.component.1.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Next, we add a child route to the `crisis-center.routes` with the path, `/admin`.
|
Next, we add a child route to the `crisis-center.routes` with the path, `/admin`.
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.3.ts', 'admin-route-no-guard', 'crisis-center.routing.ts (admin route)')(format=".")
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-center.routing.3.ts (admin route)', 'admin-route-no-guard')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
And we add a link to the `AppComponent` shell that users can click to get to this feature.
|
And we add a link to the `AppComponent` shell that users can click to get to this feature.
|
||||||
+makeExample('router/ts/app/app.component.4.ts', 'template', 'app/app.component.ts (template)')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.4.ts', 'template')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
|
@ -1202,19 +1274,26 @@ h3#can-activate-guard <i>CanActivate</i>: requiring authentication
|
||||||
|
|
||||||
At the moment we're interested in seeing how guards work so our first version does nothing useful.
|
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:
|
It simply logs to console and `returns` true immediately, allowing navigation to proceed:
|
||||||
+makeExample('router/ts/app/auth-guard.service.1.ts', '', 'app/auth-guard.service.ts')(format=".")
|
|
||||||
|
+makeExcerpt('app/auth-guard.service.1.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Next we open `crisis-center.routing.ts `, import the `AuthGuard` class, and
|
Next we open `crisis-center.routing.ts `, import the `AuthGuard` class, and
|
||||||
update the admin route with a `CanActivate` guard property that references it:
|
update the admin route with a `CanActivate` guard property that references it:
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.ts', 'admin-route', 'crisis-center.routing.ts (guarded admin route)')(format=".")
|
|
||||||
Our admin feature is now protected by the guard, albeit protected poorly.
|
+makeExcerpt('app/crisis-center/crisis-center.routing.ts (guarded admin route)', 'admin-route')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
|
Our admin feature is now protected by the guard, albeit protected poorly.
|
||||||
|
|
||||||
#### Teach *AuthGuard* to authenticate
|
#### Teach *AuthGuard* to authenticate
|
||||||
Let's make our `AuthGuard` at least pretend 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.
|
The `AuthGuard` should call an application service that can login a user and retain information about the current user.
|
||||||
Here's a demo `AuthService`:
|
Here's a demo `AuthService`:
|
||||||
+makeExample('router/ts/app/auth.service.ts', '', 'app/auth.service.ts')(format=".")
|
|
||||||
|
+makeExcerpt('app/auth.service.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Although it doesn't actually log in, it has what we need for this discussion.
|
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.
|
It has an `isLoggedIn` flag to tell us whether the user is authenticated.
|
||||||
|
@ -1222,7 +1301,9 @@ h3#can-activate-guard <i>CanActivate</i>: requiring authentication
|
||||||
The `redirectUrl` property will store our attempted URL so we can navigate to it after authenticating.
|
The `redirectUrl` property will store our attempted URL so we can navigate to it after authenticating.
|
||||||
|
|
||||||
Let's revise our `AuthGuard` to call it.
|
Let's revise our `AuthGuard` to call it.
|
||||||
+makeExample('router/ts/app/auth-guard.service.2.ts', '', 'app/auth-guard.service.ts (v.2)')(format=".")
|
|
||||||
|
+makeExcerpt('app/auth-guard.service.2.ts (v2)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice that we *inject* the `AuthService` and the `Router` in the constructor.
|
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.
|
We haven't provided the `AuthService` yet but it's good to know that we can inject helpful services into our routing guards.
|
||||||
|
@ -1295,7 +1376,9 @@ h3#can-deactivate-guard <i>CanDeactivate</i>: handling unsaved changes
|
||||||
We discard the changes if the user presses he *Cancel* button.
|
We discard the changes if the user presses he *Cancel* button.
|
||||||
|
|
||||||
Both buttons navigate back to the crisis list after save or cancel.
|
Both buttons navigate back to the crisis list after save or cancel.
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'cancel-save', 'crisis-detail.component.ts (excerpt)')(format=".")
|
|
||||||
|
+makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
What if the user tries to navigate away without saving or canceling?
|
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.
|
The user could push the browser back button or click the heroes link.
|
||||||
|
@ -1318,24 +1401,27 @@ h3#can-deactivate-guard <i>CanDeactivate</i>: handling unsaved changes
|
||||||
*resolves* when the user eventually decides what to do: either
|
*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`).
|
to discard changes and navigate away (`true`) or to preserve the pending changes and stay in the crisis editor (`false`).
|
||||||
|
|
||||||
<a id="CanDeactivate"></a>
|
a#CanDeactivate
|
||||||
:marked
|
:marked
|
||||||
We create a `Guard` that will check for the presence of a `canDeactivate` function in our component, in this
|
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.
|
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.
|
This makes our guard reusable, which is an easy win for us.
|
||||||
+makeExample('router/ts/app/can-deactivate-guard.service.ts', '', 'can-deactivate-guard.service.ts')
|
|
||||||
|
+makeExample('app/can-deactivate-guard.service.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Alternatively, We could make a component-specific `CanDeactivate` guard for our `CrisisDetailComponent`. The `canDeactivate` method provides us
|
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
|
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
|
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.
|
properties in or to confirm whether the router should allow navigation away from it.
|
||||||
+makeExample('router/ts/app/can-deactivate-guard.service.1.ts', '', 'can-deactivate-guard.service.ts (component-specific)')
|
|
||||||
|
+makeExcerpt('app/can-deactivate-guard.service.1.ts (component-specific)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Looking back at our `CrisisDetailComponent`, we have implemented our confirmation workflow for unsaved changes.
|
Looking back at our `CrisisDetailComponent`, we have implemented our confirmation workflow for unsaved changes.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-detail.component.1.ts', 'cancel-save-only', 'crisis-detail.component.ts (excerpt)')
|
+makeExcerpt('app/crisis-center/crisis-detail.component.1.ts (excerpt)', 'cancel-save-only')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice that the `canDeactivate` method *can* return synchronously;
|
Notice that the `canDeactivate` method *can* return synchronously;
|
||||||
it returns `true` immediately if there is no crisis or there are no pending changes.
|
it returns `true` immediately if there is no crisis or there are no pending changes.
|
||||||
|
@ -1344,11 +1430,13 @@ h3#can-deactivate-guard <i>CanDeactivate</i>: handling unsaved changes
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We add the `Guard` to our crisis detail route in `crisis-center.routing.ts` using the `canDeactivate` array.
|
We add the `Guard` to our crisis detail route in `crisis-center.routing.ts` using the `canDeactivate` array.
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.4.ts', '', 'crisis-center.routing.ts')
|
|
||||||
|
+makeExample('app/crisis-center/crisis-center.routing.4.ts', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We also need to add the `Guard` to our main `appRoutingProviders` so the `Router` can inject it during the navigation process.
|
We also need to add the `Guard` to our main `appRoutingProviders` so the `Router` can inject it during the navigation process.
|
||||||
+makeExample('router/ts/app/app.routing.5.ts', '', 'app.routing.ts')
|
|
||||||
|
+makeExample('app/app.routing.5.ts', '', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Now we have given our user a safeguard against unsaved changes.
|
Now we have given our user a safeguard against unsaved changes.
|
||||||
|
@ -1387,7 +1475,7 @@ h3#resolve-guard <i>Resolve</i>: pre-fetching component data
|
||||||
|
|
||||||
Let's create our `crisis-detail-resolve.service.ts` file within our `Crisis Center` feature area.
|
Let's create our `crisis-detail-resolve.service.ts` file within our `Crisis Center` feature area.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-detail-resolve.service.ts', '', 'crisis-detail-resolve.service.ts')
|
+makeExample('app/crisis-center/crisis-detail-resolve.service.ts', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We'll take the relevant parts of the `ngOnInit` lifecycle hook in our `CrisisDetailComponent` and moved them into our `CrisisDetailResolve` guard.
|
We'll take the relevant parts of the `ngOnInit` lifecycle hook in our `CrisisDetailComponent` and moved them into our `CrisisDetailResolve` guard.
|
||||||
|
@ -1401,12 +1489,12 @@ h3#resolve-guard <i>Resolve</i>: pre-fetching component data
|
||||||
|
|
||||||
Now that our guard is ready, we'll import it in our `crisis-center.routing.ts` and use the `resolve` object in our route configuration.
|
Now that our guard is ready, we'll import it in our `crisis-center.routing.ts` and use the `resolve` object in our route configuration.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.routing.5.ts', 'crisis-detail-resolve', 'crisis-center.routing.ts (resolve)')
|
+makeExcerpt('app/crisis-center/crisis-center.routing.5.ts (resolve)', 'crisis-detail-resolve')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We'll add the `CrisisDetailResolve` service to our crisis center module's `providers`, so its available to the `Router` during the navigation process.
|
We'll add the `CrisisDetailResolve` service to our crisis center module's `providers`, so its available to the `Router` during the navigation process.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.module.ts', 'crisis-detail-resolve', 'crisis-center.module.ts (crisis detail resolve provider)')
|
+makeExcerpt('app/crisis-center/crisis-center.module.ts (crisis detail resolve provider)', 'crisis-detail-resolve')
|
||||||
|
|
||||||
:marked
|
: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`.
|
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`.
|
||||||
|
@ -1414,7 +1502,7 @@ h3#resolve-guard <i>Resolve</i>: pre-fetching component data
|
||||||
Once activated, all we need to do is set our local `crisis` and `editName` properties from our resolved `Crisis` information. We no longer need to subscribe
|
Once activated, all we need to do is set our local `crisis` and `editName` properties from our resolved `Crisis` information. We no longer need to subscribe
|
||||||
and unsubscribe to the `ActivatedRoute` params to fetch the `Crisis` because it is being provided synchronously at the time the route component is activated.
|
and unsubscribe to the `ActivatedRoute` params to fetch the `Crisis` because it is being provided synchronously at the time the route component is activated.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-detail.component.ts', 'crisis-detail-resolve', 'crisis-detail.component.ts (ngOnInit v.2)')
|
+makeExcerpt('app/crisis-center/crisis-detail.component.ts (ngOnInit v2)', 'crisis-detail-resolve')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
**Two critical points**
|
**Two critical points**
|
||||||
|
@ -1455,8 +1543,7 @@ h3#resolve-guard <i>Resolve</i>: pre-fetching component data
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
|
||||||
<a id="optional-route-parameters"></a>
|
.l-main-section#optional-route-parameters
|
||||||
.l-main-section
|
|
||||||
:marked
|
:marked
|
||||||
## Milestone #4: Route Parameters
|
## Milestone #4: Route Parameters
|
||||||
|
|
||||||
|
@ -1500,18 +1587,24 @@ figure.image-display
|
||||||
|
|
||||||
<a id="route-parameters-object"></a>
|
<a id="route-parameters-object"></a>
|
||||||
### Route parameter
|
### Route parameter
|
||||||
|
|
||||||
When navigating to the `HeroDetailComponent` we specified the `id` of the hero-to-edit in the
|
When navigating to the `HeroDetailComponent` we specified the `id` of the hero-to-edit in the
|
||||||
*route parameter* and made it the second item of the [*link parameters array*](#link-parameters-array).
|
*route parameter* and made it the second item of the [*link parameters array*](#link-parameters-array).
|
||||||
|
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.1.ts','link-parameters-array')(format=".")
|
+makeExcerpt('app/heroes/hero-list.component.1.ts', 'link-parameters-array', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The router embedded the `id` value in the navigation URL because we had defined it
|
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`:
|
as a route parameter with an `:id` placeholder token in the route `path`:
|
||||||
+makeExample('router/ts/app/heroes/heroes.routing.ts','hero-detail-route')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/heroes.routing.ts', 'hero-detail-route', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array*
|
When the user clicks the back button, the `HeroDetailComponent` constructs another *link parameters array*
|
||||||
which it uses to navigate back to the `HeroListComponent`.
|
which it uses to navigate back to the `HeroListComponent`.
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.1.ts','gotoHeroes')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.1.ts', 'gotoHeroes', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
This array lacks a route parameter because we had no reason to send information to the `HeroListComponent`.
|
This array lacks a route parameter because we had no reason to send information to the `HeroListComponent`.
|
||||||
|
|
||||||
|
@ -1521,7 +1614,9 @@ figure.image-display
|
||||||
We do that with an object that contains our optional `id` parameter.
|
We do that with an object that contains our optional `id` parameter.
|
||||||
We also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore.
|
We also defined a junk parameter (`foo`) that the `HeroListComponent` should ignore.
|
||||||
Here's the revised navigation statement:
|
Here's the revised navigation statement:
|
||||||
+makeExample('router/ts/app/heroes/hero-detail.component.ts','gotoHeroes-navigate')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-detail.component.ts', 'gotoHeroes-navigate', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The application still works. Clicking "back" returns to the hero list view.
|
The application still works. Clicking "back" returns to the hero list view.
|
||||||
|
|
||||||
|
@ -1532,15 +1627,18 @@ figure.image-display
|
||||||
When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner.
|
When running in plunker, pop out the preview window by clicking the blue 'X' button in the upper right corner.
|
||||||
:marked
|
:marked
|
||||||
It should look something like this, depending on where you run it:
|
It should look something like this, depending on where you run it:
|
||||||
code-example(format="." language="bash").
|
|
||||||
|
code-example(language="bash").
|
||||||
localhost:3000/heroes;id=15;foo=foo
|
localhost:3000/heroes;id=15;foo=foo
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The `id` value appears in the URL as (`;id=15;foo=foo`), not in the URL path.
|
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 path for the "Heroes" route doesn't have an `:id` token.
|
||||||
:marked
|
|
||||||
The optional route parameters are not separated by "?" and "&".
|
The optional route parameters are not separated by "?" and "&".
|
||||||
They are **separated by semicolons (;)**
|
They are **separated by semicolons (;)**
|
||||||
This is *matrix URL* notation — something we may not have seen before.
|
This is *matrix URL* notation — something we may not have seen before.
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
*Matrix URL* notation is an idea first floated
|
*Matrix URL* notation is an idea first floated
|
||||||
|
@ -1575,23 +1673,31 @@ code-example(format="." language="bash").
|
||||||
This time we'll be navigating in the opposite direction, from the `HeroDetailComponent` to the `HeroListComponent`.
|
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;
|
First we extend the router import statement to include the `ActivatedRoute` service symbol;
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.ts','import-router', 'hero-list.component.ts (import)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.ts (import)', 'import-router')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe
|
Then we use the `ActivatedRoute` to access the `params` _Observable_ so we can subscribe
|
||||||
and extract the `id` parameter as the `selectedId`:
|
and extract the `id` parameter as the `selectedId`:
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.ts','ctor', 'hero-list.component.ts (constructor)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.ts (constructor)', 'ctor')
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
All route/query parameters are strings.
|
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.
|
The (+) in front of the `params['id']` expression is a JavaScript trick to convert the string to an integer.
|
||||||
:marked
|
:marked
|
||||||
We add an `isSelected` method that returns true when a hero's id matches the selected id.
|
We add an `isSelected` method that returns true when a hero's id matches the selected id.
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.ts','isSelected', 'hero-list.component.ts (constructor)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.ts', 'isSelected')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Finally, we update our template with a [Class Binding](template-syntax.html#class-binding) to that `isSelected` method.
|
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`.
|
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:
|
Look for it within the repeated `<li>` tag as shown here:
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.ts','template', 'hero-list.component.ts (template)')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.ts', 'template')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
|
When the user navigates from the heroes list to the "Magneta" hero and back, "Magneta" appears selected:
|
||||||
figure.image-display
|
figure.image-display
|
||||||
|
@ -1599,11 +1705,11 @@ figure.image-display
|
||||||
:marked
|
:marked
|
||||||
The optional `foo` route parameter is harmless and continues to be ignored.
|
The optional `foo` route parameter is harmless and continues to be ignored.
|
||||||
|
|
||||||
<a id="query-parameters"></a>
|
a#query-parameters
|
||||||
<a id="fragment"></a>
|
a#fragment
|
||||||
:marked
|
:marked
|
||||||
### Query Parameters and Fragments
|
### Query Parameters and Fragments
|
||||||
:marked
|
|
||||||
In our [route parameters](#optional-route-parameters) example, we only dealt with parameters specific to
|
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
|
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.
|
query parameters come into play and serve a special purpose in our application.
|
||||||
|
@ -1616,7 +1722,8 @@ figure.image-display
|
||||||
We'll also provide an arbitrary `anchor` fragment, which we would use to jump to a certain point on our page.
|
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.
|
We'll add the `NavigationExtras` object to our `router.navigate` method that navigates us to our `/login` route.
|
||||||
+makeExample('router/ts/app/auth-guard.service.ts','', 'auth-guard.service.ts (v.3)')
|
|
||||||
|
+makeExcerpt('app/auth-guard.service.ts (v3)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We can also **preserve** query parameters and fragments across navigations without having to re-provide them
|
We can also **preserve** query parameters and fragments across navigations without having to re-provide them
|
||||||
|
@ -1624,13 +1731,14 @@ figure.image-display
|
||||||
and provide the `preserveQueryParams` and `preserveFragment` to pass along the current query parameters
|
and provide the `preserveQueryParams` and `preserveFragment` to pass along the current query parameters
|
||||||
and fragment to the next route.
|
and fragment to the next route.
|
||||||
|
|
||||||
+makeExample('router/ts/app/login.component.ts','preserve', 'login.component.ts (preserved)')(format=".")
|
+makeExcerpt('app/login.component.ts', 'preserve')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Since we'll be navigating to our *Crisis Admin* route after logging in, we'll update it to handle our
|
Since we'll be navigating to our *Crisis Admin* route after logging in, we'll update it to handle our
|
||||||
query parameters and fragment.
|
query parameters and fragment.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-admin.component.ts','', 'crisis-admin.component.ts (v.2)')
|
+makeExcerpt('app/crisis-center/crisis-admin.component.ts (v2)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
*Query Parameters* and *Fragments* are also available through the `ActivatedRoute` service available to route components.
|
*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`.
|
Just like our *route parameters*, query parameters and fragments are provided as an `Observable`.
|
||||||
|
@ -1696,7 +1804,7 @@ figure.image-display
|
||||||
out our `Crisis Center` 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
|
out our `Crisis Center` 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 `CrisisCenter` NgModule. If we look in our `crisis-center.module` file, we can see it matches name of our exported NgModule class.
|
of our `CrisisCenter` NgModule. If we look in our `crisis-center.module` file, we can see it matches name of our exported NgModule class.
|
||||||
|
|
||||||
+makeExample('router/ts/app/crisis-center/crisis-center.module.ts', 'crisis-center-module-export', 'crisis-center.module.ts (export)')
|
+makeExcerpt('app/crisis-center/crisis-center.module.ts (export)', 'crisis-center-module-export')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The `loadChildren` property is used by the `Router` to map to our bundle we want to lazy-load, in this case being the `CrisisCenterModule`.
|
The `loadChildren` property is used by the `Router` to map to our bundle we want to lazy-load, in this case being the `CrisisCenterModule`.
|
||||||
|
@ -1714,13 +1822,13 @@ figure.image-display
|
||||||
to break our `CrisisCenterModule` into a completely separate module. In our `app.module.ts`, we'll remove our `CrisisCenterModule` from the
|
to break our `CrisisCenterModule` into a completely separate module. In our `app.module.ts`, we'll remove our `CrisisCenterModule` from the
|
||||||
`imports` array since we'll be loading it on-demand an we'll remove the imported `CrisisCenterModule`.
|
`imports` array since we'll be loading it on-demand an we'll remove the imported `CrisisCenterModule`.
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.module.ts', '', 'app.module.ts (final)')
|
+makeExcerpt('app/app.module.ts (final)', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
If our initial redirect went to `/heroes` instead of going to `/crisis-center`, the `CrisisCenterModule` would not be loaded until the user
|
If our initial redirect went to `/heroes` instead of going to `/crisis-center`, the `CrisisCenterModule` would not be loaded until the user
|
||||||
visited a `Crisis Center` route. We'll update our redirect in our `app.routing.ts` to make this change.
|
visited a `Crisis Center` route. We'll update our redirect in our `app.routing.ts` to make this change.
|
||||||
|
|
||||||
+makeExample('router/ts/app/app.routing.6.ts', 'heroes-redirect', 'app.routing.ts (heroes redirect)')
|
+makeExcerpt('app/app.routing.6.ts (heroes redirect)', 'heroes-redirect')
|
||||||
|
|
||||||
<a id="final-app"></a>
|
<a id="final-app"></a>
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
@ -1739,10 +1847,10 @@ figure.image-display
|
||||||
The appendix material isn't essential. Continued reading is for the curious.
|
The appendix material isn't essential. Continued reading is for the curious.
|
||||||
|
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section#link-parameters-array
|
||||||
<a id="link-parameters-array"></a>
|
|
||||||
:marked
|
:marked
|
||||||
## Appendix: Link Parameters Array
|
## Appendix: Link Parameters Array
|
||||||
|
|
||||||
We've mentioned the *Link Parameters Array* several times. We've used it several times.
|
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:
|
A link parameters array holds the ingredients for router navigation:
|
||||||
|
@ -1750,19 +1858,27 @@ figure.image-display
|
||||||
* required and optional route parameters that go into the route URL
|
* required and optional route parameters that go into the route URL
|
||||||
|
|
||||||
We can bind the `RouterLink` directive to such an array like this:
|
We can bind the `RouterLink` directive to such an array like this:
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'h-anchor')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.3.ts', 'h-anchor', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We've written a two element array when specifying a route parameter like this
|
We've written a two element array when specifying a route parameter like this
|
||||||
+makeExample('router/ts/app/heroes/hero-list.component.1.ts', 'nav-to-detail')(format=".")
|
|
||||||
|
+makeExcerpt('app/heroes/hero-list.component.1.ts', 'nav-to-detail', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We can provide optional route parameters in an object like this:
|
We can provide optional route parameters in an object like this:
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'cc-query-params')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.3.ts', 'cc-query-params', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
These three examples cover our needs for an app with one level routing.
|
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.
|
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.
|
Recall that we specified a default child route for *Crisis Center* so this simple `RouterLink` is fine.
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'cc-anchor-w-default')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.3.ts', 'cc-anchor-w-default', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Let's parse it out.
|
Let's parse it out.
|
||||||
* The first item in the array identifies the parent route ('/crisis-center').
|
* The first item in the array identifies the parent route ('/crisis-center').
|
||||||
|
@ -1782,17 +1898,20 @@ figure.image-display
|
||||||
* We add `id` of the *Dragon Crisis* as the second item in the array (`1`)
|
* We add `id` of the *Dragon Crisis* as the second item in the array (`1`)
|
||||||
|
|
||||||
It looks like this!
|
It looks like this!
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'Dragon-anchor')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.3.ts', 'Dragon-anchor', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
If we wanted to, we could redefine our `AppComponent` template with *Crisis Center* routes exclusively:
|
If we wanted to, we could redefine our `AppComponent` template with *Crisis Center* routes exclusively:
|
||||||
+makeExample('router/ts/app/app.component.3.ts', 'template')(format=".")
|
|
||||||
|
+makeExcerpt('app/app.component.3.ts', 'template', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
In sum, we can write applications with one, two or more levels of routing.
|
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
|
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.
|
any legal sequence of route paths, (required) router parameters and (optional) route parameter objects.
|
||||||
|
|
||||||
<a id="onInit"></a>
|
.l-main-section#onInit
|
||||||
.l-main-section
|
|
||||||
:marked
|
:marked
|
||||||
## Appendix: Why use an *ngOnInit* method
|
## Appendix: Why use an *ngOnInit* method
|
||||||
|
|
||||||
|
@ -1890,7 +2009,9 @@ code-example(format=".", language="bash").
|
||||||
The preferred way to configure the strategy is to add a
|
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
|
[<base href> element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) tag
|
||||||
in the `<head>` of the `index.html`.
|
in the `<head>` of the `index.html`.
|
||||||
+makeExample('router/ts/index.1.html','base-href')(format=".")
|
|
||||||
|
+makeExcerpt('index.1.html', 'base-href', '')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Without that tag, the browser may not be able to load resources
|
Without that tag, the browser may not be able to load resources
|
||||||
(images, css, scripts) when "deep linking" into the app.
|
(images, css, scripts) when "deep linking" into the app.
|
||||||
|
@ -1914,4 +2035,5 @@ code-example(format=".", language="bash").
|
||||||
We can go old-school with the `HashLocationStrategy` by
|
We can go old-school with the `HashLocationStrategy` by
|
||||||
providing the `useHash: true` in an object as the second argument of the `RouterModule.forRoot`
|
providing the `useHash: true` in an object as the second argument of the `RouterModule.forRoot`
|
||||||
in our root NgModule.
|
in our root NgModule.
|
||||||
+makeExample('router/ts/app/app.module.4.ts','', 'app.module.ts (hash URL strategy)')
|
|
||||||
|
+makeExcerpt('app/app.module.4.ts (hash URL strategy)', '')
|
||||||
|
|
Loading…
Reference in New Issue