` 元素添加一个 `routerLink` 属性。
You'll have to fix the private stylesheet (`heroes.component.css`) to make
the list look as it did before.
Revised styles are in the [final code review](#heroescomponent) at the bottom of this guide.
你还要修改私有样式表(`heroes.component.css`),让列表恢复到以前的外观。
修改后的样式表参见本指南底部的[最终代码](#heroescomponent)。
#### Remove dead code (optional)
#### 移除死代码(可选)
While the `HeroesComponent` class still works,
the `onSelect()` method and `selectedHero` property are no longer used.
虽然 `HeroesComponent` 类仍然能正常工作,但 `onSelect()` 方法和 `selectedHero` 属性已经没用了。
It's nice to tidy up and you'll be grateful to yourself later.
Here's the class after pruning away the dead code.
最好清理掉它们,将来你会体会到这么做的好处。
下面是删除了死代码之后的类。
## Routable *HeroDetailComponent*
## 支持路由的 `HeroDetailComponent`
Previously, the parent `HeroesComponent` set the `HeroDetailComponent.hero`
property and the `HeroDetailComponent` displayed the hero.
以前,父组件 `HeroesComponent` 会设置 `HeroDetailComponent.hero` 属性,然后 `HeroDetailComponent` 就会显示这个英雄。
`HeroesComponent` doesn't do that anymore.
Now the router creates the `HeroDetailComponent` in response to a URL such as `~/detail/11`.
`HeroesComponent` 已经不会再那么做了。
现在,当路由器会在响应形如 `~/detail/11` 的 URL 时创建 `HeroDetailComponent`。
The `HeroDetailComponent` needs a new way to obtain the _hero-to-display_.
`HeroDetailComponent` 需要从一种新的途径获取*要显示的英雄*。
* Get the route that created it,
获取创建本组件的路由,
* Extract the `id` from the route
从这个路由中提取出 `id`
* Acquire the hero with that `id` from the server via the `HeroService`
通过 `HeroService` 从服务器上获取具有这个 `id` 的英雄数据。
Add the following imports:
先添加下列导入语句:
{@a hero-detail-ctor}
Inject the `ActivatedRoute`, `HeroService`, and `Location` services
into the constructor, saving their values in private fields:
然后把 `ActivatedRoute`、`HeroService` 和 `Location` 服务注入到构造函数中,将它们的值保存到私有变量里:
The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`.
This component is interested in the route's bag of parameters extracted from the URL.
The _"id"_ parameter is the `id` of the hero to display.
[`ActivatedRoute`](api/router/ActivatedRoute) 保存着到这个 `HeroDetailComponent` 实例的路由信息。
这个组件对从 URL 中提取的路由参数感兴趣。
其中的 *`id`* 参数就是要显示的英雄的 `id`。
The [`HeroService`](tutorial/toh-pt4) gets hero data from the remote server
and this component will use it to get the _hero-to-display_.
[`HeroService`](tutorial/toh-pt4) 从远端服务器获取英雄数据,本组件将使用它来获取*要显示的英雄*。
The [`location`](api/common/Location) is an Angular service for interacting with the browser.
You'll use it [later](#goback) to navigate back to the view that navigated here.
[`location`](api/common/Location) 是一个 Angular 的服务,用来与浏览器打交道。
[稍后](#goback),你就会使用它来导航回上一个视图。
### Extract the _id_ route parameter
### 从路由参数中提取 `id`
In the `ngOnInit()` [lifecycle hook](guide/lifecycle-hooks#oninit)
call `getHero()` and define it as follows.
在 `ngOnInit()` [生命周期钩子](guide/lifecycle-hooks#oninit)
中调用 `getHero()`,代码如下:
The `route.snapshot` is a static image of the route information shortly after the component was created.
`route.snapshot` 是一个路由信息的静态快照,抓取自组件刚刚创建完毕之后。
The `paramMap` is a dictionary of route parameter values extracted from the URL.
The `"id"` key returns the `id` of the hero to fetch.
`paramMap` 是一个从 URL 中提取的路由参数值的字典。
`"id"` 对应的值就是要获取的英雄的 `id`。
Route parameters are always strings.
The JavaScript (+) operator converts the string to a number,
which is what a hero `id` should be.
路由参数总会是字符串。
JavaScript 的 (+) 操作符会把字符串转换成数字,英雄的 `id` 就是数字类型。
The browser refreshes and the app crashes with a compiler error.
`HeroService` doesn't have a `getHero()` method.
Add it now.
刷新浏览器,应用挂了。出现一个编译错误,因为 `HeroService` 没有一个名叫 `getHero()` 的方法。
这就添加它。
### Add `HeroService.getHero()`
### 添加 `HeroService.getHero()`
Open `HeroService` and add this `getHero()` method
添加 `HeroService`,并添加如下的 `getHero()` 方法
Note the backticks ( ` ) that
define a JavaScript
[_template literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for embedding the `id`.
注意,反引号 ( ` ) 用于定义 JavaScript 的 [模板字符串字面量](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals),以便嵌入 `id`。
Like [`getHeroes()`](tutorial/toh-pt4#observable-heroservice),
`getHero()` has an asynchronous signature.
It returns a _mock hero_ as an `Observable`, using the RxJS `of()` function.
像 [`getHeroes()`](tutorial/toh-pt4#observable-heroservice) 一样,`getHero()` 也有一个异步函数签名。
它用 RxJS 的 `of()` 函数返回一个 `Observable` 形式的*模拟英雄数据*。
You'll be able to re-implement `getHero()` as a real `Http` request
without having to change the `HeroDetailComponent` that calls it.
你将来可以用一个真实的 `Http` 请求来重新实现 `getHero()`,而不用修改调用了它的 `HeroDetailComponent`。
#### Try it
#### 试试看
The browser refreshes and the app is working again.
You can click a hero in the dashboard or in the heroes list and navigate to that hero's detail view.
刷新浏览器,应用又恢复正常了。
你可以在仪表盘或英雄列表中点击一个英雄来导航到该英雄的详情视图。
If you paste `localhost:4200/detail/11` in the browser address bar,
the router navigates to the detail view for the hero with `id: 11`, "Mr. Nice".
如果你在浏览器的地址栏中粘贴了 `localhost:4200/detail/11`,路由器也会导航到 `id: 11` 的英雄("Mr. Nice")的详情视图。
{@a goback}
### Find the way back
### 回到原路
By clicking the browser's back button,
you can go back to the hero list or dashboard view,
depending upon which sent you to the detail view.
通过点击浏览器的后退按钮,你可以回到英雄列表或仪表盘视图,这取决于你从哪里进入的详情视图。
It would be nice to have a button on the `HeroDetail` view that can do that.
如果能在 `HeroDetail` 视图中也有这么一个按钮就更好了。
Add a *go back* button to the bottom of the component template and bind it
to the component's `goBack()` method.
把一个*后退*按钮添加到组件模板的底部,并且把它绑定到组件的 `goBack()` 方法。
Add a `goBack()` _method_ to the component class that navigates backward one step
in the browser's history stack
using the `Location` service that you [injected previously](#hero-detail-ctor).
在组件类中添加一个 `goBack()` 方法,利用[你以前注入的](#hero-detail-ctor) `Location` 服务在浏览器的历史栈中后退一步。
Refresh the browser and start clicking.
Users can navigate around the app, from the dashboard to hero details and back,
from heroes list to the mini detail to the hero details and back to the heroes again.
刷新浏览器,并开始点击。
用户能在应用中导航:从仪表盘到英雄详情再回来,从英雄列表到 mini 版英雄详情到英雄详情,再回到英雄列表。
You've met all of the navigational requirements that propelled this page.
你已经满足了在本章开头设定的所有导航需求。
## Final code review
## 查看最终代码
Here are the code files discussed on this page and your app should look like this .
你的应用应该变成了这样 。本页所提及的代码文件如下:
{@a approutingmodule}
{@a appmodule}
#### _AppRoutingModule_, _AppModule_, and _HeroService_
#### `AppRoutingModule`、`AppModule` 和 `HeroService`
{@a appcomponent}
#### _AppComponent_
{@a dashboardcomponent}
#### _DashboardComponent_
{@a heroescomponent}
#### _HeroesComponent_
{@a herodetailcomponent}
#### _HeroDetailComponent_
## Summary
## 小结
* You added the Angular router to navigate among different components.
添加了 Angular *路由器*在各个不同组件之间导航。
* You turned the `AppComponent` into a navigation shell with `