diff --git a/aio/content/navigation.json b/aio/content/navigation.json
index cf1f2ea4d4..bb40ea706c 100644
--- a/aio/content/navigation.json
+++ b/aio/content/navigation.json
@@ -32,26 +32,22 @@
"tooltip": "Angular 开发文档",
"hidden": true
},
-
{
"url": "guide/docs-style-guide",
"title": "文档风格指南",
"tooltip": "给文档作者的风格指南",
"hidden": true
},
-
{
"url": "guide/webpack",
"title": "Webpack: 简介",
"hidden": true
},
-
{
"url": "guide/quickstart",
"title": "快速上手",
"tooltip": "Angular 破冰"
},
-
{
"title": "教程",
"tooltip": "此《英雄指南》教程会带你用 TypeScript 一步步创建一个 Angular 应用。",
@@ -78,7 +74,7 @@
},
{
"url": "tutorial/toh-pt3",
- "title": "5. 主从结构",
+ "title": "5. 主从组件",
"tooltip": "第五部分:把主从结构的页面重构成多个组件"
},
{
@@ -98,7 +94,6 @@
}
]
},
-
{
"title": "核心知识",
"tooltip": "学习 Angular 的核心知识",
@@ -226,14 +221,12 @@
}
]
},
-
{
"url": "guide/bootstrapping",
"title": "引导启动",
"tooltip": "在应用的根模块(AppModule)中告诉 Angular 如何构造并引导引用。"
},
{
-
"title": "NgModules",
"tooltip": "NgModules.",
"children": [
@@ -297,8 +290,8 @@
"title": "NgModule 常见问题",
"tooltip": "回答关于 NgModules 的常见问题。"
}
- ]},
-
+ ]
+ },
{
"title": "依赖注入",
"tooltip": "依赖注入:创建并注入各种服务。",
@@ -325,7 +318,6 @@
}
]
},
-
{
"url": "guide/http",
"title": "HttpClient",
@@ -346,13 +338,12 @@
"title": "速查表",
"tooltip": "关于 Angular 常用编码技术的快速指南。"
}
- ]},
-
+ ]
+ },
{
"title": "其它技术",
"tooltip": "把 Angular 用到你的实际工作中的一些技巧",
"children": [
-
{
"url": "guide/i18n",
"title": "国际化 (i18n)",
@@ -392,7 +383,6 @@
"title": "npm 包",
"tooltip": "建议的 npm 包,以及如何指定包的依赖。"
},
-
{
"url": "guide/typescript-configuration",
"title": "TypeScript 配置",
@@ -441,7 +431,6 @@
}
]
},
-
{
"title": "升级",
"tooltip": "渐进式的把 AngularJS 应用升级到 Angular。",
@@ -480,7 +469,6 @@
}
]
},
-
{
"title": "API 参考手册",
"tooltip": "关于 Angular 中类和值的详细信息。",
@@ -493,7 +481,6 @@
"hidden": true
}
],
-
"Footer": [
{
"title": "资源",
@@ -585,11 +572,18 @@
]
}
],
-
"docVersions": [
- { "title": "v4 (LTS)", "url": "https://v4.angular.io" },
- { "title": "v2", "url": "https://v2.angular.cn" },
- { "title": "AngularDart", "url": "https://webdev.dartlang.org/angular" }
-
+ {
+ "title": "v4 (LTS)",
+ "url": "https://v4.angular.io"
+ },
+ {
+ "title": "v2",
+ "url": "https://v2.angular.cn"
+ },
+ {
+ "title": "AngularDart",
+ "url": "https://webdev.dartlang.org/angular"
+ }
]
}
diff --git a/aio/content/tutorial/toh-pt0.md b/aio/content/tutorial/toh-pt0.md
index 78c21556aa..32467727b1 100644
--- a/aio/content/tutorial/toh-pt0.md
+++ b/aio/content/tutorial/toh-pt0.md
@@ -130,7 +130,7 @@ This interpolation binding presents the component's `title` property value
inside the HTML header tag.
双花括号语法是 Angular 的*插值绑定*语法。
-这个插值绑定的意思是把组件的 `title` 属性的值绑定到 HTML 中的 header 标记中。
+这个插值绑定的意思是把组件的 `title` 属性的值绑定到 HTML 中的 `h1` 标记中。
The browser refreshes and displays the new application title.
@@ -160,7 +160,7 @@ Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app.
## Final code review
-## 最终的代码
+## 查看最终代码
The source code for this tutorial and the complete _Tour of Heroes_ global styles
are available in the .
diff --git a/aio/content/tutorial/toh-pt1.md b/aio/content/tutorial/toh-pt1.md
index 12cfbf62ce..9006b90def 100644
--- a/aio/content/tutorial/toh-pt1.md
+++ b/aio/content/tutorial/toh-pt1.md
@@ -15,6 +15,8 @@ and place that component in the application shell.
Using the Angular CLI, generate a new component named `heroes`.
+使用 Angular CLI 创建一个名为 `heroes` 的新组件。
+
ng generate component heroes
@@ -24,8 +26,12 @@ Using the Angular CLI, generate a new component named `heroes`.
The CLI creates a new folder, `src/app/heroes/` and generates
the three files of the `HeroesComponent`.
+CLI 创建了一个新的文件夹 `src/app/heroes/`,并生成了 `HeroesComponent` 的三个文件。
+
The `HeroesComponent` class file is as follows:
+`HeroesComponent` 的类文件如下:
+
@@ -35,52 +41,85 @@ The `HeroesComponent` class file is as follows:
You always import the `Component` symbol from the Angular core library
and annotate the component class with `@Component`.
+你要从 Angular 核心库中导入 `Component` 符号,并为组件类加上 `@Component` 装饰器。
+
`@Component` is a decorator function that specifies the Angular metadata for the component.
+`@Component` 是个装饰器函数,用于为该组件指定 Angular 所需的元数据。
+
The CLI generated three metadata properties:
+CLI 自动生成了三个元数据属性:
+
1. `selector`— the component's CSS element selector
+ `selector`— 组件的选择器(CSS 元素选择器)
+
1. `templateUrl`— the location of the component's template file.
+ `templateUrl`— 组件模板文件的位置。
+
1. `styleUrls`— the location of the component's private CSS styles.
+ `styleUrls`— 组件私有 CSS 样式表文件的位置。
+
{@a selector}
The [CSS element selector](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors),
`'app-heroes'`, matches the name of the HTML element that identifies this component within a parent component's template.
+[CSS 元素选择器](https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors) `app-heroes` 用来在父组件的模板中匹配 HTML 元素的名称,以识别出该组件。
+
The `ngOnInit` is a [lifecycle hook](guide/lifecycle-hooks#oninit)
Angular calls `ngOnInit` shortly after creating a component.
It's a good place to put initialization logic.
+`ngOnInit` 是一个[生命周期钩子](guide/lifecycle-hooks#oninit),Angular 在创建完组件后很快就会调用 `ngOnInit`。这里是放置初始化逻辑的好地方。
+
Always `export` the component class so you can `import` it elsewhere ... like in the `AppModule`.
+始终要 `export` 这个组件类,以便在其它地方(比如 `AppModule`)导入它。
+
### Add a _hero_ property
+### 添加 `hero` 属性
+
Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
+往 `HeroesComponent` 中添加一个 `hero` 属性,用来表示一个名叫 “Windstorm” 的英雄。
+
### Show the hero
+### 显示英雄
+
Open the `heroes.component.html` template file.
Delete the default text generated by the Angular CLI and
replace it with a data binding to the new `hero` property.
+打开模板文件 `heroes.component.html`。删除 Angular CLI 自动生成的默认内容,改为到 `hero` 属性的数据绑定。
+
## Show the _HeroesComponent_ view
+## 显示 `HeroesComponent` 视图
+
To display the `HeroesComponent`, you must add it to the template of the shell `AppComponent`.
+要显示 `HeroesComponent` 你必须把它加到壳组件 `AppComponent` 的模板中。
+
Remember that `app-heroes` is the [element selector](#selector) for the `HeroesComponent`.
So add an `` element to the `AppComponent` template file, just below the title.
+别忘了,`app-heroes` 就是 `HeroesComponent` 的 [元素选择器](#selector)。
+所以,只要把 `` 元素添加到 `AppComponent` 的模板文件中就可以了,就放在标题下方。
+
@@ -88,24 +127,34 @@ So add an `` element to the `AppComponent` template file, just below
Assuming that the CLI `ng serve` command is still running,
the browser should refresh and display both the application title and the hero name.
+如果 CLI 的 `ng serve` 命令仍在运行,浏览器就会自动刷新,并且同时显示出应用的标题和英雄的名字。
+
## Create a Hero class
+## 创建 `Hero` 类
+
A real hero is more than a name.
+真实的英雄当然不止一个名字。
+
Create a `Hero` class in its own file in the `src/app` folder.
Give it `id` and `name` properties.
+在 `src/app` 文件夹中为 `Hero` 类创建一个文件,并添加 `id` 和 `name` 属性。
+
Return to the `HeroesComponent` class and import the `Hero` class.
+回到 `HeroesComponent` 类,并且导入这个 `Hero` 类。
+
Refactor the component's `hero` property to be of type `Hero`.
Initialize it with an `id` of `1` and the name `Windstorm`.
-现在,有了一个`Hero`类,我们把组件`hero`属性的类型换成`Hero`。
-然后以`1`为 id、以 “Windstorm” 为名字,初始化它。
+把组件的 `hero` 属性的类型重构为 `Hero`。
+然后以`1`为 `id`、以 “Windstorm” 为名字初始化它。
The revised `HeroesComponent` class file should look like this:
@@ -118,11 +167,17 @@ The revised `HeroesComponent` class file should look like this:
The page no longer displays properly because you changed the hero from a string to an object.
+页面显示变得不正常了,因为你刚刚把 `hero` 从字符串改成了对象。
+
## Show the hero object
+## 显示 `hero` 对象
+
Update the binding in the template to announce the hero's name
and show both `id` and `name` in a details layout like this:
+修改模板中的绑定,以显示英雄的名字,并在详情中显示 `id` 和 `name`,就像这样:
+
@@ -146,13 +205,20 @@ Modify the `hero.name` binding like this.
The browser refreshes and now the hero's name is displayed in capital letters.
+浏览器刷新了。现在,英雄的名字显示成了大写字母。
+
The word `uppercase` in the interpolation binding,
right after the pipe operator ( | ),
activates the built-in `UppercasePipe`.
+绑定表达式中的 `uppercase` 位于管道操作符( | )的右边,用来调用内置管道 `UppercasePipe`。
+
[Pipes](guide/pipes) are a good way to format strings, currency amounts, dates and other display data.
Angular ships with several built-in pipes and you can create your own.
+[管道](guide/pipes) 是格式化字符串、金额、日期和其它显示数据的好办法。
+Angular 发布了一些内置管道,而且你还可以创建自己的管道。
+
## Edit the hero
## 编辑英雄名字
@@ -215,26 +281,45 @@ Can't bind to 'ngModel' since it isn't a known property of 'input'.
Although `ngModel` is a valid Angular directive, it isn't available by default.
+虽然 `ngModel` 是一个有效的 Angular 指令,不过它在默认情况下是不可用的。
+
It belongs to the optional `FormsModule` and you must _opt-in_ to using it.
+它属于一个可选模块`FormsModule`,你必须自行添加此模块才能使用该指令。
+
## _AppModule_
Angular needs to know how the pieces of your application fit together
and what other files and libraries the app requires.
This information is called _metadata_
+Angular 需要知道如何把应用程序的各个部分组合到一起,以及该应用需要哪些其它文件和库。
+这些信息被称为*元数据(metadata)*。
+
Some of the metadata is in the `@Component` decorators that you added to your component classes.
Other critical metadata is in [`@NgModule`](guide/ngmodules) decorators.
+有些元数据位于 `@Component` 装饰器中,你会把它加到组件类上。
+另一些关键性的元数据位于 [`@NgModule`](guide/ngmodules) 装饰器中。
+
The most important `@NgModule`decorator annotates the top-level **AppModule** class.
+最重要的 `@NgModule` 装饰器位于顶级类 **AppModule** 上。
+
The Angular CLI generated an `AppModule` class in `src/app/app.module.ts` when it created the project.
This is where you _opt-in_ to the `FormsModule`.
+Angular CLI 在创建项目的时候就在 `src/app/app.module.ts` 中生成了一个 `AppModule` 类。
+这里也就是你要添加 `FormsModule` 的地方。
+
### Import _FormsModule_
+### 导入 `FormsModule`
+
Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the `@angular/forms` library.
+打开 `AppModule` (`app.module.ts`) 并从 `@angular/forms` 库中导入 `FormsModule` 符号。
+
@@ -242,6 +327,8 @@ Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
+然后把 `FormsModule` 添加到 `@NgModule` 元数据的 `imports` 数组中,这里是该应用所需外部模块的列表。
+
@@ -249,35 +336,53 @@ region="ng-imports">
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `
` above the textbox.
-浏览器刷新。又见到我们的英雄了。我们可以编辑英雄的名字,也能看到这个改动立刻体现在`
`中。
### Declare _HeroesComponent_
+### 声明 `HeroesComponent`
+
Every component must be declared in _exactly one_ [NgModule](guide/ngmodules).
+每个组件都必须声明在(且只能声明在)一个 [NgModule](guide/ngmodules) 中。
+
_You_ didn't declare the `HeroesComponent`.
So why did the application work?
+*你*没有声明过 `HeroesComponent`,可为什么本应用却正常呢?
+
It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component.
+这是因为 Angular CLI 在生成 `HeroesComponent` 组件的时候就自动把它加到了 `AppModule` 中。
+
Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
+打开 `src/app/app.module.ts` 你就会发现 `HeroesComponent` 已经在顶部导入过了。
+
The `HeroesComponent` is declared in the `@NgModule.declarations` array.
+`HeroesComponent` 也已经声明在了 `@NgModule.declarations` 数组中。
+
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.
+注意 `AppModule` 声明了应用中的所有组件,`AppComponent` 和 `HeroesComponent`。
+
## Final code review
+## 查看最终代码
+
Your app should look like this . Here are the code files discussed on this page.
+应用跑起来应该是这样的:。本页中所提及的代码如下:
+
@@ -308,15 +413,29 @@ Your app should look like this . Here are the code
* You used the CLI to create a second `HeroesComponent`.
+ 你使用 CLI 创建了第二个组件 `HeroesComponent`。
+
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
+ 你把 `HeroesComponent` 添加到了壳组件 `AppComponent` 中,以便显示它。
+
* You applied the `UppercasePipe` to format the name.
+ 你使用 `UppercasePipe` 来格式化英雄的名字。
+
* You used two-way data binding with the `ngModel` directive.
+ 你用 `ngModel` 指令实现了双向数据绑定。
+
* You learned about the `AppModule`.
+ 你知道了 `AppModule`。
+
* You imported the `FormsModule` in the `AppModule` so that Angular would recognize and apply the `ngModel` directive.
+ 你把 `FormsModule` 导入了 `AppModule`,以便 Angular 能识别并应用 `ngModel` 指令。
+
* You learned the importance of declaring components in the `AppModule`
and appreciated that the CLI declared it for you.
+
+ 你知道了把组件声明到 `AppModule` 是很重要的,并认识到 CLI 会自动帮你声明它。
diff --git a/aio/content/tutorial/toh-pt2.md b/aio/content/tutorial/toh-pt2.md
index ee999bec5a..31eab672d8 100644
--- a/aio/content/tutorial/toh-pt2.md
+++ b/aio/content/tutorial/toh-pt2.md
@@ -1,22 +1,35 @@
# Display a Heroes List
+# 显示英雄列表
+
In this page, you'll expand the Tour of Heroes app to display a list of heroes, and
allow users to select a hero and display the hero's details.
-我们需要管理多个英雄。我们将扩展《英雄指南》应用,让它显示一个英雄列表,
- 允许用户选择一个英雄,查看该英雄的详细信息。
+本页中,你将扩展《英雄指南》应用,让它显示一个英雄列表,
+并允许用户选择一个英雄,查看该英雄的详细信息。
## Create mock heroes
+## 创建模拟(mock)的英雄数据
+
You'll need some heroes to display.
+你需要一些英雄数据以供显示。
+
Eventually you'll get them from a remote data server.
For now, you'll create some _mock heroes_ and pretend they came from the server.
+最终,你会从远端的数据服务器获取它。
+不过目前,你要先创建一些*模拟的英雄数据*,并假装它们是从服务器上取到的。
+
Create a file called `mock-heroes.ts` in the `src/app/` folder.
Define a `HEROES` constant as an array of ten heroes and export it.
The file should look like this.
+在 `src/app/` 文件夹中创建一个名叫 `mock-heroes.ts` 的文件。
+定义一个包含十个英雄的常量数组 `HEROES`,并导出它。
+该文件是这样的。
+
@@ -24,42 +37,64 @@ title="src/app/mock-heroes.ts">
## Displaying heroes
-## 显示我们的英雄
+## 显示这些英雄
You're about to display the list of heroes at the top of the `HeroesComponent`.
+你要在 `HeroesComponent` 的顶部显示这个英雄列表。
+
Open the `HeroesComponent` class file and import the mock `HEROES`.
+打开 `HeroesComponent` 类文件,并导入模拟的 `HEROES`。
+
Add a `heroes` property to the class that exposes these heroes for binding.
+往类中添加一个 `heroes` 属性,这样可以暴露出这些英雄,以供绑定。
+
### List heroes with _*ngFor_
+### 使用 `*ngFor` 列出这些英雄
+
Open the `HeroesComponent` template file and make the following changes:
+打开 `HeroesComponent` 的模板文件,并做如下修改:
+
* Add an `
` at the top,
+ 在顶部添加 `
`,
+
* Below it add an HTML unordered list (`
`)
+ 然后添加表示无序列表的 HTML 元素(`
`)
+
* Insert an `
` within the `
` that displays properties of a `hero`.
+ 在 `
` 中插入一个 `
` 元素,以显示单个 `hero` 的属性。
+
* Sprinkle some CSS classes for styling (you'll add the CSS styles shortly).
+ 点缀上一些 CSS 类(稍后你还会添加更多 CSS 样式)。
+
Make it look like this:
+做完之后应该是这样的:
+
Now change the `
` to this:
+现在,把 `
` 修改成这样:
+
@@ -67,48 +102,78 @@ Now change the `
` to this:
The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive.
It repeats the host element for each element in a list.
+[`*ngFor`](guide/template-syntax#ngFor) 是一个 Angular 的复写器(repeater)指令。
+它会为列表中的每项数据复写它的宿主元素。
+
In this example
+在这个例子中
+
* `
` is the host element
+ `
` 就是 `*ngFor` 的宿主元素
+
* `heroes` is the list from the `HeroesComponent` class.
+ `heroes` 就是来自 `HeroesComponent` 类的列表。
+
* `hero` holds the current hero object for each iteration through the list.
+ 当依次遍历这个列表时,`hero` 会为每个迭代保存当前的英雄对象。
+
Don't forget the asterisk (*) in front of `ngFor`. It's a critical part of the syntax.
+不要忘了 `ngFor` 前面的星号(`*`),它是该语法中的关键部分。
+
After the browser refreshes, the list of heroes appears.
+浏览器刷新之后,英雄列表出现了。
+
{@a styles}
### Style the heroes
-### 给我们的英雄们“美容”
+### 给英雄们“美容”
The heroes list should be attractive and should respond visually when users
hover over and select a hero from the list.
+英雄列表应该富有吸引力,并且当用户把鼠标移到某个英雄上和从列表中选中某个英雄时,应该给出视觉反馈。
+
In the [first tutorial](tutorial/toh-pt0#app-wide-styles), you set the basic styles for the entire application in `styles.css`.
That stylesheet didn't include styles for this list of heroes.
+在[教程的第一章](tutorial/toh-pt0#app-wide-styles),你曾在 `styles.css` 中为整个应用设置了一些基础的样式。
+但那个样式表并不包含英雄列表所需的样式。
+
You could add more styles to `styles.css` and keep growing that stylesheet as you add components.
+固然,你可以把更多样式加入到 `styles.css`,并且放任它随着你添加更多组件而不断膨胀。
+
You may prefer instead to define private styles for a specific component and keep everything a component needs— the code, the HTML,
and the CSS —together in one place.
+但还有更好的方式。你可以定义属于特定组件的私有样式,并且让组件所需的一切(代码、HTML 和 CSS)都放在一起。
+
This approach makes it easier to re-use the component somewhere else
and deliver the component's intended appearance even if the global styles are different.
+这种方式让你在其它地方复用该组件更加容易,并且即使全局样式和这里不一样,组件也仍然具有期望的外观。
+
You define private styles either inline in the `@Component.styles` array or
as stylesheet file(s) identified in the `@Component.styleUrls` array.
+你可以用多种方式定义私有样式,或者内联在 `@Component.styles` 数组中,或者在 `@Component.styleUrls` 所指出的样式表文件中。
+
When the CLI generated the `HeroesComponent`, it created an empty `heroes.component.css` stylesheet for the `HeroesComponent`
and pointed to it in `@Component.styleUrls` like this.
+当 CLI 生成 `HeroesComponent` 时,它也同时为 `HeroesComponent` 创建了空白的 `heroes.component.css` 样式表文件,并且让 `@Component.styleUrls` 指向它,就像这样:
+
@@ -117,23 +182,37 @@ and pointed to it in `@Component.styleUrls` like this.
Open the `heroes.component.css` file and paste in the private CSS styles for the `HeroesComponent`.
You'll find them in the [final code review](#final-code-review) at the bottom of this guide.
+打开 `heroes.component.css` 文件,并且把 `HeroesComponent` 的私有 CSS 样式粘贴进去。
+你可以在本指南底部的[查看最终代码](#final-code-review)中找到它们。
+
Styles and stylesheets identified in `@Component` metadata are scoped to that specific component.
The `heroes.component.css` styles apply only to the `HeroesComponent` and don't affect the outer HTML or the HTML in any other component.
+`@Component` 元数据中指定的样式和样式表都是局限于该组件的。
+`heroes.component.css` 中的样式只会作用于 `HeroesComponent`,既不会影响到组件外的 HTML,也不会影响到其它组件中的 HTML。
+
## Master/Detail
+## 主从结构
+
When the user clicks a hero in the **master** list,
the component should display the selected hero's **details** at the bottom of the page.
+当用户在**主**列表中点击一个英雄时,该组件应该在页面底部显示所选英雄的**详情**。
+
In this section, you'll listen for the hero item click event
and update the hero detail.
+在本节,你将监听英雄条目的点击事件,并更新英雄的详情。
+
### Add a click event binding
+### 添加 `click` 事件绑定
+
Add a click event binding to the `
` like this:
我们再往`
`元素上插入一句点击事件的绑定代码:
@@ -144,40 +223,66 @@ Add a click event binding to the `
` like this:
This is an example of Angular's [event binding](guide/template-syntax#event-binding) syntax.
+这是 Angular [事件绑定](guide/template-syntax#event-binding) 语法的例子。
+
The parentheses around `click` tell Angular to listen for the `
` element's `click` event.
When the user clicks in the `
` 时,Angular 就会执行表达式 `onSelect(hero)`。
+
`onSelect()` is a `HeroesComponent` method that you're about to write.
Angular calls it with the `hero` object displayed in the clicked `
`,
the same `hero` defined previously in the `*ngFor` expression.
+`onSelect()` 是 `HeroesComponent` 上的一个方法,你很快就要写它。
+Angular 会把所点击的 `
` 上的 `hero` 对象传给它,这个 `hero` 也就是以前在 `*ngFor` 表达式中定义的那个。
+
### Add the click event handler
+### 添加 `click` 事件处理器
+
Rename the component's `hero` property to `selectedHero` but don't assign it.
There is no _selected hero_ when the application starts.
+把该组件的 `hero` 属性改名为 `selectedHero`,但不要为它赋值。
+因为应用刚刚启动时并没有*所选英雄*。
+
Add the following `onSelect()` method, which assigns the clicked hero from the template
to the component's `selectedHero`.
+添加如下 `onSelect()` 方法,它会把模板中被点击的英雄赋值给组件的 `selectedHero` 属性。
+
### Update the details template
+### 修改详情模板
+
The template still refers to the component's old `hero` property which no longer exists.
Rename `hero` to `selectedHero`.
+该模板引用的仍然是老的 `hero` 属性,但它已经不存在了。
+把 `hero` 改名为 `selectedHero`。
+
### Hide empty details with _*ngIf_
+### 使用 `*ngIf` 隐藏空白的详情
+
After the browser refreshes, the application is broken.
+刷新浏览器,应用挂了。
+
Open the browser developer tools and look in the console for an error message like this:
+打开浏览器的开发者工具,它的控制台中显示出如下错误信息:
+
HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined
@@ -188,23 +293,42 @@ Now click one of the list items.
The app seems to be working again.
The heroes appear in a list and details about the clicked hero appear at the bottom of the page.
+现在,从列表中随便点击一个条目。
+应用又正常了。
+英雄们显示在列表中,并且所点英雄的详情也显示在了页面的下方。
+
#### What happened?
+#### 怎么回事?
+
When the app starts, the `selectedHero` is `undefined` _by design_.
+当应用启动时,`selectedHero` 是 `undefined`,*设计如此*。
+
Binding expressions in the template that refer to properties of `selectedHero` — expressions like `{{selectedHero.name}}` — _must fail_ because there is no selected hero.
+但模板中的绑定表达式引用了 `selectedHero` 的属性(表达式为`{{selectedHero.name}}`),这必然会失败,因为你还没选过英雄呢。
+
#### The fix
+#### 修复
+
The component should only display the selected hero details if the `selectedHero` exists.
+该组件应该只有当 `selectedHero` 存在时才显示所选英雄的详情。
+
Wrap the hero detail HTML in a `
`.
Add Angular's `*ngIf` directive to the `
` and set it to `selectedHero`.
+把显示英雄详情的 HTML 包裹在一个`
`中。
+并且为这个 div 添加 Angular 的 `*ngIf` 指令,把它的值设置为 `selectedHero`。
+
Don't forget the asterisk (*) in front of `ngIf`. It's a critical part of the syntax.
+不要忘了 `ngIf` 前面的星号(`*`),它是该语法中的关键部分。
+
@@ -215,21 +339,35 @@ After the browser refreshes, the list of names reappears.
The details area is blank.
Click a hero and its details appear.
+浏览器刷新之后,英雄名字的列表又出现了。
+详情部分仍然是空。
+点击一个英雄,它的详情就出现了。
+
#### Why it works
+#### 为什么改好了?
+
When `selectedHero` is undefined, the `ngIf` removes the hero detail from the DOM. There are no `selectedHero` bindings to worry about.
+当 `selectedHero` 为 `undefined` 时,`ngIf` 从 DOM 中移除了英雄详情。因此也就不用担心 `selectedHero` 的绑定了。
+
When the user picks a hero, `selectedHero` has a value and
`ngIf` puts the hero detail into the DOM.
+当用户选择一个英雄时,`selectedHero` 也就有了值,并且 `ngIf` 把英雄的详情放回到 DOM 中。
+
### Style the selected hero
### 给所选英雄添加样式
It's difficult to identify the _selected hero_ in the list when all `
` elements look alike.
+所有的 `
` 元素看起来都是一样的,因此很难从列表中识别出*所选英雄*。
+
If the user clicks "Magneta", that hero should render with a distinctive but subtle background color like this:
+如果用户点击了“Magneta”,这个英雄应该用一个略有不同的背景色显示出来,就像这样:
+
### Send a message from `HeroService`
+### 从 `HeroService` 中发送一条消息
+
Modify the `getHeroes` method to send a message when the heroes are fetched.
+修改 `getHeroes` 方法,在获取到英雄数组时发送一条消息。
+
### Display the message from `HeroService`
+### 从 `HeroService` 中显示消息
+
The `MessagesComponent` should display all messages,
including the message sent by the `HeroService` when it fetches heroes.
+`MessagesComponent` 可以显示所有消息,
+包括当 `HeroService` 获取到英雄数据时发送的那条。
+
Open `MessagesComponent` and import the `MessageService`.
+打开 `MessagesComponent`,并且导入 `MessageService`。
+
@@ -386,7 +603,10 @@ Open `MessagesComponent` and import the `MessageService`.
Modify the constructor with a parameter that declares a **public** `messageService` property.
Angular will inject the singleton `MessageService` into that property
-when it creates the `HeroService`.
+when it creates the `MessagesComponent`.
+
+修改构造函数,添加一个 **public** 的 `messageService` 属性。
+Angular 将会在创建 `MessagesComponent` 的实例时 把 `MessageService` 的实例注入到这个属性中。
@@ -395,16 +615,24 @@ when it creates the `HeroService`.
The `messageService` property **must be public** because you're about to bind to it in the template.
+这个 `messageService` 属性必须是公开的,因为你将会在模板中绑定到它。
+
Angular only binds to _public_ component properties.
+Angular 只会绑定到组件的*公开*属性。
+
### Bind to the _MessageService_
+### 绑定到 `MessageService`
+
Replace the CLI-generated `MessagesComponent` template with the following.
+把 CLI 生成的 `MessagesComponent` 的模板改成这样:
+
@@ -413,26 +641,44 @@ Replace the CLI-generated `MessagesComponent` template with the following.
This template binds directly to the component's `messageService`.
+这个模板直接绑定到了组件的 `messageService` 属性上。
+
* The `*ngIf` only displays the messages area if there are messages to show.
+ `*ngIf` 只有当在有消息时才会显示消息区。
+
* An `*ngFor` presents the list of messages in repeated `
` elements.
+ `*ngFor` 用来在一系列 `
` 元素中展示消息列表。
+
* An Angular [event binding](guide/template-syntax#event-binding) binds the button's click event
to `MessageService.clear()`.
+ Angular 的[事件绑定](guide/template-syntax#event-binding)把按钮的`click`事件绑定到了`MessageService.clear()`。
+
The messages will look better when you add the private CSS styles to `messages.component.css`
as listed in one of the ["final code review"](#final-code-review) tabs below.
+当你把 [最终代码](#final-code-review) 某一页的内容添加到 `messages.component.css` 中时,这些消息会变得好看一些。
+
The browser refreshes and the page displays the list of heroes.
Scroll to the bottom to see the message from the `HeroService` in the message area.
Click the "clear" button and the message area disappears.
+刷新浏览器,页面显示出了英雄列表。
+滚动到底部,就会在消息区看到来自 `HeroService` 的消息。
+点击“清空”按钮,消息区不见了。
+
{@a final-code-review}
## Final code review
+## 查看最终代码
+
Here are the code files discussed on this page and your app should look like this .
+你的应用应该变成了这样 。本页所提及的代码文件如下:
+
`).
+ 你使用 RxJS 的 `of()` 方法返回了一个模拟英雄数据的*可观察对象* (`Observable`)。
+
* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor.
+ 在组件的 `ngOnInit` 生命周期钩子中调用 `HeroService` 方法,而不是构造函数中。
+
* You created a `MessageService` for loosely-coupled communication between classes.
+ 你创建了一个 `MessageService`,以便在类之间实现松耦合通讯。
+
* The `HeroService` injected into a component is created with another injected service,
`MessageService`.
+
+ `HeroService` 连同注入到它的服务 `MessageService` 一起,注入到了组件中。