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": {
"title": "Http",
"intro": "We convert our service and components to use Http",
"intro": "把我们的服务和组件改用Http实现",
"nextable": true
}
}

View File

@ -3,6 +3,7 @@ include ../_util-fns
// #docregion intro
:marked
# Tour of Heroes: the vision
# 《英雄指南》目标概览
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
:marked
## The End Game
## 游戏的终点
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
:marked
## Up Next
## 接下来
Well build this Tour of Heroes together, step by step.

View File

@ -2,6 +2,7 @@ include ../_util-fns
:marked
# Once Upon a Time
# 很久很久以前
Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
@ -41,7 +42,9 @@ include ../_quickstart_repo
.file typings.json
:marked
## 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
我们要启动TypeScript编译器它会监视文件变更并且启动开发服务器。我们只要敲
@ -58,7 +61,9 @@ code-example(language="bash").
.l-main-section
:marked
## Show our Hero
## 显示我们的英雄
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).
要了解插值表达式的更多知识,参阅[“显示数据”一章](../guide/displaying-data.html)。
:marked
### Hero object
### Hero对象
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
### 添加更多的HTML
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`.
@ -146,6 +155,7 @@ code-example(language="bash").
啊哦!我们的模板字符串已经太长了。我们最好小心点,免得在模板中出现拼写错误。
### Multi-line template strings
### 多行模板字符串
We could make a more readable template with string concatenation
@ -166,7 +176,9 @@ code-example(language="bash").
.callout.is-important
header A back-tick is not a single quote
header 反引号不是单引号
:marked
**Be careful!** A back-tick (`) looks a lot like a single quote (').
It's actually a completely different character.
@ -183,6 +195,7 @@ code-example(language="bash").
.l-main-section
:marked
## Editing Our Hero
## 编辑我们的英雄
We want to be able to edit the hero name in a textbox.
@ -194,6 +207,7 @@ code-example(language="bash").
把英雄的名字从单纯的`<label>`重构成`<label>`和`<input>`元素的组合,就像下面这样:
+makeExample('toh-1/ts-snippets/app.component.snippets.pt1.ts', 'editing-Hero', 'app.component.ts (input元素)')
:marked
We see in the browser that the heros name does appear in the `<input>` textbox.
But something doesnt feel right.
@ -205,6 +219,7 @@ code-example(language="bash").
当修改名字时,我们的改动并没有反映到`<h2>`中。使用单向数据绑定,我们没法实现所期望的这种行为。
### Two-Way Binding
### 双向绑定
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)和
[模板语法](../guide/template-syntax.html#ngModel)两章
:marked
Replace the `<input>` with the following HTML
@ -243,20 +259,29 @@ code-example(language="html").
.l-main-section
:marked
## The Road Weve Travelled
## 我们已经走过的路
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)
to display the application title and properties of a `Hero` object.
* 我们的《英雄指南》使用双大括号(插值表达式 —— 单向数据绑定的一种形式)来显示应用的标题和`Hero`对象的属性。
* We wrote a multi-line template using ES2015s template strings to make our template readable.
* 我们使用ES2105的模板字符串写了一个多行模板来让我们的模板更有可读性。
* 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.
* 为了同时显示和修改英雄的名字,我们还使用了内建的`ngModel`指令,往`<input>`元素上添加了双向数据绑定。
* The `ngModel` directive also propagates changes to every other binding of the `hero.name`.
* 通过`ngModel`指令,这些修改还影响到了每一个对`hero.name`的其它绑定。
p Run the #[+liveExampleLink2('', 'toh-1')] for this part.
@ -273,7 +298,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-1')]。
.l-main-section
:marked
## The Road Ahead
## 前方的路
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.
Well learn more about how to retrieve lists, bind them to the

View File

@ -2,7 +2,9 @@ include ../_util-fns
:marked
# It Takes Many Heroes
# 需要多个英雄
Our story needs more 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.
@ -24,7 +26,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
.l-main-section
:marked
## Where We Left Off
## 我们在哪儿
Before we continue with Part 2 of the Tour of Heroes,
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.
@ -48,7 +52,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
.file typings.json
:marked
### 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
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。我们只要敲
@ -64,9 +70,13 @@ code-example(language="bash").
.l-main-section
:marked
## Displaying Our Heroes
## 显示我们的英雄
### Creating heroes
### 创建英雄
Lets create an array of ten heroes at the bottom of `app.component.ts`.
我们先在`app.component.ts`的底部创建一个由十位英雄组成的数组。
@ -83,7 +93,9 @@ code-example(language="bash").
我们当然希望从一个Web服务中获取这个英雄列表但别急我们得把步子迈得小一点儿 —— 先用一组Mock(模拟)出来的英雄。
### Exposing heroes
### 导出英雄们
Lets create a public property in `AppComponent` that exposes the heroes for binding.
我们在`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.
我们并不需要明确定义`heroes`属性的数据类型TypeScript能从`HEROES`数组中推断出来。
.l-sub-section
:marked
We could have defined the heroes list here in this component class.
@ -104,9 +117,12 @@ code-example(language="bash").
我们已经把英雄列表定义在了这个组件类中。
但显然,我们最终还是得从一个数据服务中获取这些英雄。
正因如此,我们从一开始就要有意识的把英雄数据隔离到一个类中来实现。
:marked
### Displaying heroes in a template
### 在一个模板中显示英雄
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.
@ -121,6 +137,7 @@ code-example(language="bash").
现在,我们有了一个模板。接下来,就用英雄们的数据来填充它。
### Listing heroes with ngFor
### 通过ngFor来显示英雄列表
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
### 给我们的英雄们“美容”
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.
@ -224,7 +243,9 @@ code-example(language="bash").
.l-main-section
:marked
## Selecting a Hero
## 选择英雄
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.
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事件上。
### Click event
### click事件
We modify the `<li>` by inserting an Angular event binding to its click event.
我们往`<li>`元素上插入一句Angular事件绑定代码绑定到它的click事件。
@ -253,8 +276,10 @@ code-example(language="bash").
Focus on the event binding
事件绑定详解
code-example(format="." language="bash").
(click)="onSelect(hero)"
:marked
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()`,
@ -277,7 +302,9 @@ code-example(language="bash").
:marked
### Add the click handler
### 添加click事件处理器
Our event binding refers to an `onSelect` method that doesnt exist yet.
Well add that method to our component now.
@ -293,6 +320,7 @@ code-example(language="bash").
我们的组件还没有用来表示“当前选中的英雄”的变量,我们就从这一步儿开始。
### Expose the selected hero
### 导出“当前选中的英雄”
We no longer need the static `hero` property of the `AppComponent`.
@ -324,8 +352,10 @@ code-example(language="bash").
我们这就修改模板,让它绑定到新的`selectedHero`属性上去。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'selectedHero-details', 'app.component.ts (template excerpt)')
:marked
### Hide the empty detail with ngIf
### 利用ngIf隐藏空的详情
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`。
因此,我们会看到浏览器控制台中出现下列错误:
code-example(language="html").
EXCEPTION: TypeError: Cannot read property 'name' of undefined in [null]
@ -402,6 +433,7 @@ code-example(language="bash").
正如我们所预期的那样。
### Styling the selection
### 给所选英雄添加样式
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
img(src='/resources/images/devguide/toh/heroes-list-selected.png' alt="选中的英雄")
: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`.
@ -425,7 +458,9 @@ code-example(language="bash").
关键是CSS类的名字`selected`。当两位英雄一致时,它为`true`,否则为`false`。
也就是说:“*当两位英雄匹配时,应用上`selected`类,否则不应用*”。
+makeExample('toh-2/ts-snippets/app.component.snippets.pt2.ts', 'class-selected-1', 'app.component.ts (setting the CSS class)')(format=".")
:marked
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
@ -450,6 +485,7 @@ code-example(language="bash").
浏览器重新加载了你的应用。
我们选中英雄Magneta于是他通过背景色的变化被清晰的标记了出来。
figure.image-display
img(src='/resources/images/devguide/toh/heroes-list-1.png' alt="英雄列表应用的输出")
@ -467,16 +503,23 @@ code-example(language="bash").
.l-main-section
:marked
## The Road Weve Travelled
## 已走的路
Heres what we achieved in this chapter:
在本章中,我们达成了这些:
* 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 learned how to use the built-in directives `ngIf` and `ngFor` in a components template
* 我们学会了如何在组件模板中使用内建的`ngIf`和`ngFor`指令
p Run the #[+liveExampleLink2('', 'toh-2')] for this part.
@ -485,7 +528,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-2')]。
:marked
### The Road Ahead
### 前方的路
Our Tour of Heroes has grown, but its far from complete.
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

View File

@ -14,7 +14,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
.l-main-section
:marked
## 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.
在继续《英雄指南》之前,先来检查一下,你是否已经有了如下目录结构。如果没有,你得先回上一章,看看错过了哪里。
@ -34,9 +36,12 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
.file systemjs.config.js
.file tsconfig.json
.file typings.json
:marked
### 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
我们要启动TypeScript编译器它会监视文件变更并启动开发服务器。只要敲
@ -50,7 +55,9 @@ code-example(language="bash").
这个命令会在我们构建《英雄指南》的时候让应用得以持续运行。
## Making a Hero Detail Component
## 制作英雄详情组件
Our heroes list and our hero details are in the same component in the same file.
They're small now but each could grow.
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
### 拆分英雄详情组件
Add a new file named `hero-detail.component.ts` to the `app` folder and create `HeroDetailComponent` as follows.
在`app`目录下添加一个名叫`hero-detail.component.ts`的文件,并且创建`HeroDetailComponent`。代码如下:
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'v1', 'app/hero-detail.component.ts (initial version)')(format=".")
.l-sub-section
:marked
### Naming conventions
### 命名约定
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.
做完这些,我们把它导入`AppComponent`组件,并创建相应的`<my-hero-detail>`元素。
:marked
#### Hero Detail Template
#### 英雄详情模板
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`.
@ -155,11 +170,15 @@ code-example(language="bash").
现在,我们的英雄详情布局只存在于`HeroDetailComponent`组件中了。
#### Add the *hero* property
#### 添加 *hero* 属性
Lets add that `hero` property we were talking about to the component class.
我们这就添加刚刚所说的`hero`属性到组件类中。
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero')
:marked
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.
@ -184,6 +203,7 @@ code-example(language="bash").
:marked
#### The *hero* property is an ***input***
#### *hero*是一个***输入***属性
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`属性上。
绑定看起来*可能*是这样的:
code-example(format=".").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked
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.
Angular希望我们把***目标属性***定义成组件的***输入属性***否则Angular会拒绝绑定并且抛出一个错误。
.l-sub-section
:marked
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.
我们在[这里](../guide/attribute-directives.html#why-input)详细解释了输入属性,以及为什么*目标属性*需要“显式定义”这样的特殊待遇,而*来源属性*却不需要。
:marked
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.
我们有几种方式把`hero`声明成*输入属性*。
这里我们采用*首选*的方式:使用我们前面导入的`@Input`装饰器,为`hero`属性加上注解。
+makeExample('toh-3/ts/app/hero-detail.component.ts', 'hero-input')(format='.')
.l-sub-section
@ -233,10 +258,13 @@ code-example(format=".").
[Attribute Directives](../guide/attribute-directives.html#input) chapter.
要了解`@Input()`装饰器的更多知识,参见[属性型指令](../guide/attribute-directives.html#input)一章。
.l-main-section
:marked
## Refresh the AppComponent
## 刷新AppComponent
We return to the `AppComponent` and teach it to use the `HeroDetailComponent`.
回到`AppComponent`组件,我们要教它使用`HeroDetailComponent`组件。
@ -244,6 +272,7 @@ code-example(format=".").
We begin by importing the `HeroDetailComponent` so we can refer to it.
我们先导入`HeroDetailComponent`组件,好让我们可以引用它。
+makeExample('toh-3/ts/app/app.component.ts', 'hero-detail-import')
:marked
@ -251,18 +280,22 @@ code-example(format=".").
and add an element tag that represents the `HeroDetailComponent`.
找到我们刚刚从模板中移除*英雄详情*的地方,放上用来表示`HeroDetailComponent`组件的HTML标签。
code-example(format=".").
&lt;my-hero-detail>&lt;/my-hero-detail>
.l-sub-section
:marked
*my-hero-detail* is the name we set as the `selector` in the `HeroDetailComponent` metadata.
*my-hero-detail*是我们在`HeroDetailComponent`元数据中的`selector`属性所指定的名字。
:marked
The two components won't coordinate until we bind the `selectedHero` property of the `AppComponent`
to the `HeroDetailComponent` element's `hero` property like this:
这两个组件目前还不能协同工作,直到我们把`AppComponent`组件的`selectedHero`属性和`HeroDetailComponent`组件的`hero`属性绑定在一起,就像这样:
code-example(format=".").
&lt;my-hero-detail [hero]="selectedHero">&lt;/my-hero-detail>
:marked
@ -304,11 +337,14 @@ code-example(format=".").
我们要把它列在元数据的`directives`数组中这样Angular才会知道它。
让我们把这个数组属性加在`@Component`配置对象的底部,紧跟在`template`和`styles`属性之后。
+makeExample('toh-3/ts/app/app.component.ts', 'directives', 'app/app.component.ts (Directives)')
:marked
### It works!
### 搞定!
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.
@ -325,7 +361,9 @@ code-example(format=".").
我们创建了第一个可复用组件!
### Reviewing the App Structure
### 回顾应用结构
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 tsconfig.json
.file typings.json
:marked
Here are the code files we discussed in this chapter.
@ -363,18 +402,27 @@ code-example(format=".").
.l-main-section
:marked
## The Road Weve Travelled
## 走过的路
Lets take stock of what weve built.
来盘点一下我们已经构建完的部分。
* We created a reusable component
* 我们创建了一个可复用组件
* We learned how to make a component accept input
* 我们学会了如何让一个组件接收输入
* We learned to bind a parent component to a child component.
* 我们学会了把父组件绑定到子组件。
* We learned to declare the application directives we need in a `directives` array.
* 我们学会了在`directives`中定义应用所需的指令。
p Run the #[+liveExampleLink2('', 'toh-3')] for this part.
@ -384,7 +432,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-3')]。
.l-main-section
:marked
## The Road Ahead
## 前方的路
Our Tour of Heroes has become more reusable with shared components.
通过抽取共享组件,我们的《英雄指南》变得更有复用性了。

View File

@ -2,7 +2,9 @@ include ../_util-fns
:marked
# Services
# 服务
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
:marked
## 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.
@ -74,7 +78,9 @@ code-example(language="bash").
当我们继续构建《英雄指南》时,应用会自动运行和更新。
## Creating a Hero Service
## 创建英雄服务
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.
We already can select a hero from a list.
@ -101,10 +107,13 @@ code-example(language="bash").
我们可以把提供英雄数据的任务重构为一个单独的服务,它将提供英雄数据,并且把这个服务在所有需要英雄数据的组件之间共享。
### Create the HeroService
### 创建HeroService
Create a file in the `app` folder called `hero.service.ts`.
在`app`目录下创建一个名叫`hero.service.ts`的文件。
.l-sub-section
:marked
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`后缀。
如果服务名称包含多个单词,我们就把基本名部分写成中线形式(dash-case也被称作烤串形式kebab-case)。
比如,`SpecialSuperHeroService`服务应该被定义在`special-super-hero.service.ts`文件中。
:marked
We name the class `HeroService` and export it for others to import.
@ -123,15 +133,19 @@ code-example(language="bash").
:marked
### Injectable Services
### 可注入的服务
Notice that we imported the Angular `Injectable` function and applied that function as an `@Injectable()` decorator.
注意我们引入了Angular的`Injectable`函数,并通过`@Injectable()`装饰器使用这个函数。
.callout.is-helpful
:marked
**Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose.
**不要忘了写圆括号!**如果忘了写,就会导致一个很难诊断的错误。
:marked
TypeScript sees the `@Injectable()` decorator and emits metadata about our service,
metadata that Angular may need to inject other dependencies into this service.
@ -146,12 +160,15 @@ code-example(language="bash").
:marked
### Getting Heroes
### 获取英雄
Add a `getHeroes` method stub.
添加一个名叫`getHeros`的桩方法。
+makeExample('toh-4/ts/app/hero.service.1.ts', 'getHeroes-stub', 'app/hero.service.ts (getHeroes stub)')(format=".")
:marked
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英雄数据
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.
@ -187,6 +206,7 @@ code-example(language="bash").
我们还要把`import {Hero}...`语句拷贝过来,因为我们的英雄数组用到了`Hero`类。
+makeExample('toh-4/ts/app/mock-heroes.ts', null, 'app/mock-heroes.ts')
:marked
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`属性:
+makeExample('toh-4/ts/app/app.component.1.ts', 'heroes-prop', 'app/app.component.ts (heroes property)')(format=".")
:marked
### Return Mocked Heroes
### 返回模拟的英雄数据
Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method.
Our `HeroService` looks like this:
@ -208,9 +231,12 @@ code-example(language="bash").
我们的`HeroService`服务现在看起来是这样:
+makeExample('toh-4/ts/app/hero.service.1.ts', null, 'app/hero.service.ts')(format=".")
:marked
### Use the Hero Service
### 使用HeroService服务
We're ready to use the `HeroService` in other components starting with our `AppComponent`.
我们已经在包括`AppComponent`在内的多个组件中使用了`HeroService`服务。
@ -220,6 +246,7 @@ code-example(language="bash").
通常,我们会从导入要用的东西开始,比如`HeroService`。
+makeExcerpt('toh-4/ts/app/app.component.ts', 'hero-service-import')
:marked
Importing the service allows us to *reference* it in our code.
How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
@ -236,6 +263,7 @@ code-example(language="bash").
固然,我们可以使用`new`关键字来创建`HeroService`的实例,就像这样:
+makeExample('toh-4/ts/app/app.component.1.ts', 'new-service')(format=".")
:marked
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!*
* 如果……如果……嘿!这下我们可有得忙了!
We get it. Really we do.
@ -277,6 +306,7 @@ code-example(language="bash").
有办法了,真的!这个办法真是简单得不可思议,它能解决这些问题,你就再也没有犯错误的借口了。
### Inject the *HeroService*
### 注入 *HeroService*
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.
构造函数自己什么也不用做,它在参数中定义了一个私有的`heroService`属性,并把它标记为注入`HeroService`的靶点。
:marked
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").
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
(异常没有HeroService的供应商(AppComponent -> HeroService))
:marked
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
@ -331,16 +363,20 @@ code-example(format="nocode").
要做到这一点,我们应该在`@Component`组件的元数据底部添加`providers`数组属性如下:
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'providers')
:marked
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.
`providers`数组告诉Angular当它创建新的`AppComponent`组件时,也要创建一个`HeroService`的新实例。
`AppComponent`会使用那个服务来获取影响列表,在它组件树中的每一个子组件也同样如此。
a#child-component
:marked
### *getHeroes* in the *AppComponent*
### *AppComponent* 中的 *getHeroes*
We've got the service in a `heroService` private variable. Let's use it.
我们已经获得了此服务,并把它存入了私有变量`heroService`中。我们这就开始使用它。
@ -348,7 +384,9 @@ a#child-component
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=".")
:marked
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>
:marked
### The *ngOnInit* Lifecycle Hook
### *ngOnInit* 生命周期钩子
`AppComponent` should fetch and display heroes without a fuss.
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.
每个接口都有唯一的一个方法。只要组件实现了这个方法Angular就会在合适的时机调用它。
.l-sub-section
:marked
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
要了解关于生命周期钩子的更多知识,请参见 [生命周期钩子](../guide/lifecycle-hooks.html) 一章。
:marked
Here's the essential outline for the `OnInit` interface:
这是`OnInit`接口的基本轮廓:
+makeExample('toh-4/ts/app/app.component.1.ts', 'on-init', 'app/app.component.ts (ngOnInit stub)')(format=".")
:marked
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`.
@ -410,6 +453,7 @@ a#child-component
我们写下带有初始化逻辑的`ngOnInit`方法然后留给Angular供其在正确的时机调用。在这个例子中我们通过调用`getHeroes`来完成初始化。
+makeExcerpt('toh-4/ts/app/app.component.1.ts', 'ng-on-init')
:marked
Our application should be running as expected, showing a list of heroes and a hero detail view
when we click on a hero name.
@ -432,6 +476,7 @@ a#child-component
我们的`HeroService`立即返回一个模拟的英雄列表,它的`getHeroes`函数签名是同步的。
+makeExample('toh-4/ts/app/app.component.1.ts', 'get-heroes')(format=".")
:marked
Ask for heroes and they are there in the returned result.
@ -465,17 +510,20 @@ a#child-component
**承诺** 就是 …… 好吧,它就是一个承诺 —— 在有了结果时,它承诺会回调我们。
我们请求一个异步服务去做点什么,然后给它一个回调函数。
它会去做(无论用哪种方式),一旦完成,它就会调用我们的回调函数,并通过参数把工作成果或者错误信息传给我们。
.l-sub-section
:marked
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上搜索其它学习资源。
:marked
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
把`HeroService`的`getHeroes`方法改写为返回承诺的形式:
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes', 'app/hero.service.ts (excerpt)')(format=".")
:marked
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.
@ -491,6 +539,7 @@ a#child-component
回到`AppComponent`和它的`getHeroes`方法,我们看到它看起来还是这样的:
+makeExample('toh-4/ts/app/app.component.1.ts', 'getHeroes', 'app/app.component.ts (getHeroes - old)')(format=".")
:marked
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**函数:
+makeExample('toh-4/ts/app/app.component.ts', 'get-heroes', 'app/app.component.ts (getHeroes - revised)')(format=".")
.l-sub-section
:marked
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)
能比等价的函数表达式更加快速、优雅的处理*this*指针。
: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!
@ -523,14 +574,18 @@ a#child-component
responding to a name selection with a detail view.
我们的程序仍在运行,仍在显示英雄列表,在选择英雄时,仍然会把他/她显示在详情页面中。
.l-sub-section
:marked
Checkout the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection.
查看附件中的“[慢一点儿](#slow)”一节,来了解在较差的网络连接中这个应用会是什么样的。
:marked
### Review the App Structure
### 回顾本应用的结构
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
## The Road Weve Travelled
## 走过的路
Lets take stock of what weve built.
来盘点一下我们已经构建完的部分。
@ -601,7 +658,9 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
:marked
### The Road Ahead
### 前方的路
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.
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>
:marked
### Appendix: Take it slow
### 附件:慢一点儿
We can simulate a slow connection.
@ -629,6 +689,7 @@ p 运行这部分的#[+liveExampleLink2('在线例子', 'toh-4')]。
导入`Hero`类,并且在`HeroService`中添加如下的`getHeroesSlowly`方法:
+makeExample('toh-4/ts/app/hero.service.ts', 'get-heroes-slowly', 'app/hero.service.ts (getHeroesSlowly)')(format=".")
:marked
Like `getHeroes`, it also returns a !{_Promise}.
But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.