Add some blank lines, to avoid unnecessary conflicts on merging.

This commit is contained in:
Zhicheng Wang 2016-06-15 23:31:28 +08:00
parent c1b8183c38
commit 20c59f9e4a
6 changed files with 187 additions and 1 deletions

View File

@ -32,7 +32,7 @@
}, },
"toh-pt6": { "toh-pt6": {
"title": "Http", "title": "Http",
"intro": "We convert our service and components to use Http", "intro": "把我们的服务和组件改用Http实现",
"nextable": true "nextable": true
} }
} }

View File

@ -3,6 +3,7 @@ include ../_util-fns
// #docregion intro // #docregion intro
:marked :marked
# Tour of Heroes: the vision # Tour of Heroes: the vision
# 《英雄指南》目标概览 # 《英雄指南》目标概览
Our grand plan is to build an app to help a staffing agency manage its stable of heroes. Our grand plan is to build an app to help a staffing agency manage its stable of heroes.
@ -53,6 +54,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-6')]。
.l-main-section .l-main-section
:marked :marked
## The End Game ## The End Game
## 游戏的终点 ## 游戏的终点
Here's a visual idea of where we're going in this tour, beginning with the "Dashboard" Here's a visual idea of where we're going in this tour, beginning with the "Dashboard"
@ -118,6 +120,7 @@ figure.image-display
.l-main-section .l-main-section
:marked :marked
## Up Next ## Up Next
## 接下来 ## 接下来
Well build this Tour of Heroes together, step by step. Well build this Tour of Heroes together, step by step.

View File

@ -2,6 +2,7 @@ include ../_util-fns
:marked :marked
# Once Upon a Time # Once Upon a Time
# 很久很久以前 # 很久很久以前
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends. Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
@ -41,7 +42,9 @@ include ../_quickstart_repo
.file typings.json .file typings.json
:marked :marked
## Keep the app transpiling and running ## Keep the app transpiling and running
## 保持应用不断转译和运行 ## 保持应用不断转译和运行
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
我们要启动TypeScript编译器它会监视文件变更并且启动开发服务器。我们只要敲 我们要启动TypeScript编译器它会监视文件变更并且启动开发服务器。我们只要敲
@ -58,7 +61,9 @@ code-example(language="bash").
.l-main-section .l-main-section
:marked :marked
## Show our Hero ## Show our Hero
## 显示我们的英雄 ## 显示我们的英雄
We want to display Hero data in our app We want to display Hero data in our app
我们要在应用中显示英雄数据 我们要在应用中显示英雄数据
@ -92,8 +97,10 @@ code-example(language="bash").
Learn more about interpolation in the [Displaying Data chapter](../guide/displaying-data.html). Learn more about interpolation in the [Displaying Data chapter](../guide/displaying-data.html).
要了解插值表达式的更多知识,参阅[“显示数据”一章](../guide/displaying-data.html)。 要了解插值表达式的更多知识,参阅[“显示数据”一章](../guide/displaying-data.html)。
:marked :marked
### Hero object ### Hero object
### Hero对象 ### Hero对象
At the moment, our hero is just a name. Our hero needs more properties. At the moment, our hero is just a name. Our hero needs more properties.
@ -132,7 +139,9 @@ code-example(language="bash").
浏览器自动刷新,并继续显示这位英雄的名字。 浏览器自动刷新,并继续显示这位英雄的名字。
### Adding more HTML ### Adding more HTML
### 添加更多的HTML ### 添加更多的HTML
Displaying a name is good, but we want to see all of our heros properties. Displaying a name is good, but we want to see all of our heros properties.
Well add a `<div>` for our heros `id` property and another `<div>` for our heros `name`. Well add a `<div>` for our heros `id` property and another `<div>` for our heros `name`.
@ -146,6 +155,7 @@ code-example(language="bash").
啊哦!我们的模板字符串已经太长了。我们最好小心点,免得在模板中出现拼写错误。 啊哦!我们的模板字符串已经太长了。我们最好小心点,免得在模板中出现拼写错误。
### Multi-line template strings ### Multi-line template strings
### 多行模板字符串 ### 多行模板字符串
We could make a more readable template with string concatenation We could make a more readable template with string concatenation
@ -166,7 +176,9 @@ code-example(language="bash").
.callout.is-important .callout.is-important
header A back-tick is not a single quote header A back-tick is not a single quote
header 反引号不是单引号 header 反引号不是单引号
:marked :marked
**Be careful!** A back-tick (`) looks a lot like a single quote ('). **Be careful!** A back-tick (`) looks a lot like a single quote (').
It's actually a completely different character. It's actually a completely different character.
@ -183,6 +195,7 @@ code-example(language="bash").
.l-main-section .l-main-section
:marked :marked
## Editing Our Hero ## Editing Our Hero
## 编辑我们的英雄 ## 编辑我们的英雄
We want to be able to edit the hero name in a textbox. We want to be able to edit the hero name in a textbox.
@ -194,6 +207,7 @@ code-example(language="bash").
把英雄的名字从单纯的`<label>`重构成`<label>`和`<input>`元素的组合,就像下面这样: 把英雄的名字从单纯的`<label>`重构成`<label>`和`<input>`元素的组合,就像下面这样:
+makeExample('toh-1/ts-snippets/app.component.snippets.pt1.ts', 'editing-Hero', 'app.component.ts (input元素)') +makeExample('toh-1/ts-snippets/app.component.snippets.pt1.ts', 'editing-Hero', 'app.component.ts (input元素)')
:marked :marked
We see in the browser that the heros name does appear in the `<input>` textbox. We see in the browser that the heros name does appear in the `<input>` textbox.
But something doesnt feel right. But something doesnt feel right.
@ -205,6 +219,7 @@ code-example(language="bash").
当修改名字时,我们的改动并没有反映到`<h2>`中。使用单向数据绑定,我们没法实现所期望的这种行为。 当修改名字时,我们的改动并没有反映到`<h2>`中。使用单向数据绑定,我们没法实现所期望的这种行为。
### Two-Way Binding ### Two-Way Binding
### 双向绑定 ### 双向绑定
We intend to display the name of the hero in the `<input>`, change it, We intend to display the name of the hero in the `<input>`, change it,
@ -226,6 +241,7 @@ code-example(language="bash").
要学习关于`ngModel`的更多知识,参见[表单](../guide/forms.html#ngModel)和 要学习关于`ngModel`的更多知识,参见[表单](../guide/forms.html#ngModel)和
[模板语法](../guide/template-syntax.html#ngModel)两章 [模板语法](../guide/template-syntax.html#ngModel)两章
:marked :marked
Replace the `<input>` with the following HTML Replace the `<input>` with the following HTML
@ -243,20 +259,29 @@ code-example(language="html").
.l-main-section .l-main-section
:marked :marked
## The Road Weve Travelled ## The Road Weve Travelled
## 我们已经走过的路 ## 我们已经走过的路
Lets take stock of what weve built. Lets take stock of what weve built.
我们来盘点一下已经构建完成的部分。 我们来盘点一下已经构建完成的部分。
* Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding) * Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding)
to display the application title and properties of a `Hero` object. to display the application title and properties of a `Hero` object.
* 我们的《英雄指南》使用双大括号(插值表达式 —— 单向数据绑定的一种形式)来显示应用的标题和`Hero`对象的属性。 * 我们的《英雄指南》使用双大括号(插值表达式 —— 单向数据绑定的一种形式)来显示应用的标题和`Hero`对象的属性。
* We wrote a multi-line template using ES2015s template strings to make our template readable. * We wrote a multi-line template using ES2015s template strings to make our template readable.
* 我们使用ES2105的模板字符串写了一个多行模板来让我们的模板更有可读性。 * 我们使用ES2105的模板字符串写了一个多行模板来让我们的模板更有可读性。
* We can both display and change the heros name after adding a two-way data binding to the `<input>` element * We can both display and change the heros name after adding a two-way data binding to the `<input>` element
using the built-in `ngModel` directive. using the built-in `ngModel` directive.
* 为了同时显示和修改英雄的名字,我们还使用了内建的`ngModel`指令,往`<input>`元素上添加了双向数据绑定。 * 为了同时显示和修改英雄的名字,我们还使用了内建的`ngModel`指令,往`<input>`元素上添加了双向数据绑定。
* The `ngModel` directive also propagates changes to every other binding of the `hero.name`. * The `ngModel` directive also propagates changes to every other binding of the `hero.name`.
* 通过`ngModel`指令,这些修改还影响到了每一个对`hero.name`的其它绑定。 * 通过`ngModel`指令,这些修改还影响到了每一个对`hero.name`的其它绑定。
p Run the #[+liveExampleLink2('', 'toh-1')] for this part. p Run the #[+liveExampleLink2('', 'toh-1')] for this part.
@ -273,7 +298,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-1')]。
.l-main-section .l-main-section
:marked :marked
## The Road Ahead ## The Road Ahead
## 前方的路 ## 前方的路
Our Tour of Heroes only displays one hero and we really want to display a list of heroes. Our Tour of Heroes only displays one hero and we really want to display a list of heroes.
We also want to allow the user to select a hero and display their details. We also want to allow the user to select a hero and display their details.
Well learn more about how to retrieve lists, bind them to the Well learn more about how to retrieve lists, bind them to the

View File

@ -2,7 +2,9 @@ include ../_util-fns
:marked :marked
# It Takes Many Heroes # It Takes Many Heroes
# 需要多个英雄 # 需要多个英雄
Our story needs more heroes. Our story needs more heroes.
Well expand our Tour of Heroes app to display a list of heroes, Well expand our Tour of Heroes app to display a list of heroes,
allow the user to select a hero, and display the heros details. allow the user to select a hero, and display the heros details.
@ -24,7 +26,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
.l-main-section .l-main-section
:marked :marked
## Where We Left Off ## Where We Left Off
## 我们在哪儿 ## 我们在哪儿
Before we continue with Part 2 of the Tour of Heroes, Before we continue with Part 2 of the Tour of Heroes,
lets verify we have the following structure after [Part 1](./toh-pt1.html). lets verify we have the following structure after [Part 1](./toh-pt1.html).
If not, well need to go back to Part 1 and figure out what we missed. If not, well need to go back to Part 1 and figure out what we missed.
@ -48,7 +52,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
.file typings.json .file typings.json
:marked :marked
### Keep the app transpiling and running ### Keep the app transpiling and running
### 让应用代码保持转译和运行 ### 让应用代码保持转译和运行
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。我们只要敲 我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。我们只要敲
@ -64,9 +70,13 @@ code-example(language="bash").
.l-main-section .l-main-section
:marked :marked
## Displaying Our Heroes ## Displaying Our Heroes
## 显示我们的英雄 ## 显示我们的英雄
### Creating heroes ### Creating heroes
### 创建英雄 ### 创建英雄
Lets create an array of ten heroes at the bottom of `app.component.ts`. Lets create an array of ten heroes at the bottom of `app.component.ts`.
我们先在`app.component.ts`的底部创建一个由十位英雄组成的数组。 我们先在`app.component.ts`的底部创建一个由十位英雄组成的数组。
@ -83,7 +93,9 @@ code-example(language="bash").
我们当然希望从一个Web服务中获取这个英雄列表但别急我们得把步子迈得小一点儿 —— 先用一组Mock(模拟)出来的英雄。 我们当然希望从一个Web服务中获取这个英雄列表但别急我们得把步子迈得小一点儿 —— 先用一组Mock(模拟)出来的英雄。
### Exposing heroes ### Exposing heroes
### 导出英雄们 ### 导出英雄们
Lets create a public property in `AppComponent` that exposes the heroes for binding. Lets create a public property in `AppComponent` that exposes the heroes for binding.
我们在`AppComponent`上创建一个公开属性,用来暴露这些英雄,以供绑定。 我们在`AppComponent`上创建一个公开属性,用来暴露这些英雄,以供绑定。
@ -94,6 +106,7 @@ code-example(language="bash").
We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array. We did not have to define the `heroes` type. TypeScript can infer it from the `HEROES` array.
我们并不需要明确定义`heroes`属性的数据类型TypeScript能从`HEROES`数组中推断出来。 我们并不需要明确定义`heroes`属性的数据类型TypeScript能从`HEROES`数组中推断出来。
.l-sub-section .l-sub-section
:marked :marked
We could have defined the heroes list here in this component class. We could have defined the heroes list here in this component class.
@ -104,9 +117,12 @@ code-example(language="bash").
我们已经把英雄列表定义在了这个组件类中。 我们已经把英雄列表定义在了这个组件类中。
但显然,我们最终还是得从一个数据服务中获取这些英雄。 但显然,我们最终还是得从一个数据服务中获取这些英雄。
正因如此,我们从一开始就要有意识的把英雄数据隔离到一个类中来实现。 正因如此,我们从一开始就要有意识的把英雄数据隔离到一个类中来实现。
:marked :marked
### Displaying heroes in a template ### Displaying heroes in a template
### 在一个模板中显示英雄 ### 在一个模板中显示英雄
Our component has `heroes`. Lets create an unordered list in our template to display them. Our component has `heroes`. Lets create an unordered list in our template to display them.
Well insert the following chunk of HTML below the title and above the hero details. Well insert the following chunk of HTML below the title and above the hero details.
@ -121,6 +137,7 @@ code-example(language="bash").
现在,我们有了一个模板。接下来,就用英雄们的数据来填充它。 现在,我们有了一个模板。接下来,就用英雄们的数据来填充它。
### Listing heroes with ngFor ### Listing heroes with ngFor
### 通过ngFor来显示英雄列表 ### 通过ngFor来显示英雄列表
We want to bind the array of `heroes` in our component to our template, iterate over them, We want to bind the array of `heroes` in our component to our template, iterate over them,
@ -187,7 +204,9 @@ code-example(language="bash").
当浏览器刷新时,我们就看到了英雄列表。 当浏览器刷新时,我们就看到了英雄列表。
### Styling our heroes ### Styling our heroes
### 给我们的英雄们“美容” ### 给我们的英雄们“美容”
Our list of heroes looks pretty bland. Our list of heroes looks pretty bland.
We want to make it visually obvious to a user which hero we are hovering over and which hero is selected. We want to make it visually obvious to a user which hero we are hovering over and which hero is selected.
@ -224,7 +243,9 @@ code-example(language="bash").
.l-main-section .l-main-section
:marked :marked
## Selecting a Hero ## Selecting a Hero
## 选择英雄 ## 选择英雄
We have a list of heroes and we have a single hero displayed in our app. We have a list of heroes and we have a single hero displayed in our app.
The list and the single hero are not connected in any way. The list and the single hero are not connected in any way.
We want the user to select a hero from our list, and have the selected hero appear in the details view. We want the user to select a hero from our list, and have the selected hero appear in the details view.
@ -242,7 +263,9 @@ code-example(language="bash").
我们通过组件中的一个`selectedHero`属性来连接主从视图。它被绑定到了click事件上。 我们通过组件中的一个`selectedHero`属性来连接主从视图。它被绑定到了click事件上。
### Click event ### Click event
### click事件 ### click事件
We modify the `<li>` by inserting an Angular event binding to its click event. We modify the `<li>` by inserting an Angular event binding to its click event.
我们往`<li>`元素上插入一句Angular事件绑定代码绑定到它的click事件。 我们往`<li>`元素上插入一句Angular事件绑定代码绑定到它的click事件。
@ -253,8 +276,10 @@ code-example(language="bash").
Focus on the event binding Focus on the event binding
事件绑定详解 事件绑定详解
code-example(format="." language="bash"). code-example(format="." language="bash").
(click)="onSelect(hero)" (click)="onSelect(hero)"
:marked :marked
The parenthesis identify the `<li>` elements `click` event as the target. The parenthesis identify the `<li>` elements `click` event as the target.
The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`, The expression to the right of the equal sign calls the `AppComponent` method, `onSelect()`,
@ -277,7 +302,9 @@ code-example(language="bash").
:marked :marked
### Add the click handler ### Add the click handler
### 添加click事件处理器 ### 添加click事件处理器
Our event binding refers to an `onSelect` method that doesnt exist yet. Our event binding refers to an `onSelect` method that doesnt exist yet.
Well add that method to our component now. Well add that method to our component now.
@ -293,6 +320,7 @@ code-example(language="bash").
我们的组件还没有用来表示“当前选中的英雄”的变量,我们就从这一步儿开始。 我们的组件还没有用来表示“当前选中的英雄”的变量,我们就从这一步儿开始。
### Expose the selected hero ### Expose the selected hero
### 导出“当前选中的英雄” ### 导出“当前选中的英雄”
We no longer need the static `hero` property of the `AppComponent`. We no longer need the static `hero` property of the `AppComponent`.
@ -324,8 +352,10 @@ code-example(language="bash").
我们这就修改模板,让它绑定到新的`selectedHero`属性上去。 我们这就修改模板,让它绑定到新的`selectedHero`属性上去。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (template excerpt)') +makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (template excerpt)')
:marked :marked
### Hide the empty detail with ngIf ### Hide the empty detail with ngIf
### 利用ngIf隐藏空的详情 ### 利用ngIf隐藏空的详情
When our app loads we see a list of heroes, but a hero is not selected. When our app loads we see a list of heroes, but a hero is not selected.
@ -335,6 +365,7 @@ code-example(language="bash").
当应用刚加载时,我们会看到一个英雄列表,但还没有任何英雄被选中。 当应用刚加载时,我们会看到一个英雄列表,但还没有任何英雄被选中。
`selectedHero`属性是`undefined`。 `selectedHero`属性是`undefined`。
因此,我们会看到浏览器控制台中出现下列错误: 因此,我们会看到浏览器控制台中出现下列错误:
code-example(language="html"). code-example(language="html").
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null] EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
@ -402,6 +433,7 @@ code-example(language="bash").
正如我们所预期的那样。 正如我们所预期的那样。
### Styling the selection ### Styling the selection
### 给所选英雄添加样式 ### 给所选英雄添加样式
We see the selected hero in the details area below but we cant quickly locate that hero in the list above. We see the selected hero in the details area below but we cant quickly locate that hero in the list above.
@ -415,6 +447,7 @@ code-example(language="bash").
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="选中的英雄") img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="选中的英雄")
:marked :marked
Well add a property binding on `class` for the `selected` class to the template. We'll set this to an expression that compares the current `selectedHero` to the `hero`. Well add a property binding on `class` for the `selected` class to the template. We'll set this to an expression that compares the current `selectedHero` to the `hero`.
@ -425,7 +458,9 @@ code-example(language="bash").
关键是CSS类的名字`selected`。当两位英雄一致时,它为`true`,否则为`false`。 关键是CSS类的名字`selected`。当两位英雄一致时,它为`true`,否则为`false`。
也就是说:“*当两位英雄匹配时,应用上`selected`类,否则不应用*”。 也就是说:“*当两位英雄匹配时,应用上`selected`类,否则不应用*”。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (setting the CSS class)')(format=".") +makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (setting the CSS class)')(format=".")
:marked :marked
Notice in the template that the `class.selected` is surrounded in square brackets (`[]`). Notice in the template that the `class.selected` is surrounded in square brackets (`[]`).
This is the syntax for a **property binding**, a binding in which data flows one way This is the syntax for a **property binding**, a binding in which data flows one way
@ -450,6 +485,7 @@ code-example(language="bash").
浏览器重新加载了你的应用。 浏览器重新加载了你的应用。
我们选中英雄Magneta于是他通过背景色的变化被清晰的标记了出来。 我们选中英雄Magneta于是他通过背景色的变化被清晰的标记了出来。
figure.image-display figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="英雄列表应用的输出") img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="英雄列表应用的输出")
@ -467,16 +503,23 @@ code-example(language="bash").
.l-main-section .l-main-section
:marked :marked
## The Road Weve Travelled ## The Road Weve Travelled
## 已走的路 ## 已走的路
Heres what we achieved in this chapter: Heres what we achieved in this chapter:
在本章中,我们达成了这些: 在本章中,我们达成了这些:
* Our Tour of Heroes now displays a list of selectable heroes * Our Tour of Heroes now displays a list of selectable heroes
* 我们的《英雄指南》现在显示一个可选英雄的列表 * 我们的《英雄指南》现在显示一个可选英雄的列表
* We added the ability to select a hero and show the heros details * We added the ability to select a hero and show the heros details
* 我们添加了选择英雄的能力,并且会显示这个英雄的详情 * 我们添加了选择英雄的能力,并且会显示这个英雄的详情
* We learned how to use the built-in directives `ngIf` and `ngFor` in a components template * We learned how to use the built-in directives `ngIf` and `ngFor` in a components template
* 我们学会了如何在组件模板中使用内建的`ngIf`和`ngFor`指令 * 我们学会了如何在组件模板中使用内建的`ngIf`和`ngFor`指令
p Run the #[+liveExampleLink2('', 'toh-2')] for this part. p Run the #[+liveExampleLink2('', 'toh-2')] for this part.
@ -485,7 +528,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
:marked :marked
### The Road Ahead ### The Road Ahead
### 前方的路 ### 前方的路
Our Tour of Heroes has grown, but its far from complete. Our Tour of Heroes has grown, but its far from complete.
We can't put the entire app into a single component. We can't put the entire app into a single component.
We need to break it up into sub-components and teach them to work together We need to break it up into sub-components and teach them to work together

View File

@ -14,7 +14,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
.l-main-section .l-main-section
:marked :marked
## Where We Left Off ## Where We Left Off
## 我们在哪儿 ## 我们在哪儿
Before we continue with our Tour of Heroes, lets verify we have the following structure. If not, well need to go back and follow the previous chapters. Before we continue with our Tour of Heroes, lets verify we have the following structure. If not, well need to go back and follow the previous chapters.
在继续《英雄指南》之前,先来检查一下,你是否已经有了如下目录结构。如果没有,你得先回上一章,看看错过了哪里。 在继续《英雄指南》之前,先来检查一下,你是否已经有了如下目录结构。如果没有,你得先回上一章,看看错过了哪里。
@ -34,9 +36,12 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
.file systemjs.config.js .file systemjs.config.js
.file tsconfig.json .file tsconfig.json
.file typings.json .file typings.json
:marked :marked
### Keep the app transpiling and running ### Keep the app transpiling and running
### 让应用代码保持转译和运行 ### 让应用代码保持转译和运行
We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing We want to start the TypeScript compiler, have it watch for changes, and start our server. We'll do this by typing
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。只要敲 我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。只要敲
@ -50,7 +55,9 @@ code-example(language="bash").
这个命令会在我们构建《英雄指南》的时候让应用得以持续运行。 这个命令会在我们构建《英雄指南》的时候让应用得以持续运行。
## Making a Hero Detail Component ## Making a Hero Detail Component
## 制作英雄详情组件 ## 制作英雄详情组件
Our heroes list and our hero details are in the same component in the same file. Our heroes list and our hero details are in the same component in the same file.
They're small now but each could grow. They're small now but each could grow.
We are sure to receive new requirements for one and not the other. We are sure to receive new requirements for one and not the other.
@ -77,16 +84,21 @@ code-example(language="bash").
我们来把英雄详情拆分成一个独立的组件。 我们来把英雄详情拆分成一个独立的组件。
### Separating the Hero Detail Component ### Separating the Hero Detail Component
### 拆分英雄详情组件 ### 拆分英雄详情组件
Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows. Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows.
在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下: 在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下:
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'app/hero-detail.component.ts (initial version)')(format=".") +makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'app/hero-detail.component.ts (initial version)')(format=".")
.l-sub-section .l-sub-section
:marked :marked
### Naming conventions ### Naming conventions
### 命名约定 ### 命名约定
We like to identify at a glance which classes are components and which files contain components. We like to identify at a glance which classes are components and which files contain components.
我们希望一眼就能看出哪个类是组件,以及哪个文件包含组件。 我们希望一眼就能看出哪个类是组件,以及哪个文件包含组件。
@ -128,9 +140,12 @@ code-example(language="bash").
When we finish here, we'll import it into `AppComponent` and create a corresponding `<my-hero-detail>` element. When we finish here, we'll import it into `AppComponent` and create a corresponding `<my-hero-detail>` element.
做完这些,我们把它导入`AppComponent`组件,并创建相应的`<my-hero-detail>`元素。 做完这些,我们把它导入`AppComponent`组件,并创建相应的`<my-hero-detail>`元素。
:marked :marked
#### Hero Detail Template #### Hero Detail Template
#### 英雄详情模板 #### 英雄详情模板
At the moment, the *Heroes* and *Hero Detail* views are combined in one template in `AppComponent`. At the moment, the *Heroes* and *Hero Detail* views are combined in one template in `AppComponent`.
Lets **cut** the *Hero Detail* content from `AppComponent` and **paste** it into the new template property of `HeroDetailComponent`. Lets **cut** the *Hero Detail* content from `AppComponent` and **paste** it into the new template property of `HeroDetailComponent`.
@ -155,11 +170,15 @@ code-example(language="bash").
现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中了。 现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中了。
#### Add the *hero* property #### Add the *hero* property
#### 添加 *hero* 属性 #### 添加 *hero* 属性
Lets add that `hero` property we were talking about to the component class. Lets add that `hero` property we were talking about to the component class.
我们这就添加刚刚所说的`hero`属性到组件类中。 我们这就添加刚刚所说的`hero`属性到组件类中。
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero') +makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero')
:marked :marked
Uh oh. We declared the `hero` property as type `Hero` but our `Hero` class is over in the `app.component.ts` file. Uh oh. We declared the `hero` property as type `Hero` but our `Hero` class is over in the `app.component.ts` file.
We have two components, each in their own file, that need to reference the `Hero` class. We have two components, each in their own file, that need to reference the `Hero` class.
@ -184,6 +203,7 @@ code-example(language="bash").
:marked :marked
#### The *hero* property is an ***input*** #### The *hero* property is an ***input***
#### *hero*是一个***输入***属性 #### *hero*是一个***输入***属性
The `HeroDetailComponent` must be told what hero to display. Who will tell it? The parent `AppComponent`! The `HeroDetailComponent` must be told what hero to display. Who will tell it? The parent `AppComponent`!
@ -201,8 +221,10 @@ code-example(language="bash").
我们马上升级`AppComponent`的模板,以便把该组件的`selectedHero`属性绑定到`HeroDetailComponent`组件的`hero`属性上。 我们马上升级`AppComponent`的模板,以便把该组件的`selectedHero`属性绑定到`HeroDetailComponent`组件的`hero`属性上。
绑定看起来*可能*是这样的: 绑定看起来*可能*是这样的:
code-example(format="."). code-example(format=".").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail> &lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked :marked
Notice that the `hero` property is the ***target*** of a property binding &mdash; it's in square brackets to the left of the (=). Notice that the `hero` property is the ***target*** of a property binding &mdash; it's in square brackets to the left of the (=).
@ -212,6 +234,7 @@ code-example(format=".").
If we don't, Angular rejects the binding and throws an error. If we don't, Angular rejects the binding and throws an error.
Angular希望我们把***目标属性***定义成组件的***输入属性***否则Angular会拒绝绑定并且抛出一个错误。 Angular希望我们把***目标属性***定义成组件的***输入属性***否则Angular会拒绝绑定并且抛出一个错误。
.l-sub-section .l-sub-section
:marked :marked
We explain input properties in more detail [here](../guide/attribute-directives.html#why-input) We explain input properties in more detail [here](../guide/attribute-directives.html#why-input)
@ -219,12 +242,14 @@ code-example(format=".").
*source* properties do not. *source* properties do not.
我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么*目标属性*需要“显式定义”这样的特殊待遇,而*来源属性*却不需要。 我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么*目标属性*需要“显式定义”这样的特殊待遇,而*来源属性*却不需要。
:marked :marked
There are a couple of ways we can declare that `hero` is an *input*. There are a couple of ways we can declare that `hero` is an *input*.
We'll do it the way we *prefer*, by annotating the `hero` property with the `@Input` decorator that we imported earlier. We'll do it the way we *prefer*, by annotating the `hero` property with the `@Input` decorator that we imported earlier.
我们有几种方式把`hero`声明成*输入属性*。 我们有几种方式把`hero`声明成*输入属性*。
这里我们采用*首选*的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。 这里我们采用*首选*的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-input')(format='.') +makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-input')(format='.')
.l-sub-section .l-sub-section
@ -233,10 +258,13 @@ code-example(format=".").
[Attribute Directives](../guide/attribute-directives.html#input) chapter. [Attribute Directives](../guide/attribute-directives.html#input) chapter.
要了解`@Input()`装饰器的更多知识,参见[属性型指令](../guide/attribute-directives.html#input)一章。 要了解`@Input()`装饰器的更多知识,参见[属性型指令](../guide/attribute-directives.html#input)一章。
.l-main-section .l-main-section
:marked :marked
## Refresh the AppComponent ## Refresh the AppComponent
## 刷新AppComponent ## 刷新AppComponent
We return to the `AppComponent` and teach it to use the `HeroDetailComponent`. We return to the `AppComponent` and teach it to use the `HeroDetailComponent`.
回到`AppComponent`组件,我们要教它使用`HeroDetailComponent`组件。 回到`AppComponent`组件,我们要教它使用`HeroDetailComponent`组件。
@ -244,6 +272,7 @@ code-example(format=".").
We begin by importing the `HeroDetailComponent` so we can refer to it. We begin by importing the `HeroDetailComponent` so we can refer to it.
我们先导入`HeroDetailComponent`组件,好让我们可以引用它。 我们先导入`HeroDetailComponent`组件,好让我们可以引用它。
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-import') +makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-import')
:marked :marked
@ -251,18 +280,22 @@ code-example(format=".").
and add an element tag that represents the `HeroDetailComponent`. and add an element tag that represents the `HeroDetailComponent`.
找到我们刚刚从模板中移除*英雄详情*的地方,放上用来表示`HeroDetailComponent`组件的HTML标签。 找到我们刚刚从模板中移除*英雄详情*的地方,放上用来表示`HeroDetailComponent`组件的HTML标签。
code-example(format="."). code-example(format=".").
&lt;my-hero-detail>&lt;/my-hero-detail> &lt;my-hero-detail>&lt;/my-hero-detail>
.l-sub-section .l-sub-section
:marked :marked
*my-hero-detail* is the name we set as the `selector` in the `HeroDetailComponent` metadata. *my-hero-detail* is the name we set as the `selector` in the `HeroDetailComponent` metadata.
*my-hero-detail*是我们在`HeroDetailComponent`元数据中的`selector`属性所指定的名字。 *my-hero-detail*是我们在`HeroDetailComponent`元数据中的`selector`属性所指定的名字。
:marked :marked
The two components won't coordinate until we bind the `selectedHero` property of the `AppComponent` The two components won't coordinate until we bind the `selectedHero` property of the `AppComponent`
to the `HeroDetailComponent` element's `hero` property like this: to the `HeroDetailComponent` element's `hero` property like this:
这两个组件目前还不能协同工作,直到我们把`AppComponent`组件的`selectedHero`属性和`HeroDetailComponent`组件的`hero`属性绑定在一起,就像这样: 这两个组件目前还不能协同工作,直到我们把`AppComponent`组件的`selectedHero`属性和`HeroDetailComponent`组件的`hero`属性绑定在一起,就像这样:
code-example(format="."). code-example(format=".").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail> &lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked :marked
@ -304,11 +337,14 @@ code-example(format=".").
我们要把它列在元数据的`directives`数组中这样Angular才会知道它。 我们要把它列在元数据的`directives`数组中这样Angular才会知道它。
让我们把这个数组属性加在`@Component`配置对象的底部,紧跟在`template`和`styles`属性之后。 让我们把这个数组属性加在`@Component`配置对象的底部,紧跟在`template`和`styles`属性之后。
+makeExample('toh-3/ts/app/app.component.ts', 'directives', 'app/app.component.ts (Directives)') +makeExample('toh-3/ts/app/app.component.ts', 'directives', 'app/app.component.ts (Directives)')
:marked :marked
### It works! ### It works!
### 搞定! ### 搞定!
When we view our app in the browser we see the list of heroes. When we view our app in the browser we see the list of heroes.
When we select a hero we can see the selected heros details. When we select a hero we can see the selected heros details.
@ -325,7 +361,9 @@ code-example(format=".").
我们创建了第一个可复用组件! 我们创建了第一个可复用组件!
### Reviewing the App Structure ### Reviewing the App Structure
### 回顾应用结构 ### 回顾应用结构
Lets verify that we have the following structure after all of our good refactoring in this chapter: Lets verify that we have the following structure after all of our good refactoring in this chapter:
来验证下吧,在本章中,经过这些漂亮的重构,我们应该得到了下列结构: 来验证下吧,在本章中,经过这些漂亮的重构,我们应该得到了下列结构:
@ -345,6 +383,7 @@ code-example(format=".").
.file package.json .file package.json
.file tsconfig.json .file tsconfig.json
.file typings.json .file typings.json
:marked :marked
Here are the code files we discussed in this chapter. Here are the code files we discussed in this chapter.
@ -363,18 +402,27 @@ code-example(format=".").
.l-main-section .l-main-section
:marked :marked
## The Road Weve Travelled ## The Road Weve Travelled
## 走过的路 ## 走过的路
Lets take stock of what weve built. Lets take stock of what weve built.
来盘点一下我们已经构建完的部分。 来盘点一下我们已经构建完的部分。
* We created a reusable component * We created a reusable component
* 我们创建了一个可复用组件 * 我们创建了一个可复用组件
* We learned how to make a component accept input * We learned how to make a component accept input
* 我们学会了如何让一个组件接收输入 * 我们学会了如何让一个组件接收输入
* We learned to bind a parent component to a child component. * We learned to bind a parent component to a child component.
* 我们学会了把父组件绑定到子组件。 * 我们学会了把父组件绑定到子组件。
* We learned to declare the application directives we need in a `directives` array. * We learned to declare the application directives we need in a `directives` array.
* 我们学会了在`directives`中定义应用所需的指令。 * 我们学会了在`directives`中定义应用所需的指令。
p Run the #[+liveExampleLink2('', 'toh-3')] for this part. p Run the #[+liveExampleLink2('', 'toh-3')] for this part.
@ -384,7 +432,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
.l-main-section .l-main-section
:marked :marked
## The Road Ahead ## The Road Ahead
## 前方的路 ## 前方的路
Our Tour of Heroes has become more reusable with shared components. Our Tour of Heroes has become more reusable with shared components.
通过抽取共享组件,我们的《英雄指南》变得更有复用性了。 通过抽取共享组件,我们的《英雄指南》变得更有复用性了。

View File

@ -2,7 +2,9 @@ include ../_util-fns
:marked :marked
# Services # Services
# 服务 # 服务
The Tour of Heroes is evolving and we anticipate adding more components in the near future. The Tour of Heroes is evolving and we anticipate adding more components in the near future.
《英雄指南》继续前行。接下来,我们准备添加更多的组件。 《英雄指南》继续前行。接下来,我们准备添加更多的组件。
@ -33,7 +35,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
.l-main-section .l-main-section
:marked :marked
## Where We Left Off ## Where We Left Off
## 我们在哪儿 ## 我们在哪儿
Before we continue with our Tour of Heroes, lets verify we have the following structure. Before we continue with our Tour of Heroes, lets verify we have the following structure.
If not, well need to go back and follow the previous chapters. If not, well need to go back and follow the previous chapters.
@ -74,7 +78,9 @@ code-example(language="bash").
当我们继续构建《英雄指南》时,应用会自动运行和更新。 当我们继续构建《英雄指南》时,应用会自动运行和更新。
## Creating a Hero Service ## Creating a Hero Service
## 创建英雄服务 ## 创建英雄服务
Our stakeholders have shared their larger vision for our app. Our stakeholders have shared their larger vision for our app.
They tell us they want to show the heroes in various ways on different pages. They tell us they want to show the heroes in various ways on different pages.
We already can select a hero from a list. We already can select a hero from a list.
@ -101,10 +107,13 @@ code-example(language="bash").
我们可以把提供英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并且把这个服务在所有需要英雄数据的组件之间共享。 我们可以把提供英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并且把这个服务在所有需要英雄数据的组件之间共享。
### Create the HeroService ### Create the HeroService
### 创建HeroService ### 创建HeroService
Create a file in the `app` folder called `hero.service.ts`. Create a file in the `app` folder called `hero.service.ts`.
在`app`目录下创建一个名叫`hero.service.ts`的文件。 在`app`目录下创建一个名叫`hero.service.ts`的文件。
.l-sub-section .l-sub-section
:marked :marked
We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`. We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`.
@ -114,6 +123,7 @@ code-example(language="bash").
我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。 我们遵循的文件命名约定是:服务名称的小写形式(基本名),加上`.service`后缀。
如果服务名称包含多个单词,我们就把基本名部分写成中线形式(dash-case也被称作烤串形式kebab-case)。 如果服务名称包含多个单词,我们就把基本名部分写成中线形式(dash-case也被称作烤串形式kebab-case)。
比如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。 比如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。
:marked :marked
We name the class `HeroService` and export it for others to import. We name the class `HeroService` and export it for others to import.
@ -123,15 +133,19 @@ code-example(language="bash").
:marked :marked
### Injectable Services ### Injectable Services
### 可注入的服务 ### 可注入的服务
Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator. Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator.
注意我们引入了Angular的`Injectable`函数,并通过`@Injectable()`装饰器使用这个函数。 注意我们引入了Angular的`Injectable`函数,并通过`@Injectable()`装饰器使用这个函数。
.callout.is-helpful .callout.is-helpful
:marked :marked
**Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose. **Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose.
**不要忘了写圆括号!**如果忘了写,就会导致一个很难诊断的错误。 **不要忘了写圆括号!**如果忘了写,就会导致一个很难诊断的错误。
:marked :marked
TypeScript sees the `@Injectable()` decorator and emits metadata about our service, TypeScript sees the `@Injectable()` decorator and emits metadata about our service,
metadata that Angular may need to inject other dependencies into this service. metadata that Angular may need to inject other dependencies into this service.
@ -146,12 +160,15 @@ code-example(language="bash").
:marked :marked
### Getting Heroes ### Getting Heroes
### 获取英雄 ### 获取英雄
Add a `getHeroes` method stub. Add a `getHeroes` method stub.
添加一个名叫`getHeros`的桩方法。 添加一个名叫`getHeros`的桩方法。
+makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'app/hero.service.ts (getHeroes stub)')(format=".") +makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'app/hero.service.ts (getHeroes stub)')(format=".")
:marked :marked
We're holding back on the implementation for a moment to make an important point. We're holding back on the implementation for a moment to make an important point.
@ -174,7 +191,9 @@ code-example(language="bash").
这下子,我们可以随时改变数据访问的实现方式了。 这下子,我们可以随时改变数据访问的实现方式了。
### Mock Heroes ### Mock Heroes
### Mock英雄数据 ### Mock英雄数据
We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either. We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either.
We'll move the mock data to its own file. We'll move the mock data to its own file.
@ -187,6 +206,7 @@ code-example(language="bash").
我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。 我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts') +makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts')
:marked :marked
We export the `HEROES` constant so we can import it elsewhere &mdash; such as our `HeroService`. We export the `HEROES` constant so we can import it elsewhere &mdash; such as our `HeroService`.
@ -198,9 +218,12 @@ code-example(language="bash").
同时,回到刚剪切出`HEROES`数组的`app.component.ts`文件,我们留下了一个尚未初始化的`heroes`属性: 同时,回到刚剪切出`HEROES`数组的`app.component.ts`文件,我们留下了一个尚未初始化的`heroes`属性:
+makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app/app.component.ts (heroes property)')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app/app.component.ts (heroes property)')(format=".")
:marked :marked
### Return Mocked Heroes ### Return Mocked Heroes
### 返回模拟的英雄数据 ### 返回模拟的英雄数据
Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method. Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method.
Our `HeroService` looks like this: Our `HeroService` looks like this:
@ -208,9 +231,12 @@ code-example(language="bash").
我们的`HeroService`服务现在看起来是这样: 我们的`HeroService`服务现在看起来是这样:
+makeExample('toh-4/ts/app/hero.service.1.ts', null, 'app/hero.service.ts')(format=".") +makeExample('toh-4/ts/app/hero.service.1.ts', null, 'app/hero.service.ts')(format=".")
:marked :marked
### Use the Hero Service ### Use the Hero Service
### 使用HeroService服务 ### 使用HeroService服务
We're ready to use the `HeroService` in other components starting with our `AppComponent`. We're ready to use the `HeroService` in other components starting with our `AppComponent`.
我们已经在包括`AppComponent`在内的多个组件中使用了`HeroService`服务。 我们已经在包括`AppComponent`在内的多个组件中使用了`HeroService`服务。
@ -220,6 +246,7 @@ code-example(language="bash").
通常,我们会从导入要用的东西开始,比如`HeroService`。 通常,我们会从导入要用的东西开始,比如`HeroService`。
+makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import') +makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import')
:marked :marked
Importing the service allows us to *reference* it in our code. Importing the service allows us to *reference* it in our code.
How should the `AppComponent` acquire a runtime concrete `HeroService` instance? How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
@ -236,6 +263,7 @@ code-example(language="bash").
固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样: 固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样:
+makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".")
:marked :marked
That's a bad idea for several reasons including That's a bad idea for several reasons including
@ -269,6 +297,7 @@ code-example(language="bash").
比如,能离线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。 比如,能离线操作吗?能在测试时使用不同的模拟版本吗?这可不容易。
* What if ... what if ... Hey, we've got work to do!* * What if ... what if ... Hey, we've got work to do!*
* 如果……如果……嘿!这下我们可有得忙了! * 如果……如果……嘿!这下我们可有得忙了!
We get it. Really we do. We get it. Really we do.
@ -277,6 +306,7 @@ code-example(language="bash").
有办法了,真的!这个办法真是简单得不可思议,它能解决这些问题,你就再也没有犯错误的借口了。 有办法了,真的!这个办法真是简单得不可思议,它能解决这些问题,你就再也没有犯错误的借口了。
### Inject the *HeroService* ### Inject the *HeroService*
### 注入 *HeroService* ### 注入 *HeroService*
Two lines replace the one line that created with *new*: Two lines replace the one line that created with *new*:
@ -301,6 +331,7 @@ code-example(language="bash").
defines a private `heroService` property and identifies it as a `HeroService` injection site. defines a private `heroService` property and identifies it as a `HeroService` injection site.
构造函数自己什么也不用做,它在参数中定义了一个私有的`heroService`属性,并把它标记为注入`HeroService`的靶点。 构造函数自己什么也不用做,它在参数中定义了一个私有的`heroService`属性,并把它标记为注入`HeroService`的靶点。
:marked :marked
Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`. Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`.
@ -322,6 +353,7 @@ code-example(language="bash").
code-example(format="nocode"). code-example(format="nocode").
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService) EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
(异常没有HeroService的供应商(AppComponent -> HeroService)) (异常没有HeroService的供应商(AppComponent -> HeroService))
:marked :marked
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**. We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
Do that by adding the following `providers` array property to the bottom of the component metadata Do that by adding the following `providers` array property to the bottom of the component metadata
@ -331,16 +363,20 @@ code-example(format="nocode").
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下: 要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下:
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers') +makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers')
:marked :marked
The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`. The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
The `AppComponent` can use that service to get heroes and so can every child component of its component tree. The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
`providers`数组告诉Angular当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。 `providers`数组告诉Angular当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。
`AppComponent`会使用那个服务来获取影响列表,在它组件树中的每一个子组件也同样如此。 `AppComponent`会使用那个服务来获取影响列表,在它组件树中的每一个子组件也同样如此。
a#child-component a#child-component
:marked :marked
### *getHeroes* in the *AppComponent* ### *getHeroes* in the *AppComponent*
### *AppComponent* 中的 *getHeroes* ### *AppComponent* 中的 *getHeroes*
We've got the service in a `heroService` private variable. Let's use it. We've got the service in a `heroService` private variable. Let's use it.
我们已经获得了此服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。 我们已经获得了此服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。
@ -348,7 +384,9 @@ a#child-component
We pause to think. We can call the service and get the data in one line. We pause to think. We can call the service and get the data in one line.
停下来想一想。我们可以在同一行内调用此服务并获得数据。 停下来想一想。我们可以在同一行内调用此服务并获得数据。
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
:marked :marked
We don't really need a dedicated method to wrap one line. We write it anyway: We don't really need a dedicated method to wrap one line. We write it anyway:
@ -359,7 +397,9 @@ a#child-component
<a id="oninit"></a> <a id="oninit"></a>
:marked :marked
### The *ngOnInit* Lifecycle Hook ### The *ngOnInit* Lifecycle Hook
### *ngOnInit* 生命周期钩子 ### *ngOnInit* 生命周期钩子
`AppComponent` should fetch and display heroes without a fuss. `AppComponent` should fetch and display heroes without a fuss.
Where do we call the `getHeroes` method? In a constructor? We do *not*! Where do we call the `getHeroes` method? In a constructor? We do *not*!
@ -392,17 +432,20 @@ a#child-component
Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time. Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time.
每个接口都有唯一的一个方法。只要组件实现了这个方法Angular就会在合适的时机调用它。 每个接口都有唯一的一个方法。只要组件实现了这个方法Angular就会在合适的时机调用它。
.l-sub-section .l-sub-section
:marked :marked
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter. Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
要了解关于生命周期钩子的更多知识,请参见 [生命周期钩子](../guide/lifecycle-hooks.html) 一章。 要了解关于生命周期钩子的更多知识,请参见 [生命周期钩子](../guide/lifecycle-hooks.html) 一章。
:marked :marked
Here's the essential outline for the `OnInit` interface: Here's the essential outline for the `OnInit` interface:
这是`OnInit`接口的基本轮廓: 这是`OnInit`接口的基本轮廓:
+makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app/app.component.ts (ngOnInit stub)')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app/app.component.ts (ngOnInit stub)')(format=".")
:marked :marked
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
at the right time. In our case, we initialize by calling `getHeroes`. at the right time. In our case, we initialize by calling `getHeroes`.
@ -410,6 +453,7 @@ a#child-component
我们写下带有初始化逻辑的`ngOnInit`方法然后留给Angular供其在正确的时机调用。在这个例子中我们通过调用`getHeroes`来完成初始化。 我们写下带有初始化逻辑的`ngOnInit`方法然后留给Angular供其在正确的时机调用。在这个例子中我们通过调用`getHeroes`来完成初始化。
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init') +makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init')
:marked :marked
Our application should be running as expected, showing a list of heroes and a hero detail view Our application should be running as expected, showing a list of heroes and a hero detail view
when we click on a hero name. when we click on a hero name.
@ -432,6 +476,7 @@ a#child-component
我们的`HeroService`立即返回一个模拟的英雄列表,它的`getHeroes`函数签名是同步的。 我们的`HeroService`立即返回一个模拟的英雄列表,它的`getHeroes`函数签名是同步的。
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
:marked :marked
Ask for heroes and they are there in the returned result. Ask for heroes and they are there in the returned result.
@ -465,17 +510,20 @@ a#child-component
**承诺** 就是 …… 好吧,它就是一个承诺 —— 在有了结果时,它承诺会回调我们。 **承诺** 就是 …… 好吧,它就是一个承诺 —— 在有了结果时,它承诺会回调我们。
我们请求一个异步服务去做点什么,然后给它一个回调函数。 我们请求一个异步服务去做点什么,然后给它一个回调函数。
它会去做(无论用哪种方式),一旦完成,它就会调用我们的回调函数,并通过参数把工作成果或者错误信息传给我们。 它会去做(无论用哪种方式),一旦完成,它就会调用我们的回调函数,并通过参数把工作成果或者错误信息传给我们。
.l-sub-section .l-sub-section
:marked :marked
We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web. We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web.
这里只是粗浅的说说,要了解更多,请参见[这里](http://exploringjs.com/es6/ch_promises.html)或在Web上搜索其它学习资源。 这里只是粗浅的说说,要了解更多,请参见[这里](http://exploringjs.com/es6/ch_promises.html)或在Web上搜索其它学习资源。
:marked :marked
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method: Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
把`HeroService`的`getHeroes`方法改写为返回承诺的形式: 把`HeroService`的`getHeroes`方法改写为返回承诺的形式:
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'app/hero.service.ts (excerpt)')(format=".") +makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'app/hero.service.ts (excerpt)')(format=".")
:marked :marked
We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server, We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server,
by returning an **immediately resolved !{_Promise}** with our mock heroes as the result. by returning an **immediately resolved !{_Promise}** with our mock heroes as the result.
@ -491,6 +539,7 @@ a#child-component
回到`AppComponent`和它的`getHeroes`方法,我们看到它看起来还是这样的: 回到`AppComponent`和它的`getHeroes`方法,我们看到它看起来还是这样的:
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app/app.component.ts (getHeroes - old)')(format=".") +makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app/app.component.ts (getHeroes - old)')(format=".")
:marked :marked
As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes. As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes.
@ -507,6 +556,7 @@ a#child-component
我们把回调函数作为参数传给承诺对象的**then**函数: 我们把回调函数作为参数传给承诺对象的**then**函数:
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".") +makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".")
.l-sub-section .l-sub-section
:marked :marked
The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
@ -514,6 +564,7 @@ a#child-component
回调中所用的[ES2015箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) 回调中所用的[ES2015箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
能比等价的函数表达式更加快速、优雅的处理*this*指针。 能比等价的函数表达式更加快速、优雅的处理*this*指针。
:marked :marked
Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it! Our callback sets the component's `heroes` property to the array of heroes returned by the service. That's all there is to it!
@ -523,14 +574,18 @@ a#child-component
responding to a name selection with a detail view. responding to a name selection with a detail view.
我们的程序仍在运行,仍在显示英雄列表,在选择英雄时,仍然会把他/她显示在详情页面中。 我们的程序仍在运行,仍在显示英雄列表,在选择英雄时,仍然会把他/她显示在详情页面中。
.l-sub-section .l-sub-section
:marked :marked
Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection. Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection.
查看附件中的“[慢一点儿](#slow)”一节,来了解在较差的网络连接中这个应用会是什么样的。 查看附件中的“[慢一点儿](#slow)”一节,来了解在较差的网络连接中这个应用会是什么样的。
:marked :marked
### Review the App Structure ### Review the App Structure
### 回顾本应用的结构 ### 回顾本应用的结构
Lets verify that we have the following structure after all of our good refactoring in this chapter: Lets verify that we have the following structure after all of our good refactoring in this chapter:
再检查下,经历了本章的所有重构之后,我们应该有了下列文件结构: 再检查下,经历了本章的所有重构之后,我们应该有了下列文件结构:
@ -570,7 +625,9 @@ a#child-component
`) `)
:marked :marked
## The Road Weve Travelled ## The Road Weve Travelled
## 走过的路 ## 走过的路
Lets take stock of what weve built. Lets take stock of what weve built.
来盘点一下我们已经构建完的部分。 来盘点一下我们已经构建完的部分。
@ -601,7 +658,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
:marked :marked
### The Road Ahead ### The Road Ahead
### 前方的路 ### 前方的路
Our Tour of Heroes has become more reusable using shared components and services. Our Tour of Heroes has become more reusable using shared components and services.
We want to create a dashboard, add menu links that route between the views, and format data in a template. We want to create a dashboard, add menu links that route between the views, and format data in a template.
As our app evolves, well learn how to design it to make it easier to grow and maintain. As our app evolves, well learn how to design it to make it easier to grow and maintain.
@ -618,6 +677,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
<a id="slow"></a> <a id="slow"></a>
:marked :marked
### Appendix: Take it slow ### Appendix: Take it slow
### 附件:慢一点儿 ### 附件:慢一点儿
We can simulate a slow connection. We can simulate a slow connection.
@ -629,6 +689,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
导入`Hero`类,并且在`HeroService`中添加如下的`getHeroesSlowly`方法: 导入`Hero`类,并且在`HeroService`中添加如下的`getHeroesSlowly`方法:
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'app/hero.service.ts (getHeroesSlowly)')(format=".") +makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'app/hero.service.ts (getHeroesSlowly)')(format=".")
:marked :marked
Like `getHeroes`, it also returns a !{_Promise}. Like `getHeroes`, it also returns a !{_Promise}.
But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes. But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.