@ -3,10 +3,10 @@ include ../_util-fns
:marked
# Routing Around the App
We received new requirements for our Tour of Heroes application:
* a dd a *Dashboard* view.
* n avigate between the *Heroes* and *Dashboard* views.
* c licking on a hero in either view navigates to a detail view of the selected hero.
* c licking a *deep link* in an email opens the detail view for a particular hero;
* A dd a *Dashboard* view.
* N avigate between the *Heroes* and *Dashboard* views.
* C licking on a hero in either view navigates to a detail view of the selected hero.
* C licking a *deep link* in an email opens the detail view for a particular hero;
When we’ re done, users will be able to navigate the app like this:
figure.image-display
@ -16,7 +16,7 @@ figure.image-display
.l-sub-section
:marked
The [Routing and Navigation](../guide/router-deprecated.html) chapter covers the router in more detail
than we will in this tou r.
than we will in this tut orial .
p Run the #[+liveExampleLink2('', 'toh-5')] for this part.
@ -65,10 +65,10 @@ code-example(language="bash").
## Action plan
Here's our plan
* turn `AppComponent` into an application shell that only handles navigation.
* relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent`
* add routing
* create a new `DashboardComponent`
* turn `AppComponent` into an application shell that only handles navigation,
* relocate the *Heroes* concerns within the current `AppComponent` to a separate `HeroesComponent`,
* add routing,
* create a new `DashboardComponent`,
* tie the *Dashboard* into the navigation structure.
.l-sub-section
@ -91,13 +91,13 @@ code-example(language="bash").
Instead of moving anything out of `AppComponent`, we'll just rename it `HeroesComponent`
and create a new `AppComponent` shell separately.
The steps are:
* rename `app.component.ts` file to `heroes.component.ts`.
* rename the `AppComponent` class to `HeroesComponent`.
* rename the selector `my-app` to `my-heroes`.
The steps are: rename the
* `app.component.ts` file to `heroes.component.ts`,
* `AppComponent` class to `HeroesComponent`,
* selector `my-app` to `my-heroes`.
:marked
+makeExample('toh-5/ts/app/heroes.component.ts', 'heroes-component-renaming', 'app/heroes.component.ts (renaming)')(format=".")
+makeExample('toh-5/ts/app/heroes.component.ts', 'heroes-component-renaming', 'app/heroes.component.ts (showing renamings only )')(format=".")
:marked
## Create *AppComponent*
@ -154,10 +154,10 @@ code-example(language="bash").
The Angular router is a combination of multiple services (`ROUTER_PROVIDERS`), multiple directives (`ROUTER_DIRECTIVES`),
and a configuration decorator (`RouteConfig`). We'll import them all together:
+makeExample('toh-5/ts/app/app.component.2.ts', 'import-router', 'app.component.ts (router imports)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'import-router', 'app/app .component.ts (router imports)')(format=".")
:marked
Next we update the `directives` and `providers` metadata arrays to *include* the router assets.
+makeExample('toh-5/ts/app/app.component.2.ts', 'directives-and-providers', 'app.component.ts (directives and providers)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'directives-and-providers', 'app/app .component.ts (directives and providers)')(format=".")
:marked
Notice that we also removed the `HeroesComponent` from the `directives` array.
`AppComponent` no longer shows heroes; that will be the router's job.
@ -172,7 +172,7 @@ code-example(language="bash").
pastes a URL into the browser address bar.
Let's define our first route, a route to the `HeroesComponent`.
+makeExample('toh-5/ts/app/app.component.2.ts', 'route-config', 'app.component.ts (RouteConfig for heroes)')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'route-config', 'app/app .component.ts (RouteConfig for heroes)')(format=".")
:marked
`@RouteConfig` takes an array of *route definitions*.
We have only one route definition at the moment but rest assured, we'll add more.
@ -203,7 +203,7 @@ code-example(language="bash").
We add an anchor tag to the template which, when clicked, triggers navigation to the `HeroesComponent`.
The revised template looks like this:
+makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app.component.ts (template for Heroes )')(format=".")
+makeExample('toh-5/ts/app/app.component.2.ts', 'template', 'app/app.component.ts (template v1 )')(format=".")
:marked
Notice the `[routerLink]` binding in the anchor tag.
We bind the `RouterLink` directive (another of the `ROUTER_DIRECTIVES`) to an array
@ -250,7 +250,7 @@ code-example(language="bash").
Import the `DashboardComponent` so we can reference it in the dashboard route definition.
Add the following `'Dashboard'` route definition to the `@RouteConfig` array of definitions.
+makeExample('toh-5/ts/app/app.component.ts','dashboard-route', 'app.component.ts (Dashboard R oute)')(format=".")
+makeExample('toh-5/ts/app/app.component.ts','dashboard-route', 'app/app.component.ts (Dashboard r oute)')(format=".")
.l-sub-section
:marked
**useAsDefault**
@ -265,7 +265,7 @@ code-example(language="bash").
:marked
Finally, add a dashboard navigation link to the template, just above the *Heroes* link.
+makeExample('toh-5/ts/app/app.component.ts','template', 'app.component.ts (template)')(format=".")
+makeExample('toh-5/ts/app/app.component.ts','template', 'app/app .component.ts (template)')(format=".")
.l-sub-section
:marked
We nestled the two links within `<nav>` tags.
@ -288,7 +288,7 @@ code-example(language="bash").
We _can_ switch to [component-relative paths](../cookbook/component-relative-paths.html) if we prefer.
:marked
Create that file with these contents:
+makeExample('toh-5/ts/app/dashboard.component.html', null, 'dashboard.component.html')(format=".")
+makeExample('toh-5/ts/app/dashboard.component.html', null, 'app/ dashboard.component.html')(format=".")
:marked
We use `*ngFor` once again to iterate over a list of heroes and display their names.
We added extra `<div>` elements to help with styling later in this chapter.
@ -305,7 +305,7 @@ code-example(language="bash").
and added it to the `providers` array of the top level `AppComponent`.
That move created a singleton `HeroService` instance, available to *all* components of the application.
We'll inject and use it here in the `DashboardComponent` .
Angular will inject `HeroService` and we'll use it here in the `DashboardComponent` .
### Get heroes
Open the `dashboard.component.ts` and add the requisite `import` statements.
@ -364,7 +364,7 @@ code-example(format='').
### Configure a Route with a Parameter
Here's the *route definition* we'll use.
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (R oute to HeroDetailComponent)')(format=".")
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (r oute to HeroDetailComponent)')(format=".")
:marked
The colon (:) in the path indicates that `:id` is a placeholder to be filled with a specific hero `id`
when navigating to the `HeroDetailComponent`.
@ -389,19 +389,19 @@ code-example(format='').
:marked
## Revise the *HeroDetailComponent*
Before we rewrite the `HeroDetailComponent`, let's remember what it looks like now:
Before we rewrite the `HeroDetailComponent`, let's review what it looks like now:
+makeExample('toh-4/ts/app/hero-detail.component.ts', null, 'app/hero-detail.component.ts (current)')
:marked
The template won't change. We'll display a hero the same way. The big changes are driven by how we get the hero.
We will no longer receive the hero in a parent component property binding.
The new `HeroDetailComponent` should take the `id` parameter from the router's `RouteParams` service
and use the `HeroService` to fetch the hero with that `id` from storage .
and use the `HeroService` to fetch the hero with that `id`.
We need an import statement to reference the `RouteParams`.
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-route-params')(format=".")
:marked
We import the `HeroService`so we can fetch a hero` .
We import the `HeroService`so we can fetch a hero.
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'import-hero-service')(format=".")
:marked
We import the `OnInit` interface because we'll call the `HeroService` inside the `ngOnInit` component lifecycle hook.
@ -460,13 +460,11 @@ code-example(format='').
:marked
Here's the (nearly) finished `HeroDetailComponent`:
+makeExample('toh-5/ts/app/hero-detail.component.ts', 'v2', 'app/hero-detail.component.ts (latest)')(format=".")
:marked
.l-main-section
:marked
## Select a *Dashboard* Hero
When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero..
When a user selects a hero in the dashboard, the app should navigate to the `HeroDetailComponent` to view and edit the selected hero.
In the dashboard template we bound each hero's click event to the `gotoDetail` method, passing along the selected `hero` entity.
+makeExample('toh-5/ts/app/dashboard.component.html','click', 'app/dashboard.component.html (click binding)')(format=".")
@ -489,7 +487,7 @@ code-example(format='').
+makeExample('toh-5/ts/app/app.component.ts','hero-detail-route', 'app/app.component.ts (hero detail route)')(format=".")
:marked
The `DashboardComponent` doesn't have the router yet. We obtain it in the usual way:
` import` the `router` reference and inject it in the constructor (along with the `HeroService`):
import the `router` reference and inject it in the constructor (along with the `HeroService`):
+makeExample('toh-5/ts/app/dashboard.component.ts','import-router', 'app/dashboard.component.ts (excerpts)')(format=".")
+makeExample('toh-5/ts/app/dashboard.component.ts','ctor')(format=".")
@ -526,7 +524,7 @@ figure.image-display
### Format with the *UpperCasePipe*
Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect of the `UpperCasePipe`
that we slipped into the interpolation binding. Look for it right after the pipe operator, ( | ).
that we slipped into the interpolation binding. Look for it right after the pipe operator ( | ).
+makeExample('toh-5/ts/app/heroes.component.html','pipe')(format=".")
:marked
Pipes are a good way to format strings, currency amounts, dates and other display data.
@ -551,14 +549,14 @@ figure.image-display
So we can remove it from the metadata `directives` array. The `directives` array is now empty so we delete it.
We might as well delete the `HeroDetailComponent` import statement too.
The revised component metadata looks like this:
The revised `@Component` looks like this:
+makeExample('toh-5/ts/app/heroes.component.ts', 'metadata', 'app/heroes.component.ts (revised metadata)')(format=".")
:marked
Now we can see what's going on as we update the component class along the same lines as the dashboard:
1. Import the `router`
1. Inject the `router` in the constructor (along with the `HeroService`)
1. Implement the `gotoDetail` method by calling the `router.navigate` method
with a two-part 'HeroDetail' *link parameters array*.
with a two-part `HeroDetail` *link parameters array*.
Here's the revised component class:
+makeExample('toh-5/ts/app/heroes.component.ts', 'class', 'app/heroes.component.ts (class)')
@ -613,7 +611,7 @@ figure.image-display
We cooperated by surrounding those links in `<nav>` tags.
Add a `app.component.css` file to the `app` folder with the following content.
+makeExample('toh-5/ts/app/app.component.css', 'css', 'app/app.component.css (Navigation S tyles)')
+makeExample('toh-5/ts/app/app.component.css', '', 'app/app.component.css (navigation s tyles)')
.l-sub-section
:marked
**The *router-link-active* class**
@ -632,11 +630,20 @@ figure.image-display
We can also create styles at the *application level* outside of any component.
Our designers provided some basic styles to apply to elements across the entire app.
Add the following to a new file named `styles.css` in the root folder.
+makeExample('toh-5/ts/styles.1.css', '', 'styles.css (App Styles)')(format=".")
These correspond to the full set of master styles that we
introduced earlier (see
[QuickStart, "Add some style"](../quickstart.html#!#add-some-style)).
Here is an excerpt.
+makeExample('toh-5/ts/styles.1.css', 'toh-excerpt', 'styles.css (app styles excerpt)')(format=".")
- var styles_css = 'https://raw.githubusercontent.com/angular/angular.io/master/public/docs/_examples/styles.css'
:marked
Reference this stylesheet within the `index.html` in the traditional manner.
Add a new file named `styles.css` in the root folder, if there isn't one already.
Ensure that it contains the [master styles given here](!{styles_css}).
Also ensure this stylesheet is referenced in the traditional manner within `index.html`.
+makeExample('toh-5/ts/index.html','css', 'index.html (link ref)')(format=".")
:marked
Look at the app now. Our dashboard, heroes, and navigation links are styling!
@ -680,7 +687,6 @@ p.
.file systemjs.config.json
.file tsconfig.json
.file typings.json
:marked
.l-main-section
:marked
@ -689,15 +695,15 @@ p.
### The Road Behind
We travelled a great distance in this chapter.
- We added the Angular *Component Router* to navigate among different components.
- We learned how to create router links to represent navigation menu items
- We used router parameters to navigate to the details of user selected hero
- We shared the `HeroService` among multiple components
- We learned how to create router links to represent navigation menu items.
- We used router parameters to navigate to the details of user selected hero.
- We shared the `HeroService` among multiple components.
- We moved HTML and CSS out of the component file and into their own files.
- We added the `uppercase` pipe to format data
- We added the `uppercase` pipe to format data.
### The Road Ahead
We have much of the foundation we need to build an application.
We're still missing a key piece: remote data access.
In a forthcoming tutorial chapter,
In the next chapter,
we’ ll replace our mock data with data retrieved from a server using http.