refactor: 重构自动翻译代码

This commit is contained in:
Zhicheng Wang 2018-03-24 16:33:17 +08:00
parent 6c3d57aee9
commit e167fa5229
80 changed files with 9875 additions and 2961 deletions

View File

@ -62,9 +62,7 @@ The following table lists some of the key AngularJS template features with their
### 绑定/插值表达式 ### 绑定/插值表达式
<code-example hideCopy> <code-example hideCopy>
Your favorite hero is: {{vm.favoriteHero}} Your favorite hero is: {{vm.favoriteHero}}
</code-example> </code-example>
In AngularJS, an expression in curly braces denotes one-way binding. In AngularJS, an expression in curly braces denotes one-way binding.
@ -118,9 +116,7 @@ The following table lists some of the key AngularJS template features with their
### 过滤器 ### 过滤器
<code-example hideCopy> <code-example hideCopy>
&lt;td>{{movie.title | uppercase}}&lt;/td> &lt;td>{{movie.title | uppercase}}&lt;/td>
</code-example> </code-example>
To filter output in AngularJS templates, use the pipe character (|) and one or more filters. To filter output in AngularJS templates, use the pipe character (|) and one or more filters.
@ -165,11 +161,9 @@ The following table lists some of the key AngularJS template features with their
### 局部变量 ### 局部变量
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;tr ng-repeat="movie in vm.movies"> &lt;tr ng-repeat="movie in vm.movies">
&lt;td>{{movie.title}}&lt;/td> &lt;td>{{movie.title}}&lt;/td>
&lt;/tr> &lt;/tr>
</code-example> </code-example>
Here, `movie` is a user-defined local variable. Here, `movie` is a user-defined local variable.
@ -246,9 +240,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-app ### ng-app
<code-example hideCopy> <code-example hideCopy>
&lt;body ng-app="movieHunter"> &lt;body ng-app="movieHunter">
</code-example> </code-example>
The application startup process is called **bootstrapping**. The application startup process is called **bootstrapping**.
@ -295,11 +287,9 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-class ### ng-class
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;div ng-class="{active: isActive}"> &lt;div ng-class="{active: isActive}">
&lt;div ng-class="{active: isActive, &lt;div ng-class="{active: isActive,
shazam: isImportant}"> shazam: isImportant}">
</code-example> </code-example>
In AngularJS, the `ng-class` directive includes/excludes CSS classes In AngularJS, the `ng-class` directive includes/excludes CSS classes
@ -361,10 +351,8 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-click ### ng-click
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;button ng-click="vm.toggleImage()"> &lt;button ng-click="vm.toggleImage()">
&lt;button ng-click="vm.toggleImage($event)"> &lt;button ng-click="vm.toggleImage($event)">
</code-example> </code-example>
In AngularJS, the `ng-click` directive allows you to specify custom behavior when an element is clicked. In AngularJS, the `ng-click` directive allows you to specify custom behavior when an element is clicked.
@ -433,9 +421,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-controller ### ng-controller
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;div ng-controller="MovieListCtrl as vm"> &lt;div ng-controller="MovieListCtrl as vm">
</code-example> </code-example>
In AngularJS, the `ng-controller` directive attaches a controller to the view. In AngularJS, the `ng-controller` directive attaches a controller to the view.
@ -506,9 +492,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-href ### ng-href
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;a ng-href="{{ angularDocsUrl }}">Angular Docs&lt;/a> &lt;a ng-href="{{ angularDocsUrl }}">Angular Docs&lt;/a>
</code-example> </code-example>
The `ng-href` directive allows AngularJS to preprocess the `href` property so that it The `ng-href` directive allows AngularJS to preprocess the `href` property so that it
@ -522,9 +506,7 @@ AngularJS 为模板提供了七十多个内置指令。
在 AngularJS 中,`ng-href` 通常用来作为导航的一部分,激活一个路由。 在 AngularJS 中,`ng-href` 通常用来作为导航的一部分,激活一个路由。
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;a ng-href="#{{ moviesHash }}">Movies&lt;/a> &lt;a ng-href="#{{ moviesHash }}">Movies&lt;/a>
</code-example> </code-example>
Routing is handled differently in Angular. Routing is handled differently in Angular.
@ -574,9 +556,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-if ### ng-if
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;table ng-if="movies.length"> &lt;table ng-if="movies.length">
</code-example> </code-example>
In AngularJS, the `ng-if` directive removes or recreates a portion of the DOM, In AngularJS, the `ng-if` directive removes or recreates a portion of the DOM,
@ -623,9 +603,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-model ### ng-model
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;input ng-model="vm.favoriteHero"/> &lt;input ng-model="vm.favoriteHero"/>
</code-example> </code-example>
In AngularJS, the `ng-model` directive binds a form control to a property in the controller associated with the template. In AngularJS, the `ng-model` directive binds a form control to a property in the controller associated with the template.
@ -665,9 +643,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-repeat ### ng-repeat
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;tr ng-repeat="movie in vm.movies"> &lt;tr ng-repeat="movie in vm.movies">
</code-example> </code-example>
In AngularJS, the `ng-repeat` directive repeats the associated DOM element In AngularJS, the `ng-repeat` directive repeats the associated DOM element
@ -719,11 +695,9 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-show ### ng-show
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;h3 ng-show="vm.favoriteHero"> &lt;h3 ng-show="vm.favoriteHero">
Your favorite hero is: {{vm.favoriteHero}} Your favorite hero is: {{vm.favoriteHero}}
&lt;/h3> &lt;/h3>
</code-example> </code-example>
In AngularJS, the `ng-show` directive shows or hides the associated DOM element, based on In AngularJS, the `ng-show` directive shows or hides the associated DOM element, based on
@ -776,9 +750,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-src ### ng-src
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;img ng-src="{{movie.imageurl}}"> &lt;img ng-src="{{movie.imageurl}}">
</code-example> </code-example>
The `ng-src` directive allows AngularJS to preprocess the `src` property so that it The `ng-src` directive allows AngularJS to preprocess the `src` property so that it
@ -819,9 +791,7 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-style ### ng-style
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;div ng-style="{color: colorPreference}"> &lt;div ng-style="{color: colorPreference}">
</code-example> </code-example>
In AngularJS, the `ng-style` directive sets a CSS style on an HTML element In AngularJS, the `ng-style` directive sets a CSS style on an HTML element
@ -877,7 +847,6 @@ AngularJS 为模板提供了七十多个内置指令。
### ng-switch ### ng-switch
<code-example hideCopy format=""> <code-example hideCopy format="">
&lt;div ng-switch="vm.favoriteHero && &lt;div ng-switch="vm.favoriteHero &&
vm.checkMovieHero(vm.favoriteHero)"> vm.checkMovieHero(vm.favoriteHero)">
&lt;div ng-switch-when="true"> &lt;div ng-switch-when="true">
@ -890,7 +859,6 @@ AngularJS 为模板提供了七十多个内置指令。
Please enter your favorite hero. Please enter your favorite hero.
&lt;/div> &lt;/div>
&lt;/div> &lt;/div>
</code-example> </code-example>
In AngularJS, the `ng-switch` directive swaps the contents of In AngularJS, the `ng-switch` directive swaps the contents of
@ -996,9 +964,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### currency ### currency
<code-example hideCopy> <code-example hideCopy>
&lt;td>{{movie.price | currency}}&lt;/td> &lt;td>{{movie.price | currency}}&lt;/td>
</code-example> </code-example>
Formats a number as currency. Formats a number as currency.
@ -1028,9 +994,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### date ### date
<code-example hideCopy> <code-example hideCopy>
&lt;td>{{movie.releaseDate | date}}&lt;/td> &lt;td>{{movie.releaseDate | date}}&lt;/td>
</code-example> </code-example>
Formats a date to a string based on the requested format. Formats a date to a string based on the requested format.
@ -1060,9 +1024,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### filter ### filter
<code-example hideCopy> <code-example hideCopy>
&lt;tr ng-repeat="movie in movieList | filter: {title:listFilter}"> &lt;tr ng-repeat="movie in movieList | filter: {title:listFilter}">
</code-example> </code-example>
Selects a subset of items from the defined collection, based on the filter criteria. Selects a subset of items from the defined collection, based on the filter criteria.
@ -1094,9 +1056,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### json ### json
<code-example hideCopy> <code-example hideCopy>
&lt;pre>{{movie | json}}&lt;/pre> &lt;pre>{{movie | json}}&lt;/pre>
</code-example> </code-example>
Converts a JavaScript object into a JSON string. This is useful for debugging. Converts a JavaScript object into a JSON string. This is useful for debugging.
@ -1126,9 +1086,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### limitTo ### limitTo
<code-example hideCopy> <code-example hideCopy>
&lt;tr ng-repeat="movie in movieList | limitTo:2:0"> &lt;tr ng-repeat="movie in movieList | limitTo:2:0">
</code-example> </code-example>
Selects up to the first parameter (2) number of items from the collection Selects up to the first parameter (2) number of items from the collection
@ -1164,9 +1122,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### lowercase ### lowercase
<code-example hideCopy> <code-example hideCopy>
&lt;div>{{movie.title | lowercase}}&lt;/div> &lt;div>{{movie.title | lowercase}}&lt;/div>
</code-example> </code-example>
Converts the string to lowercase. Converts the string to lowercase.
@ -1196,9 +1152,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### number ### number
<code-example hideCopy> <code-example hideCopy>
&lt;td>{{movie.starRating | number}}&lt;/td> &lt;td>{{movie.starRating | number}}&lt;/td>
</code-example> </code-example>
Formats a number as text. Formats a number as text.
@ -1236,9 +1190,7 @@ AngularJS 中的很多内置过滤器在 Angular 中都有对应的管道。
### orderBy ### orderBy
<code-example hideCopy> <code-example hideCopy>
&lt;tr ng-repeat="movie in movieList | orderBy : 'title'"> &lt;tr ng-repeat="movie in movieList | orderBy : 'title'">
</code-example> </code-example>
Displays the collection in the order specified by the expression. Displays the collection in the order specified by the expression.
@ -1322,11 +1274,9 @@ The Angular code is shown using TypeScript.
### IIFE ### IIFE
<code-example hideCopy> <code-example hideCopy>
(function () { (function () {
... ...
}()); }());
</code-example> </code-example>
In AngularJS, an immediately invoked function expression (or IIFE) around controller code In AngularJS, an immediately invoked function expression (or IIFE) around controller code
@ -1365,9 +1315,7 @@ The Angular code is shown using TypeScript.
### Angular 模块 ### Angular 模块
<code-example hideCopy> <code-example hideCopy>
angular.module("movieHunter", ["ngRoute"]); angular.module("movieHunter", ["ngRoute"]);
</code-example> </code-example>
In AngularJS, an Angular module keeps track of controllers, services, and other code. In AngularJS, an Angular module keeps track of controllers, services, and other code.
@ -1412,13 +1360,11 @@ The Angular code is shown using TypeScript.
### 控制器注册 ### 控制器注册
<code-example hideCopy> <code-example hideCopy>
angular angular
.module("movieHunter") .module("movieHunter")
.controller("MovieListCtrl", .controller("MovieListCtrl",
["movieService", ["movieService",
MovieListCtrl]); MovieListCtrl]);
</code-example> </code-example>
AngularJS has code in each controller that looks up an appropriate Angular module AngularJS has code in each controller that looks up an appropriate Angular module
@ -1470,10 +1416,8 @@ The Angular code is shown using TypeScript.
### 控制器函数 ### 控制器函数
<code-example hideCopy> <code-example hideCopy>
function MovieListCtrl(movieService) { function MovieListCtrl(movieService) {
} }
</code-example> </code-example>
In AngularJS, you write the code for the model and methods in a controller function. In AngularJS, you write the code for the model and methods in a controller function.
@ -1516,11 +1460,9 @@ The Angular code is shown using TypeScript.
### 依赖注入 ### 依赖注入
<code-example hideCopy> <code-example hideCopy>
MovieListCtrl.$inject = ['MovieService']; MovieListCtrl.$inject = ['MovieService'];
function MovieListCtrl(movieService) { function MovieListCtrl(movieService) {
} }
</code-example> </code-example>
In AngularJS, you pass in any dependencies as controller function arguments. In AngularJS, you pass in any dependencies as controller function arguments.
@ -1616,9 +1558,7 @@ also encapsulate a style sheet within a specific component.
### Link 标签 ### Link 标签
<code-example hideCopy> <code-example hideCopy>
&lt;link href="styles.css" rel="stylesheet" /> &lt;link href="styles.css" rel="stylesheet" />
</code-example> </code-example>
AngularJS, uses a `link` tag in the head section of the `index.html` file AngularJS, uses a `link` tag in the head section of the `index.html` file

View File

@ -291,10 +291,8 @@ These two common animations have their own aliases:
这两个常见的动画有自己的别名: 这两个常见的动画有自己的别名:
<code-example language="typescript"> <code-example language="typescript">
transition(':enter', [ ... ]); // void => * transition(':enter', [ ... ]); // void => *
transition(':leave', [ ... ]); // * => void transition(':leave', [ ... ]); // * => void
</code-example> </code-example>
</div> </div>
@ -562,5 +560,4 @@ The callbacks receive an `AnimationEvent` that contains useful properties such a
Those callbacks will fire whether or not an animation is picked up. Those callbacks will fire whether or not an animation is picked up.
无论动画是否实际执行过,那些回调都会触发。 无论动画是否实际执行过,那些回调都会触发。

View File

@ -48,10 +48,8 @@ JIT compilation is the default when you run the _build-only_ or the _build-and-s
当你运行 *`build`**`serve`* 这两个 CLI 命令时 JIT 编译是默认选项: 当你运行 *`build`**`serve`* 这两个 CLI 命令时 JIT 编译是默认选项:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng build ng build
ng serve ng serve
</code-example> </code-example>
{@a compile} {@a compile}
@ -61,10 +59,8 @@ For AOT compilation, append the `--aot` flags to the _build-only_ or the _build-
要进行 AOT 编译只要给这两个 CLI 命令添加 `--aot` 标志就行了: 要进行 AOT 编译只要给这两个 CLI 命令添加 `--aot` 标志就行了:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng build --aot ng build --aot
ng serve --aot ng serve --aot
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -170,7 +166,7 @@ The option is `false` by default.
这个选项告诉编译器不要生成 `.metadata.json` 文件,它默认是 `false` 这个选项告诉编译器不要生成 `.metadata.json` 文件,它默认是 `false`
`.metadata.json` files contain information needed by the template compiler from a `.ts` `.metadata.json` files contain infomration needed by the template compiler from a `.ts`
file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains, file that is not included in the `.d.ts` file produced by the TypeScript compiler. This information contains,
for example, the content of annotations (such as a component's template) which TypeScript for example, the content of annotations (such as a component's template) which TypeScript
emits to the `.js` file but not to the `.d.ts` file. emits to the `.js` file but not to the `.d.ts` file.
@ -195,7 +191,6 @@ include a copy of the information that is in the `.metadata.json` file.
This option tells the template compiler to report an error to the `.metadata.json` This option tells the template compiler to report an error to the `.metadata.json`
file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`. file if `"skipMetadataEmit"` is `false` . This option is `false` by default. This should only be used when `"skipMetadataEmit"` is `false` and `"skipTemplateCodeGen"` is `true`.
<!-- 这里整节都不太确定 -->
这个选项告诉模板编译器如果 `"skipMetadataEmit"``false`,那就把错误信息汇报到 `.metadata.json` 中。 这个选项告诉模板编译器如果 `"skipMetadataEmit"``false`,那就把错误信息汇报到 `.metadata.json` 中。
只有当 `"skipMetadataEmit"``false``"skipTemplateCodeGen"``true` 时才应该使用这个选项。 只有当 `"skipMetadataEmit"``false``"skipTemplateCodeGen"``true` 时才应该使用这个选项。
@ -383,21 +378,21 @@ rules.
这是供 `bazel` 构建规则使用的选项,它用于简化 `bazel` 规则跟踪文件依赖的方式。 这是供 `bazel` 构建规则使用的选项,它用于简化 `bazel` 规则跟踪文件依赖的方式。
除了 `bazel` 规则之外不建议使用该选项。 除了 `bazel` 规则之外不建议使用该选项。
### *enableIvy* ### *enableIvy*
Tells the compiler to generate definitions using the Render3 style code generation. This option defaults to `false`. Tells the compiler to generate definitions using the Render3 style code generation. This option defaults to `false`.
告诉编译器使用 Render3 风格的代码生成器来来生成各种定义。 告诉编译器使用 Render3 风格的代码生成器来来生成各种定义。
该选项默认为 `false` 该选项默认为 `false`
Not all features are supported with this option enabled. It is only supported Not all features are supported with this option enabled. It is only supported
for experimentation and testing of Render3 style code generation. for experimentation and testing of Render3 style code generation.
当开启该选项时,有些特性不受支持。它仅仅用来为试验和测试 Render3 风格的代码生成提供支持。 当开启该选项时,有些特性不受支持。它仅仅用来为试验和测试 Render3 风格的代码生成提供支持。
*Note*: Is it not recommended to use this option as it is not yet feature complete with the Render2 code generation. *Note*: Is it not recommended to use this option as it is not yet feature complete with the Render2 code generation.
*注意*:不建议使用该选项,因为它在使用 Render2 的代码生成器时还缺少一些特性。 *注意*:不建议使用该选项,因为它在使用 Render2 的代码生成器时还缺少一些特性。
## Angular Metadata and AOT ## Angular Metadata and AOT
@ -828,7 +823,7 @@ The compiler only supports metadata for these Angular decorators.
编译器只支持下列 Angular 装饰器的元数据。 编译器只支持下列 Angular 装饰器的元数据。
<t>Decorator<t><t>装饰器</t> | <t>Module</t><t>所在模块</t> <t>Decorator</t><t>装饰器</t> | <t>Module</t><t>所在模块</t>
------------------|-------------- ------------------|--------------
`Attribute` | `@angular/core` `Attribute` | `@angular/core`
`Component` | `@angular/core` `Component` | `@angular/core`
@ -982,18 +977,18 @@ The following are metadata errors you may encounter, with explanations and sugge
你可能遇到一些元数据错误,下面是对它们的解释和纠正建议。 你可能遇到一些元数据错误,下面是对它们的解释和纠正建议。
[Expression form not supported <t>【不支持此表达式格式】</t>](#expression-form-not-supported)<br> [<t>Expression form not supported</t><t>【不支持此表达式格式】</t>](#expression-form-not-supported)<br>
[Reference to a local (non-exported) symbol<t>【引用了局部(未导出的)符号】</t>](#reference-to-a-local-symbol)<br> [<t>Reference to a local (non-exported) symbol</t><t>【引用了局部(未导出的)符号】</t>](#reference-to-a-local-symbol)<br>
[Only initialized variables and constants<t>【只允许初始化过的变量和常量】</t>](#only-initialized-variables)<br> [<t>Only initialized variables and constants</t><t>【只允许初始化过的变量和常量】</t>](#only-initialized-variables)<br>
[Reference to a non-exported class<t>【引用了未导出的类】</t>](#reference-to-a-non-exported-class)<br> [<t>Reference to a non-exported class</t><t>【引用了未导出的类】</t>](#reference-to-a-non-exported-class)<br>
[Reference to a non-exported function<t>【引用了未导出的函数】</t>](#reference-to-a-non-exported-function)<br> [<t>Reference to a non-exported function</t><t>【引用了未导出的函数】</t>](#reference-to-a-non-exported-function)<br>
[Function calls are not supported<t>【不支持函数调用】</t>](#function-calls-not-supported)<br> [<t>Function calls are not supported</t><t>【不支持函数调用】</t>](#function-calls-not-supported)<br>
[Destructured variable or constant not supported<t>【不支持解构变量或常量】</t>](#destructured-variable-not-supported)<br> [<t>Destructured variable or constant not supported</t><t>【不支持解构变量或常量】</t>](#destructured-variable-not-supported)<br>
[Could not resolve type<t>【不能解析此类型】</t>](#could-not-resolve-type)<br> [<t>Could not resolve type</t><t>【不能解析此类型】</t>](#could-not-resolve-type)<br>
[Name expected<t>【期待是名字】</t>](#name-expected)<br> [<t>Name expected</t><t>【期待是名字】</t>](#name-expected)<br>
[Unsupported enum member name<t>【不支持的枚举成员名】</t>](#unsupported-enum-member-name)<br> [<t>Unsupported enum member name</t><t>【不支持的枚举成员名】</t>](#unsupported-enum-member-name)<br>
[Tagged template expressions are not supported<t>【不支持带标签函数的模板表达式】</t>](#tagged-template-expressions-not-supported)<br> [<t>Tagged template expressions are not supported</t><t>【不支持带标签函数的模板表达式】</t>](#tagged-template-expressions-not-supported)<br>
[Symbol reference expected<t>【期待是符号引用】</t>](#symbol-reference-expected)<br> [<t>Symbol reference expected</t><t>【期待是符号引用】</t>](#symbol-reference-expected)<br>
<hr> <hr>
@ -1383,7 +1378,6 @@ To correct this error, export a function from the module and refer to the functi
要改正这个问题,就要从模块中导出这个函数,并改成在服务提供商的 `useFactory` 中引用该函数。 要改正这个问题,就要从模块中导出这个函数,并改成在服务提供商的 `useFactory` 中引用该函数。
<code-example linenums="false"> <code-example linenums="false">
// CORRECTED // CORRECTED
import { calculateValue } from './utilities'; import { calculateValue } from './utilities';
@ -1399,7 +1393,6 @@ export function someValueFactory() {
{ provide: SomeValue, useFactory: someValueFactory } { provide: SomeValue, useFactory: someValueFactory }
] ]
... ...
</code-example> </code-example>
<hr> <hr>
@ -1425,7 +1418,6 @@ For example, you cannot write something like this:
比如,你不能这么写: 比如,你不能这么写:
<code-example linenums="false"> <code-example linenums="false">
// ERROR // ERROR
import { configuration } from './configuration'; import { configuration } from './configuration';
@ -1437,7 +1429,6 @@ const {foo, bar} = configuration;
{provide: Bar, useValue: bar}, {provide: Bar, useValue: bar},
] ]
... ...
</code-example> </code-example>
To correct this error, refer to non-destructured values. To correct this error, refer to non-destructured values.
@ -1445,7 +1436,6 @@ To correct this error, refer to non-destructured values.
要纠正这个错误,就要引用非解构方式的变量。 要纠正这个错误,就要引用非解构方式的变量。
<code-example linenums="false"> <code-example linenums="false">
// CORRECTED // CORRECTED
import { configuration } from './configuration'; import { configuration } from './configuration';
... ...
@ -1454,7 +1444,6 @@ import { configuration } from './configuration';
{provide: Bar, useValue: configuration.bar}, {provide: Bar, useValue: configuration.bar},
] ]
... ...
</code-example> </code-example>
<hr> <hr>
@ -1528,7 +1517,6 @@ Here's an illustrative example.
下面的例子说明了这一点。 下面的例子说明了这一点。
<code-example linenums="false"> <code-example linenums="false">
// CORRECTED // CORRECTED
import { Inject } from '@angular/core'; import { Inject } from '@angular/core';
@ -1544,7 +1532,6 @@ export function _window() { return window; }
export class MyComponent { export class MyComponent {
constructor (@Inject(WINDOW) private win: Window) { ... } constructor (@Inject(WINDOW) private win: Window) { ... }
} }
</code-example> </code-example>
The `Window` type in the constructor is no longer a problem for the compiler because it The `Window` type in the constructor is no longer a problem for the compiler because it
@ -1557,7 +1544,6 @@ Angular does something similar with the `DOCUMENT` token so you can inject the b
Angular 也用 `DOCUMENT` 令牌做了类似的事情,所以你也可以注入浏览器的 `document` 对象(或它的一个抽象层,取决于该应用运行在哪个平台)。 Angular 也用 `DOCUMENT` 令牌做了类似的事情,所以你也可以注入浏览器的 `document` 对象(或它的一个抽象层,取决于该应用运行在哪个平台)。
<code-example linenums="false"> <code-example linenums="false">
import { Inject } from '@angular/core'; import { Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser'; import { DOCUMENT } from '@angular/platform-browser';
@ -1565,7 +1551,6 @@ import { DOCUMENT } from '@angular/platform-browser';
export class MyComponent { export class MyComponent {
constructor (@Inject(DOCUMENT) private doc: Document) { ... } constructor (@Inject(DOCUMENT) private doc: Document) { ... }
} }
</code-example> </code-example>
<hr> <hr>
@ -1613,7 +1598,6 @@ The compiler can understand simple enum values but not complex values such as th
编译器可以理解简单的枚举值,但不能理解复杂的,比如从那些计算属性中派生出来的。 编译器可以理解简单的枚举值,但不能理解复杂的,比如从那些计算属性中派生出来的。
<code-example linenums="false"> <code-example linenums="false">
// ERROR // ERROR
enum Colors { enum Colors {
Red = 1, Red = 1,
@ -1628,7 +1612,6 @@ enum Colors {
{ provide: StrongColor, useValue: Colors.Blue } // bad { provide: StrongColor, useValue: Colors.Blue } // bad
] ]
... ...
</code-example> </code-example>
Avoid referring to enums with complicated initializers or computed properties. Avoid referring to enums with complicated initializers or computed properties.
@ -1915,28 +1898,28 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
* What the AOT compiler does and why it is important. * What the AOT compiler does and why it is important.
什么是 AOT 编译器,以及它为什么如此重要。 什么是 AOT 编译器,以及它为什么如此重要。
* Why metadata must be written in a subset of JavaScript. * Why metadata must be written in a subset of JavaScript.
为何元数据必须使用 JavaScript 的一个子集来书写。 为何元数据必须使用 JavaScript 的一个子集来书写。
* What that subset is. * What that subset is.
这个子集是什么。 这个子集是什么。
* Other restrictions on metadata definition. * Other restrictions on metadata definition.
定义元数据时的其它限制。 定义元数据时的其它限制。
* Macro-functions and macro-static methods. * Macro-functions and macro-static methods.
宏函数和静态宏函数。 宏函数和静态宏函数。
* Compiler errors related to metadata. * Compiler errors related to metadata.
与元数据有关的编译器错误。 与元数据有关的编译器错误。
* Validation of binding expressions * Validation of binding expressions
验证绑定表达式。 验证绑定表达式。

View File

@ -4,9 +4,7 @@
</div> </div>
<header class="api-header"> <header class="api-header"><h1><label class="api-status-label experimental">experimental</label><label class="api-type-label class">class</label>Class Name</h1></header>
<h1><label class="api-status-label experimental">experimental</label><label class="api-type-label class">class</label>Class Name</h1>
</header>
<div class="page-actions"> <div class="page-actions">
@ -84,13 +82,13 @@
</li> </li>
</ul> </ul>
</section> </section>
<section> <section>
<h2>Constructor</h2> <h2>Constructor</h2>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0"> <code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<aio-code class="simple-code"><pre class="prettyprint lang-"> <aio-code class="simple-code"><pre class="prettyprint lang-">
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> <code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
@ -103,7 +101,6 @@
<table class="is-full-width list-table"> <table class="is-full-width list-table">
<thead> <thead>
<tr> <tr>
<th> <th>
@ -131,10 +128,8 @@
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td> <td>
@ -156,7 +151,6 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -180,7 +174,6 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -204,7 +197,6 @@
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</section> </section>
@ -214,7 +206,6 @@
<table class="is-full-width item-table"> <table class="is-full-width item-table">
<thead> <thead>
<tr> <tr>
<th> <th>
@ -224,10 +215,8 @@
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td> <td>
@ -241,12 +230,10 @@
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<table class="is-full-width api-method item-table"> <table class="is-full-width api-method item-table">
<thead> <thead>
<tr> <tr>
<th> <th>
@ -256,10 +243,8 @@
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td> <td>
@ -271,11 +256,10 @@
<h5>Declaration</h5> <h5>Declaration</h5>
<code-example language="ts" hidecopy="true" ng-version="5.2.0"> <code-example language="ts" hidecopy="true" ng-version="5.2.0">
<aio-code class="simple-code"><pre class="prettyprint lang-ts"> <aio-code class="simple-code"><pre class="prettyprint lang-ts">
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/animations/AnimationBuilder" class="code-anchor"><span class="typ">AnimationBuilder</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><a class="code-anchor" href="api/animations/AnimationBuilder#build"><span class="pln">build</span><span class="pun">(</span><span class="pln">animation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pun">[]):</span><span class="pln"> </span><span class="typ">AnimationFactory</span></a><span class="pln"></span><span class="pun">}</span></code></pre> <code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/animations/AnimationBuilder" class="code-anchor"><span class="typ">AnimationBuilder</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln"></span><a class="code-anchor" href="api/animations/AnimationBuilder#build"><span class="pln">build</span><span class="pun">(</span><span class="pln">animation</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">AnimationMetadata</span><span class="pun">[]):</span><span class="pln"> </span><span class="typ">AnimationFactory</span></a><span class="pln"></span><span class="pun">}</span></code></pre>
</aio-code>
</aio-code>
</code-example> </code-example>
<h6>Parameters</h6> <h6>Parameters</h6>
@ -296,13 +280,10 @@
<table class="is-full-width"> <table class="is-full-width">
<tbody> <tbody>
<tr> <tr>
<td> <td>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0"> <code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<aio-code class="simple-code"><pre class="prettyprint lang-"> <aio-code class="simple-code"><pre class="prettyprint lang-">
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> <code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
@ -318,13 +299,11 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0"> <code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<aio-code class="simple-code"><pre class="prettyprint lang-"> <aio-code class="simple-code"><pre class="prettyprint lang-">
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> <code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
@ -340,7 +319,6 @@
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -351,9 +329,7 @@
<p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p> <p>Bacon ipsum dolor amet pork belly capicola sirloin venison alcatra ground round ham hock jowl turkey picanha bresaola pancetta brisket chicken fatback. Burgdoggen kevin salami jowl shoulder jerky leberkas meatball. Ham hock picanha burgdoggen pork belly rump bacon cupim. Bacon kielbasa sirloin shank strip steak ground round. Bresaola cow salami meatloaf pork chop leberkas flank turducken biltong meatball chuck pork tri-tip chicken. Ribeye corned beef shoulder, meatloaf strip steak jerky porchetta capicola alcatra ham.</p>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</section> </section>
@ -364,7 +340,6 @@
<p>Intro description text about what the example is and how it can be used.</p> <p>Intro description text about what the example is and how it can be used.</p>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0"> <code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<aio-code class="simple-code"><pre class="prettyprint lang-"> <aio-code class="simple-code"><pre class="prettyprint lang-">
<code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> <code class="animated fadeIn"><span class="kwd">constructor</span><span class="pun">(</span><span class="pln">element</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">,</span><span class="pln"> keyframes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">key</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">]:</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">

View File

@ -10,6 +10,8 @@ While a small application might have only one NgModule, most apps have many more
## NgModule metadata ## NgModule metadata
## `@NgModule` 元数据
An NgModule is defined as a class decorated with `@NgModule`. The `@NgModule` decorator is a function that takes a single metadata object, whose properties describe the module. The most important properties are as follows. An NgModule is defined as a class decorated with `@NgModule`. The `@NgModule` decorator is a function that takes a single metadata object, whose properties describe the module. The most important properties are as follows.
* `declarations`&mdash;The [components](guide/architecture-components), _directives_, and _pipes_ that belong to this NgModule. * `declarations`&mdash;The [components](guide/architecture-components), _directives_, and _pipes_ that belong to this NgModule.

View File

@ -1,4 +1,4 @@
# Architecture Overview # Architecture overview
# 架构概览 # 架构概览
@ -122,6 +122,8 @@ To define navigation rules, you associate *navigation paths* with your component
## What's next ## What's next
## 接下来呢?
You've learned the basics about the main building blocks of an Angular application. The following diagram shows how these basic pieces are related. You've learned the basics about the main building blocks of an Angular application. The following diagram shows how these basic pieces are related.
<figure> <figure>

View File

@ -83,9 +83,7 @@ Create the directive class file in a terminal window with this CLI command.
在命令行窗口下用 CLI 命令创建指令类文件。 在命令行窗口下用 CLI 命令创建指令类文件。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate directive highlight ng generate directive highlight
</code-example> </code-example>
The CLI creates `src/app/highlight.directive.ts`, a corresponding test file (`.../spec.ts`, and _declares_ the directive class in the root `AppModule`. The CLI creates `src/app/highlight.directive.ts`, a corresponding test file (`.../spec.ts`, and _declares_ the directive class in the root `AppModule`.
@ -197,9 +195,7 @@ Now run the application to see the `HighlightDirective` in action.
运行这个应用以查看 `HighlightDirective` 的实际效果。 运行这个应用以查看 `HighlightDirective` 的实际效果。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng serve ng serve
</code-example> </code-example>
To summarize, Angular found the `appHighlight` attribute on the **host** `<p>` element. To summarize, Angular found the `appHighlight` attribute on the **host** `<p>` element.
@ -531,14 +527,12 @@ The final source code follows:
最终的源码如下: 最终的源码如下:
<code-tabs> <code-tabs>
<code-pane title="app/app.component.ts" path="attribute-directives/src/app/app.component.ts"></code-pane> <code-pane title="app/app.component.ts" path="attribute-directives/src/app/app.component.ts"></code-pane>
<code-pane title="app/app.component.html" path="attribute-directives/src/app/app.component.html"></code-pane> <code-pane title="app/app.component.html" path="attribute-directives/src/app/app.component.html"></code-pane>
<code-pane title="app/highlight.directive.ts" path="attribute-directives/src/app/highlight.directive.ts"></code-pane> <code-pane title="app/highlight.directive.ts" path="attribute-directives/src/app/highlight.directive.ts"></code-pane>
<code-pane title="app/app.module.ts" path="attribute-directives/src/app/app.module.ts"></code-pane> <code-pane title="app/app.module.ts" path="attribute-directives/src/app/app.module.ts"></code-pane>
<code-pane title="main.ts" path="attribute-directives/src/main.ts"></code-pane> <code-pane title="main.ts" path="attribute-directives/src/main.ts"></code-pane>
<code-pane title="index.html" path="attribute-directives/src/index.html"></code-pane> <code-pane title="index.html" path="attribute-directives/src/index.html"></code-pane>
</code-tabs> </code-tabs>
You can also experience and download the <live-example title="Attribute Directive example"></live-example>. You can also experience and download the <live-example title="Attribute Directive example"></live-example>.
@ -624,12 +618,12 @@ Now apply that reasoning to the following example:
The template and its component trust each other. The template and its component trust each other.
The `color` property doesn't require the `@Input` decorator. The `color` property doesn't require the `@Input` decorator.
`color` 属性位于右侧的绑定表达式中,它属于模板所在的组件。 `color` 属性位于右侧的绑定表达式中,它属于模板所在的组件。
该模板和组件相互信任。因此 `color` 不需要 `@Input` 装饰器。 该模板和组件相互信任。因此 `color` 不需要 `@Input` 装饰器。
* The `appHighlight` property on the left refers to an _aliased_ property of the `HighlightDirective`, * The `appHighlight` property on the left refers to an _aliased_ property of the `HighlightDirective`,
not a property of the template's component. There are trust issues. not a property of the template's component. There are trust issues.
Therefore, the directive property must carry the `@Input` decorator. Therefore, the directive property must carry the `@Input` decorator.
`appHighlight` 属性位于左侧,它引用了 `HighlightDirective` 中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。 `appHighlight` 属性位于左侧,它引用了 `HighlightDirective` 中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。
所以,该属性必须带 `@Input` 装饰器。 所以,该属性必须带 `@Input` 装饰器。

View File

@ -12,7 +12,7 @@ A basic understanding of the following:
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule). * [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
[JavaScript 模块与 NgModules](guide/ngmodule-vs-jsmodule). [JavaScript 模块与 NgModules](guide/ngmodule-vs-jsmodule)
<hr /> <hr />
@ -69,15 +69,15 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
* **_declarations_**&mdash;this application's lone component. * **_declarations_**&mdash;this application's lone component.
**_declarations_** —— 该应用所拥有的组件。 **_declarations_** —— 该应用所拥有的组件。
* **_imports_**&mdash;import `BrowserModule` to have browser specific services such as DOM rendering, sanitization, and location. * **_imports_**&mdash;import `BrowserModule` to have browser specific services such as DOM rendering, sanitization, and location.
**_imports_** —— 导入 `BrowserModule` 以获取浏览器特有的服务,比如 DOM 渲染、无害化处理和位置location **_imports_** —— 导入 `BrowserModule` 以获取浏览器特有的服务,比如 DOM 渲染、无害化处理和位置location
* **_providers_**&mdash;the service providers. * **_providers_**&mdash;the service providers.
**_providers_** —— 各种服务提供商。 **_providers_** —— 各种服务提供商。
* **_bootstrap_**&mdash;the _root_ component that Angular creates and inserts * **_bootstrap_**&mdash;the _root_ component that Angular creates and inserts
into the `index.html` host web page. into the `index.html` host web page.
@ -176,7 +176,6 @@ The following example, named `ItemDirective` is the default directive structure
下面的例子中,`item.directive.ts` 中的 `ItemDirective` 是 CLI 自动生成的默认指令结构。 下面的例子中,`item.directive.ts` 中的 `ItemDirective` 是 CLI 自动生成的默认指令结构。
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false"> <code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false">
</code-example> </code-example>
The key point here is that you have to export it so you can import it elsewhere. Next, import it The key point here is that you have to export it so you can import it elsewhere. Next, import it
@ -185,7 +184,6 @@ into the NgModule, in this example `app.module.ts`, with a JavaScript import sta
重点在于你要先在这里导出它才能在别处导入它。接下来,使用 JavaScript 的 `import` 语句把它导入到 NgModule 中(这里是 `app.module.ts`)。 重点在于你要先在这里导出它才能在别处导入它。接下来,使用 JavaScript 的 `import` 语句把它导入到 NgModule 中(这里是 `app.module.ts`)。
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
And in the same file, add it to the `@NgModule` `declarations` array: And in the same file, add it to the `@NgModule` `declarations` array:
@ -193,7 +191,6 @@ And in the same file, add it to the `@NgModule` `declarations` array:
同样在这个文件中,把它添加到 `@NgModule``declarations` 数组中: 同样在这个文件中,把它添加到 `@NgModule``declarations` 数组中:
<code-example path="bootstrapping/src/app/app.module.ts" region="declarations" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="declarations" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
Now you could use your `ItemDirective` in a component. This example uses `AppModule`, but you'd do it the same way for a feature module. For more about directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). You'd also use the same technique for [pipes](guide/pipes) and components. Now you could use your `ItemDirective` in a component. This example uses `AppModule`, but you'd do it the same way for a feature module. For more about directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). You'd also use the same technique for [pipes](guide/pipes) and components.

View File

@ -81,7 +81,6 @@ Angular 支持大多数常用浏览器,包括下列版本:
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -97,9 +96,7 @@ Angular 支持大多数常用浏览器,包括下列版本:
</td> </td>
</tr> </tr>
<tr> <tr>
<tr> <tr>
<td> <td>
@ -115,7 +112,6 @@ Angular 支持大多数常用浏览器,包括下列版本:
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -133,7 +129,6 @@ Angular 支持大多数常用浏览器,包括下列版本:
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -151,7 +146,6 @@ Angular 支持大多数常用浏览器,包括下列版本:
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -239,7 +233,6 @@ For example, [if you need the web animations polyfill](http://caniuse.com/#feat=
# it isn't a strict requirement of Angular anymore (more below) # it isn't a strict requirement of Angular anymore (more below)
npm install --save web-animations-js npm install --save web-animations-js
</code-example> </code-example>
Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example: Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example:
@ -247,7 +240,6 @@ Then open the `polyfills.ts` file and un-comment the corresponding `import` stat
然后打开 `polyfills.ts` 文件,并反注释对应的 `import` 语句,就像这样: 然后打开 `polyfills.ts` 文件,并反注释对应的 `import` 语句,就像这样:
<code-example title="src/polyfills.ts"> <code-example title="src/polyfills.ts">
/** /**
* Required to support Web Animations `@angular/platform-browser/animations`. * Required to support Web Animations `@angular/platform-browser/animations`.
@ -255,7 +247,6 @@ Then open the `polyfills.ts` file and un-comment the corresponding `import` stat
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
**/ **/
import 'web-animations-js'; // Run `npm install --save web-animations-js`. import 'web-animations-js'; // Run `npm install --save web-animations-js`.
</code-example> </code-example>
If you can't find the polyfill you want in `polyfills.ts`, If you can't find the polyfill you want in `polyfills.ts`,
@ -799,7 +790,6 @@ If you are not using the CLI, you should add your polyfill scripts directly to t
如果你不使用 CLI就要直接把腻子脚本添加到宿主页`index.html`)中,就像这样: 如果你不使用 CLI就要直接把腻子脚本添加到宿主页`index.html`)中,就像这样:
<code-example title="src/index.html"> <code-example title="src/index.html">
&lt;!-- pre-zone polyfills --> &lt;!-- pre-zone polyfills -->
&lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script> &lt;script src="node_modules/core-js/client/shim.min.js">&lt;/script>
&lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script> &lt;script src="node_modules/web-animations-js/web-animations.min.js">&lt;/script>
@ -828,5 +818,4 @@ If you are not using the CLI, you should add your polyfill scripts directly to t
&lt;script src="node_modules/zone.js/dist/zone.js">&lt;/script> &lt;script src="node_modules/zone.js/dist/zone.js">&lt;/script>
&lt;!-- application polyfills --> &lt;!-- application polyfills -->
</code-example> </code-example>

View File

@ -431,5 +431,4 @@ modules with SystemJS as the samples currently do.
The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
draws more attention to the order in which Angular calls the hooks. draws more attention to the order in which Angular calls the hooks.
[生命周期钩子](guide/lifecycle-hooks)章现在更加简短,并且对强调了 Angular 是以什么顺序来调用钩子方法的。 [生命周期钩子](guide/lifecycle-hooks)章现在更加简短,并且对强调了 Angular 是以什么顺序来调用钩子方法的。

View File

@ -18,13 +18,11 @@
<th> <th>
<p><code>import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';</code> <p><code>import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -42,7 +40,6 @@
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -57,13 +54,11 @@
<th> <th>
<p><code>import { NgModule } from '@angular/core';</code> <p><code>import { NgModule } from '@angular/core';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -162,7 +157,6 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -181,7 +175,6 @@ is available to <code>declarations</code> of this module.</p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -410,7 +403,6 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -427,13 +419,11 @@ is available to <code>declarations</code> of this module.</p>
<th> <th>
<p><code>import { CommonModule } from '@angular/common';</code> <p><code>import { CommonModule } from '@angular/common';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -499,7 +489,6 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -517,7 +506,6 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -534,13 +522,11 @@ is available to <code>declarations</code> of this module.</p>
<th> <th>
<p><code>import { FormsModule } from '@angular/forms';</code> <p><code>import { FormsModule } from '@angular/forms';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -558,7 +544,6 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -575,13 +560,11 @@ is available to <code>declarations</code> of this module.</p>
<th> <th>
<p><code>import { Directive, ... } from '@angular/core';</code> <p><code>import { Directive, ... } from '@angular/core';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -641,16 +624,13 @@ is available to <code>declarations</code> of this module.</p>
<td> <td>
<p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class. <p>Declares that a class has dependencies that should be injected into the constructor when the dependency injector is creating an instance of this class.
</p> </p>
<p>声明某个类具有一些依赖。当依赖注入器要创建这个类的实例时,应该把这些依赖注入到它的构造函数中。</p> <p>声明某个类具有一些依赖。当依赖注入器要创建这个类的实例时,应该把这些依赖注入到它的构造函数中。</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -667,13 +647,11 @@ is available to <code>declarations</code> of this module.</p>
<th> <th>
<p><code>@Directive({ property1: value1, ... })</code> <p><code>@Directive({ property1: value1, ... })</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -712,7 +690,6 @@ is available to <code>declarations</code> of this module.</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -728,7 +705,8 @@ is available to <code>declarations</code> of this module.</p>
<th> <th>
<p><code>@Component</code> extends <code>@Directive</code>, <p>
<code>@Component</code> extends <code>@Directive</code>,
so the <code>@Directive</code> configuration applies to components as well</p> so the <code>@Directive</code> configuration applies to components as well</p>
<p><code>@Component</code> 继承自 <code>@Directive</code> <p><code>@Component</code> 继承自 <code>@Directive</code>
@ -737,7 +715,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -803,7 +780,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -820,13 +796,11 @@ so the <code>@Directive</code> configuration applies to components as well</p>
<th> <th>
<p><code>import { Input, ... } from '@angular/core';</code> <p><code>import { Input, ... } from '@angular/core';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -957,7 +931,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -974,15 +947,13 @@ so the <code>@Directive</code> configuration applies to components as well</p>
<th> <th>
<p>(implemented as class methods) <p>(implemented as class methods)
</p> </p>
<p>由类的方法实现。</p> <p>由类的方法实现。</p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1128,7 +1099,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -1147,7 +1117,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1197,7 +1166,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
<table class="is-full-width is-fixed-layout"> <table class="is-full-width is-fixed-layout">
@ -1214,13 +1182,11 @@ so the <code>@Directive</code> configuration applies to components as well</p>
<th> <th>
<p><code>import { Routes, RouterModule, ... } from '@angular/router';</code> <p><code>import { Routes, RouterModule, ... } from '@angular/router';</code>
</p> </p>
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1366,7 +1332,6 @@ so the <code>@Directive</code> configuration applies to components as well</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
</div> </div>

View File

@ -21,52 +21,48 @@ Observables are often compared to promises. Here are some key differences:
* Observables are declarative; computation does not start until subscription. Promises execute immediately on creation. This makes observables useful for defining recipes that can be run whenever you need the result. * Observables are declarative; computation does not start until subscription. Promises execute immediately on creation. This makes observables useful for defining recipes that can be run whenever you need the result.
可观察对象是声明式的,在被订阅之前,它不会开始执行。承诺是在创建时就立即执行的。这让可观察对象可用于定义那些应该按需执行的菜谱。 可观察对象是声明式的,在被订阅之前,它不会开始执行。承诺是在创建时就立即执行的。这让可观察对象可用于定义那些应该按需执行的菜谱。
* Observables provide many values. Promises provide one. This makes observables useful for getting multiple values over time. * Observables provide many values. Promises provide one. This makes observables useful for getting multiple values over time.
可观察对象能提供多个值。承诺只提供一个。这让可观察对象可用于随着时间的推移获取多个值。 可观察对象能提供多个值。承诺只提供一个。这让可观察对象可用于随着时间的推移获取多个值。
* Observables differentiate between chaining and subscription. Promises only have `.then()` clauses. This makes observables useful for creating complex transformation recipes to be used by other part of the system, without causing the work to be executed. * Observables differentiate between chaining and subscription. Promises only have `.then()` clauses. This makes observables useful for creating complex transformation recipes to be used by other part of the system, without causing the work to be executed.
可观察对象会区分串联处理和订阅语句。承诺只有 `.then()` 语句。这让可观察对象可用于创建供系统的其它部分使用而不希望立即执行的复杂菜谱。 可观察对象会区分串联处理和订阅语句。承诺只有 `.then()` 语句。这让可观察对象可用于创建供系统的其它部分使用而不希望立即执行的复杂菜谱。
* Observables `subscribe()` is responsible for handling errors. Promises push errors to the child promises. This makes observables useful for centralized and predictable error handling. * Observables `subscribe()` is responsible for handling errors. Promises push errors to the child promises. This makes observables useful for centralized and predictable error handling.
可观察对象的 `subscribe()` 会负责处理错误。承诺会把错误推送给它的子承诺。这让可观察对象可用于进行集中式、可预测的错误处理。 可观察对象的 `subscribe()` 会负责处理错误。承诺会把错误推送给它的子承诺。这让可观察对象可用于进行集中式、可预测的错误处理。
### Creation and subscription ### Creation and subscription
### 创建与订阅 ### 创建与订阅
* Observables are not executed until a consumer subscribes. The `subscribe()` executes the defined behavior once, and it can be called again. Each subscription has its own computation. Resubscription causes recomputation of values. * Observables are not executed until a consumer subcribes. The `subscribe()` executes the defined behavior once, and it can be called again. Each subscription has its own computation. Resubscription causes recomputation of values.
在有消费者订阅之前,可观察对象不会执行。`subscribe()` 会执行一次定义好的行为,并且可以再次调用它。每次订阅都是单独计算的。重新订阅会导致重新计算这些值。 在有消费者订阅之前,可观察对象不会执行。`subscribe()` 会执行一次定义好的行为,并且可以再次调用它。每次订阅都是单独计算的。重新订阅会导致重新计算这些值。
<code-example hideCopy> <code-example hideCopy>
// declare a publishing operation // declare a publishing operation
new Observable((observer) => { subscriber_fn }); new Observable((observer) => { subscriber_fn });
// initiate execution // initiate execution
observable.subscribe(() => { observable.subscribe(() => {
// observer handles notifications // observer handles notifications
}); });
</code-example> </code-example>
* Promises execute immediately, and just once. The computation of the result is initiated when the promise is created. There is no way to restart work. All `then` clauses (subscriptions) share the same computation. * Promises execute immediately, and just once. The computation of the result is initiated when the promise is created. There is no way to restart work. All `then` clauses (subscriptions) share the same computation.
承诺会立即执行,并且只执行一次。当承诺创建时,会立即计算出结果。没有办法重新做一次。所有的 `then` 语句(订阅)都会共享同一次计算。 承诺会立即执行,并且只执行一次。当承诺创建时,会立即计算出结果。没有办法重新做一次。所有的 `then` 语句(订阅)都会共享同一次计算。
<code-example hideCopy> <code-example hideCopy>
// initiate execution // initiate execution
new Promise((resolve, reject) => { executer_fn }); new Promise((resolve, reject) => { executer_fn });
// handle return value // handle return value
promise.then((value) => { promise.then((value) => {
// handle result here // handle result here
}); });
</code-example> </code-example>
### Chaining ### Chaining
@ -75,13 +71,13 @@ promise.then((value) => {
* Observables differentiate between transformation function such as a map and subscription. Only subscription activates the subscriber function to start computing the values. * Observables differentiate between transformation function such as a map and subscription. Only subscription activates the subscriber function to start computing the values.
可观察对象会区分各种转换函数,比如映射和订阅。只有订阅才会激活订阅者函数,以开始计算那些值。 可观察对象会区分各种转换函数,比如映射和订阅。只有订阅才会激活订阅者函数,以开始计算那些值。
<code-example hideCopy>observable.map((v) => 2*v);</code-example> <code-example hideCopy>observable.map((v) => 2*v);</code-example>
* Promises do not differentiate between the last `.then` clauses (equivalent to subscription) and intermediate `.then` clauses (equivalent to map). * Promises do not differentiate between the last `.then` clauses (equivalent to subscription) and intermediate `.then` clauses (equivalent to map).
承诺并不区分最后的 `.then()` 语句(等价于订阅)和中间的 `.then()` 语句(等价于映射)。 承诺并不区分最后的 `.then()` 语句(等价于订阅)和中间的 `.then()` 语句(等价于映射)。
<code-example hideCopy>promise.then((v) => 2*v);</code-example> <code-example hideCopy>promise.then((v) => 2*v);</code-example>
@ -91,18 +87,16 @@ promise.then((value) => {
* Observable subscriptions are cancellable. Unsubscribing removes the listener from receiving further values, and notifies the subscriber function to cancel work. * Observable subscriptions are cancellable. Unsubscribing removes the listener from receiving further values, and notifies the subscriber function to cancel work.
可观察对象的订阅是可取消的。取消订阅会移除监听器,使其不再接受将来的值,并通知订阅者函数取消正在进行的工作。 可观察对象的订阅是可取消的。取消订阅会移除监听器,使其不再接受将来的值,并通知订阅者函数取消正在进行的工作。
<code-example hideCopy> <code-example hideCopy>
const sub = obs.subscribe(...); const sub = obs.subscribe(...);
sub.unsubscribe(); sub.unsubscribe();
</code-example> </code-example>
* Promises are not cancellable. * Promises are not cancellable.
承诺是不可取消的。 承诺是不可取消的。
### Error handling ### Error handling
@ -110,26 +104,22 @@ sub.unsubscribe();
* Observable execution errors are delivered to the subscriber's error handler, and the subscriber automatically unsubscribes from the observable. * Observable execution errors are delivered to the subscriber's error handler, and the subscriber automatically unsubscribes from the observable.
可观察对象的错误处理是交给订阅者的错误处理器的,并且该订阅者会自动取消对这个可观察对象的订阅。 可观察对象的错误处理是交给订阅者的错误处理器的,并且该订阅者会自动取消对这个可观察对象的订阅。
<code-example hideCopy> <code-example hideCopy>
obs.subscribe(() => { obs.subscribe(() => {
throw Error('my error'); throw Error('my error');
}); });
</code-example> </code-example>
* Promises push errors to the child promises. * Promises push errors to the child promises.
承诺会把错误推给其子承诺。 承诺会把错误推给其子承诺。
<code-example hideCopy> <code-example hideCopy>
promise.then(() => { promise.then(() => {
throw Error('my error'); throw Error('my error');
}); });
</code-example> </code-example>
### Cheat sheet ### Cheat sheet
@ -141,7 +131,6 @@ The following code snippets illustrate how the same kind of operation is defined
下列代码片段揭示了同样的操作要如何分别使用可观察对象和承诺进行实现。 下列代码片段揭示了同样的操作要如何分别使用可观察对象和承诺进行实现。
<table> <table>
<tr> <tr>
<th> <th>
@ -169,7 +158,6 @@ The following code snippets illustrate how the same kind of operation is defined
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -197,7 +185,6 @@ The following code snippets illustrate how the same kind of operation is defined
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -221,7 +208,6 @@ The following code snippets illustrate how the same kind of operation is defined
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -249,7 +235,6 @@ The following code snippets illustrate how the same kind of operation is defined
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -275,7 +260,6 @@ The following code snippets illustrate how the same kind of operation is defined
</td> </td>
</tr> </tr>
</table> </table>
## Observables compared to events API ## Observables compared to events API
@ -295,9 +279,12 @@ Here are some code samples that illustrate how the same kind of operation is def
下列代码片段揭示了同样的操作要如何分别使用可观察对象和事件 API 进行实现。 下列代码片段揭示了同样的操作要如何分别使用可观察对象和事件 API 进行实现。
<table> <table>
<tr> <tr>
<th>
</th>
<th> <th>
Observable Observable
@ -315,7 +302,6 @@ Here are some code samples that illustrate how the same kind of operation is def
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -353,7 +339,6 @@ button.removeEventListener(click, handler);
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -381,7 +366,6 @@ button.removeEventListener(click, handler);
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -395,9 +379,9 @@ button.removeEventListener(click, handler);
<td> <td>
Listen for keystrokes, but provide a stream representing the value in the input. Listen for keystrokes, but provide a stream representing the value in the input.
监听按键,提供一个流来表示这些输入的值。 监听按键,提供一个流来表示这些输入的值。
<pre>fromEvent(inputEl, 'keydown').pipe( <pre>fromEvent(inputEl, 'keydown').pipe(
map(e => e.target.value) map(e => e.target.value)
);</pre> );</pre>
@ -407,7 +391,7 @@ button.removeEventListener(click, handler);
<td> <td>
Does not support configuration. Does not support configuration.
不支持配置。 不支持配置。
<pre>element.addEventListener(eventName, (event) => { <pre>element.addEventListener(eventName, (event) => {
@ -418,7 +402,6 @@ button.removeEventListener(click, handler);
</td> </td>
</tr> </tr>
</table> </table>
## Observables compared to arrays ## Observables compared to arrays
@ -431,9 +414,12 @@ An observable produces values over time. An array is created as a static set of
在下列例子中,➞ 符号表示异步传递值。 在下列例子中,➞ 符号表示异步传递值。
<table> <table>
<tr> <tr>
<th>
</th>
<th> <th>
Observable Observable
@ -451,7 +437,6 @@ An observable produces values over time. An array is created as a static set of
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -465,6 +450,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs: ➞1➞2➞3➞5➞7</pre> <pre>obs: ➞1➞2➞3➞5➞7</pre>
<pre>obsB: ➞'a'➞'b'➞'c'</pre> <pre>obsB: ➞'a'➞'b'➞'c'</pre>
</td> </td>
@ -472,12 +458,12 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr: [1, 2, 3, 5, 7]</pre> <pre>arr: [1, 2, 3, 5, 7]</pre>
<pre>arrB: ['a', 'b', 'c']</pre> <pre>arrB: ['a', 'b', 'c']</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -489,6 +475,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs.concat(obsB)</pre> <pre>obs.concat(obsB)</pre>
<pre>➞1➞2➞3➞5➞7➞'a'➞'b'➞'c'</pre> <pre>➞1➞2➞3➞5➞7➞'a'➞'b'➞'c'</pre>
</td> </td>
@ -496,12 +483,12 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr.concat(arrB)</pre> <pre>arr.concat(arrB)</pre>
<pre>[1,2,3,5,7,'a','b','c']</pre> <pre>[1,2,3,5,7,'a','b','c']</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -513,6 +500,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs.filter((v) => v>3)</pre> <pre>obs.filter((v) => v>3)</pre>
<pre>➞5➞7</pre> <pre>➞5➞7</pre>
</td> </td>
@ -520,12 +508,12 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr.filter((v) => v>3)</pre> <pre>arr.filter((v) => v>3)</pre>
<pre>[5, 7]</pre> <pre>[5, 7]</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -537,6 +525,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs.find((v) => v>3)</pre> <pre>obs.find((v) => v>3)</pre>
<pre>➞5</pre> <pre>➞5</pre>
</td> </td>
@ -544,12 +533,12 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr.find((v) => v>10)</pre> <pre>arr.find((v) => v>10)</pre>
<pre>5</pre> <pre>5</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -561,6 +550,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs.findIndex((v) => v>3)</pre> <pre>obs.findIndex((v) => v>3)</pre>
<pre>➞3</pre> <pre>➞3</pre>
</td> </td>
@ -568,12 +558,12 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr.findIndex((v) => v>3)</pre> <pre>arr.findIndex((v) => v>3)</pre>
<pre>3</pre> <pre>3</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -609,7 +599,6 @@ An observable produces values over time. An array is created as a static set of
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -621,6 +610,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs.map((v) => -v)</pre> <pre>obs.map((v) => -v)</pre>
<pre>➞-1➞-2➞-3➞-5➞-7</pre> <pre>➞-1➞-2➞-3➞-5➞-7</pre>
</td> </td>
@ -628,12 +618,12 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr.map((v) => -v)</pre> <pre>arr.map((v) => -v)</pre>
<pre>[-1, -2, -3, -5, -7]</pre> <pre>[-1, -2, -3, -5, -7]</pre>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -645,6 +635,7 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>obs.scan((s,v)=> s+v, 0)</pre> <pre>obs.scan((s,v)=> s+v, 0)</pre>
<pre>➞1➞3➞6➞11➞18</pre> <pre>➞1➞3➞6➞11➞18</pre>
</td> </td>
@ -652,10 +643,10 @@ An observable produces values over time. An array is created as a static set of
<td> <td>
<pre>arr.reduce((s,v) => s+v, 0)</pre> <pre>arr.reduce((s,v) => s+v, 0)</pre>
<pre>18</pre> <pre>18</pre>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -525,5 +525,4 @@ and verify that the history meets expectations:
[Back to top](guide/component-interaction#top) [Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top) [回到顶部](guide/component-interaction#top)

View File

@ -20,7 +20,7 @@ This page describes how to load and apply these component styles.
You can run the <live-example></live-example> in Stackblitz and download the code from there. You can run the <live-example></live-example> in Stackblitz and download the code from there.
你可以运行<live-example></live-example>在 Stackblitz 中试用并下载本页的代码。 你可以运行<live-example></live-example>在 Stackblitz 中试用并下载本页的代码。
## Using component styles ## Using component styles
@ -42,7 +42,6 @@ Usually you give it one string, as in the following example:
通常你只给它一个字符串就行了,如同下例: 通常你只给它一个字符串就行了,如同下例:
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts" linenums="false"> <code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts" linenums="false">
</code-example> </code-example>
## Style scope ## Style scope
@ -116,7 +115,6 @@ targeting elements *inside* the component's template).
使用 `:host` 伪类选择器,用来选择组件*宿主*元素中的元素(相对于组件模板*内部*的元素)。 使用 `:host` 伪类选择器,用来选择组件*宿主*元素中的元素(相对于组件模板*内部*的元素)。
<code-example path="component-styles/src/app/hero-details.component.css" region="host" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="host" title="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
The `:host` selector is the only way to target the host element. You can't reach The `:host` selector is the only way to target the host element. You can't reach
@ -136,7 +134,6 @@ The next example targets the host element again, but only when it also has the `
下一个例子再次把宿主元素作为目标,但是只有当它同时带有 `active` CSS 类的时候才会生效。 下一个例子再次把宿主元素作为目标,但是只有当它同时带有 `active` CSS 类的时候才会生效。
<code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="hostfunction" title="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
### :host-context ### :host-context
@ -163,7 +160,6 @@ if some ancestor element has the CSS class `theme-light`.
在下面的例子中,只有当某个祖先元素有 CSS 类 `theme-light` 时,才会把 `background-color` 样式应用到组件*内部*的所有 `<h2>` 元素中。 在下面的例子中,只有当某个祖先元素有 CSS 类 `theme-light` 时,才会把 `background-color` 样式应用到组件*内部*的所有 `<h2>` 元素中。
<code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" title="src/app/hero-details.component.css" linenums="false"> <code-example path="component-styles/src/app/hero-details.component.css" region="hostcontext" title="src/app/hero-details.component.css" linenums="false">
</code-example> </code-example>
### (deprecated) `/deep/`, `>>>`, and `::ng-deep` ### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
@ -257,7 +253,6 @@ Each string in the array defines some CSS for this component.
这个数组中的每一个字符串(通常也只有一个)定义一份 CSS。 这个数组中的每一个字符串(通常也只有一个)定义一份 CSS。
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts (CSS inline)"> <code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts (CSS inline)">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -275,9 +270,7 @@ The CLI defines an empty `styles` array when you create the component with the `
当使用 `--inline-styles` 标识创建组件时CLI 就会定义一个空的 `styles` 数组 当使用 `--inline-styles` 标识创建组件时CLI 就会定义一个空的 `styles` 数组
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component hero-app --inline-style ng generate component hero-app --inline-style
</code-example> </code-example>
### Style files in component metadata ### Style files in component metadata
@ -290,10 +283,8 @@ to a component's `@Component` decorator:
你可以通过把外部 CSS 文件添加到 `@Component``styleUrls` 属性中来加载外部样式。 你可以通过把外部 CSS 文件添加到 `@Component``styleUrls` 属性中来加载外部样式。
<code-tabs> <code-tabs>
<code-pane title="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane> <code-pane title="src/app/hero-app.component.ts (CSS in file)" path="component-styles/src/app/hero-app.component.1.ts"></code-pane>
<code-pane title="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane> <code-pane title="src/app/hero-app.component.css" path="component-styles/src/app/hero-app.component.css"></code-pane>
</code-tabs> </code-tabs>
<div class="alert is-critical"> <div class="alert is-critical">
@ -319,9 +310,7 @@ The CLI creates an empty styles file for you by default and references that file
CLI 会默认为你创建一个空白的样式表文件,并且在所生成组件的 `styleUrls` 中引用该文件。 CLI 会默认为你创建一个空白的样式表文件,并且在所生成组件的 `styleUrls` 中引用该文件。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component hero-app ng generate component hero-app
</code-example> </code-example>
### Template inline styles ### Template inline styles
@ -334,7 +323,6 @@ inside `<style>` tags.
你也可以在组件的 HTML 模板中嵌入 `<style>` 标签。 你也可以在组件的 HTML 模板中嵌入 `<style>` 标签。
<code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" title="src/app/hero-controls.component.ts"> <code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" title="src/app/hero-controls.component.ts">
</code-example> </code-example>
### Template link tags ### Template link tags
@ -346,7 +334,6 @@ You can also write `<link>` tags into the component's HTML template.
你也可以在组件的 HTML 模板中写 `<link>` 标签。 你也可以在组件的 HTML 模板中写 `<link>` 标签。
<code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts"> <code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -378,7 +365,6 @@ In this case, the URL is relative to the CSS file into which you're importing.
在*这种*情况下URL 是相对于你正在导入的 CSS 文件的。 在*这种*情况下URL 是相对于你正在导入的 CSS 文件的。
<code-example path="component-styles/src/app/hero-details.component.css" region="import" title="src/app/hero-details.component.css (excerpt)"> <code-example path="component-styles/src/app/hero-details.component.css" region="import" title="src/app/hero-details.component.css (excerpt)">
</code-example> </code-example>
### External and global style files ### External and global style files
@ -407,14 +393,12 @@ you can write style files in [sass](http://sass-lang.com/), [less](http://lesscs
如果使用 CLI 进行构建,那么你可以用 [sass](http://sass-lang.com/)、[less](http://lesscss.org/) 或 [stylus](http://stylus-lang.com/) 来编写样式,并使用相应的扩展名(`.scss`、`.less`、`.styl`)把它们指定到 `@Component.styleUrls` 元数据中。例子如下: 如果使用 CLI 进行构建,那么你可以用 [sass](http://sass-lang.com/)、[less](http://lesscss.org/) 或 [stylus](http://stylus-lang.com/) 来编写样式,并使用相应的扩展名(`.scss`、`.less`、`.styl`)把它们指定到 `@Component.styleUrls` 元数据中。例子如下:
<code-example> <code-example>
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
... ...
</code-example> </code-example>
The CLI build process runs the pertinent CSS preprocessor. The CLI build process runs the pertinent CSS preprocessor.
@ -486,7 +470,6 @@ To set the components encapsulation mode, use the `encapsulation` property in th
通过组件元数据中的 `encapsulation` 属性来设置组件封装模式: 通过组件元数据中的 `encapsulation` 属性来设置组件封装模式:
<code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false"> <code-example path="component-styles/src/app/quest-summary.component.ts" region="encapsulation.native" title="src/app/quest-summary.component.ts" linenums="false">
</code-example> </code-example>
`Native` view encapsulation only works on browsers that have native support `Native` view encapsulation only works on browsers that have native support
@ -516,7 +499,6 @@ attached to it:
在启用了仿真模式的 Angular 应用的 DOM 树中,每个 DOM 元素都被加上了一些额外的属性。 在启用了仿真模式的 Angular 应用的 DOM 树中,每个 DOM 元素都被加上了一些额外的属性。
<code-example format=""> <code-example format="">
&lt;hero-details _nghost-pmm-5> &lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2> &lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6> &lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
@ -549,7 +531,6 @@ by the generated component styles, which are in the `<head>` section of the DOM:
但它们会作为生成的组件样式的目标,就像 DOM 的 `<head>` 中一样: 但它们会作为生成的组件样式的目标,就像 DOM 的 `<head>` 中一样:
<code-example format=""> <code-example format="">
[_nghost-pmm-5] { [_nghost-pmm-5] {
display: block; display: block;
border: 1px solid black; border: 1px solid black;
@ -559,13 +540,11 @@ by the generated component styles, which are in the `<head>` section of the DOM:
background-color: white; background-color: white;
border: 1px solid #777; border: 1px solid #777;
} }
</code-example> </code-example>
These styles are post-processed so that each selector is augmented These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors. with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page. These extra selectors enable the scoping rules described in this page.
这些就是那些样式被处理后的结果,每个选择器都被增加了 `_nghost``_ngcontent` 属性选择器。 这些就是那些样式被处理后的结果,每个选择器都被增加了 `_nghost``_ngcontent` 属性选择器。
这些额外的选择器实现了本文所描述的这些作用域规则。 这些额外的选择器实现了本文所描述的这些作用域规则。

View File

@ -34,7 +34,6 @@ Imagine writing the following code:
要理解为什么依赖注入这么重要,不妨先考虑不使用它的一个例子。想象下列代码: 要理解为什么依赖注入这么重要,不妨先考虑不使用它的一个例子。想象下列代码:
<code-example path="dependency-injection/src/app/car/car-no-di.ts" region="car" title="src/app/car/car.ts (without DI)"> <code-example path="dependency-injection/src/app/car/car-no-di.ts" region="car" title="src/app/car/car.ts (without DI)">
</code-example> </code-example>
The `Car` class creates everything it needs inside its constructor. The `Car` class creates everything it needs inside its constructor.
@ -152,7 +151,6 @@ Now you can create a car by passing the engine and tires to the constructor.
现在,通过往构造函数中传入引擎和轮胎来创建一辆车。 现在,通过往构造函数中传入引擎和轮胎来创建一辆车。
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation" linenums="false"> <code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation" linenums="false">
</code-example> </code-example>
How cool is that? How cool is that?
@ -195,7 +193,6 @@ during each test:
在每个测试期间,你可以往构造函数中传入 mock 对象,做想让它们做的事: 在每个测试期间,你可以往构造函数中传入 mock 对象,做想让它们做的事:
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-mocks" linenums="false"> <code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-mocks" linenums="false">
</code-example> </code-example>
**You just learned what dependency injection is**. **You just learned what dependency injection is**.
@ -223,7 +220,6 @@ You _could_ write a giant class to do that:
可以写一个巨型类来做这件事: 可以写一个巨型类来做这件事:
<code-example path="dependency-injection/src/app/car/car-factory.ts" title="src/app/car/car-factory.ts"> <code-example path="dependency-injection/src/app/car/car-factory.ts" title="src/app/car/car-factory.ts">
</code-example> </code-example>
It's not so bad now with only three creation methods. It's not so bad now with only three creation methods.
@ -253,7 +249,6 @@ When you need a `Car`, you simply ask the injector to get it for you and you're
当需要一个 `Car` 时,就简单的找注入器取车就可以了。 当需要一个 `Car` 时,就简单的找注入器取车就可以了。
<code-example path="dependency-injection/src/app/car/car-injector.ts" region="injector-call" title="src/app/car/car-injector.ts" linenums="false"> <code-example path="dependency-injection/src/app/car/car-injector.ts" region="injector-call" title="src/app/car/car-injector.ts" linenums="false">
</code-example> </code-example>
Everyone wins. The `Car` knows nothing about creating an `Engine` or `Tires`. Everyone wins. The `Car` knows nothing about creating an `Engine` or `Tires`.

View File

@ -30,7 +30,6 @@ from the [The Tour of Heroes](tutorial/).
先从[《英雄指南》](tutorial/)中*英雄*特性区的一个简化版本开始。 先从[《英雄指南》](tutorial/)中*英雄*特性区的一个简化版本开始。
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts" <code-pane title="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts"
region="v1"> region="v1">
</code-pane> </code-pane>
@ -60,7 +59,6 @@ defined in a separate `mock-heroes` file.
<code-example title="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts" <code-example title="src/app/heroes/hero-list.component.ts (class)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts"
region="class"> region="class">
</code-example> </code-example>
That may suffice in the early stages of development, but it's far from ideal. That may suffice in the early stages of development, but it's far from ideal.
@ -85,9 +83,7 @@ The [**Angular CLI**](https://cli.angular.io/) can generate a new `HeroService`
[**Angular CLI**](https://cli.angular.io/) 可以使用下列命令在 `src/app/heroes` 目录下新建一个 `HeroService` 类。 [**Angular CLI**](https://cli.angular.io/) 可以使用下列命令在 `src/app/heroes` 目录下新建一个 `HeroService` 类。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate service heroes/hero ng generate service heroes/hero
</code-example> </code-example>
That command creates the following `HeroService` skeleton. That command creates the following `HeroService` skeleton.
@ -95,7 +91,6 @@ That command creates the following `HeroService` skeleton.
这条命令会创建如下的 `HeroService` 骨架代码: 这条命令会创建如下的 `HeroService` 骨架代码:
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.ts (CLI-generated)"> <code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.ts (CLI-generated)">
</code-example> </code-example>
Assume for now that the [`@Injectable` decorator](#injectable) is an essential ingredient in every Angular service definition. Assume for now that the [`@Injectable` decorator](#injectable) is an essential ingredient in every Angular service definition.
@ -106,7 +101,6 @@ that returns the same mock data as before.
把该类的其它部分改写为暴露一个返回和以前一样的 mock 数据的 `getHeroes` 方法。 把该类的其它部分改写为暴露一个返回和以前一样的 mock 数据的 `getHeroes` 方法。
<code-example path="dependency-injection/src/app/heroes/hero.service.1.ts" title="src/app/heroes/hero.service.ts"> <code-example path="dependency-injection/src/app/heroes/hero.service.1.ts" title="src/app/heroes/hero.service.ts">
</code-example> </code-example>
Of course, this isn't a real data service. Of course, this isn't a real data service.
@ -189,7 +183,6 @@ Here's a revised `HeroesComponent` that registers the `HeroService` in its `prov
下面是修改过的 `HerosComponent`,把 `HeroService` 注册到了它的 `providers` 数组中。 下面是修改过的 `HerosComponent`,把 `HeroService` 注册到了它的 `providers` 数组中。
<code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/heroes/heroes.component.1.ts" title="src/app/heroes/heroes.component.ts" linenums="false">
</code-example> </code-example>
{@a register-providers-ngmodule} {@a register-providers-ngmodule}
@ -203,7 +196,6 @@ In the following excerpt, the root `AppModule` registers two providers in its `p
在下面的代码片段中,根模块 `AppModule` 在自己的 `providers` 数组中注册了两个提供商。 在下面的代码片段中,根模块 `AppModule` 在自己的 `providers` 数组中注册了两个提供商。
<code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers"> <code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers">
</code-example> </code-example>
The first entry registers the `UserService` class (_not shown_) under the `UserService` _injection token_. The first entry registers the `UserService` class (_not shown_) under the `UserService` _injection token_.
@ -284,7 +276,7 @@ and is never destroyed so the `HeroService` created for the `HeroComponent` also
在这个范例应用中,`HeroComponent` 会在应用启动时创建,并且它从未销毁,因此,由 `HeroComponent` 创建的 `HeroService` 也同样会活在应用的整个生命周期中。 在这个范例应用中,`HeroComponent` 会在应用启动时创建,并且它从未销毁,因此,由 `HeroComponent` 创建的 `HeroService` 也同样会活在应用的整个生命周期中。
If you want to restrict `HeroService` access to the `HeroesComponent` and its nested `HeroListComponent`, If you want to restrict `HeroService` access to the `HeroComponent` and its nested `HeroListComponent`,
providing the `HeroService` in the `HeroComponent` may be a good choice. providing the `HeroService` in the `HeroComponent` may be a good choice.
如果你要把 `HeroService` 的访问权限定在 `HeroesComponent` 及其嵌套的 `HeroListComponent` 中,那么在 `HeroesComponent` 中提供这个 `HeroService` 就是一个好选择。 如果你要把 `HeroService` 的访问权限定在 `HeroesComponent` 及其嵌套的 `HeroListComponent` 中,那么在 `HeroesComponent` 中提供这个 `HeroService` 就是一个好选择。
@ -319,7 +311,6 @@ Here's the `HeroListComponent` constructor, asking for the `HeroService` to be i
<code-example title="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts" <code-example title="src/app/heroes/hero-list.component (constructor signature)" path="dependency-injection/src/app/heroes/hero-list.component.ts"
region="ctor-signature"> region="ctor-signature">
</code-example> </code-example>
Of course, the `HeroListComponent` should do something with the injected `HeroService`. Of course, the `HeroListComponent` should do something with the injected `HeroService`.
@ -329,13 +320,11 @@ Here's the revised component, making use of the injected service, side-by-side w
下面输出修改过的组件,改用注入的服务,与前一个版本对比一下。 下面输出修改过的组件,改用注入的服务,与前一个版本对比一下。
<code-tabs> <code-tabs>
<code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts"> <code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
</code-pane> </code-pane>
<code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts"> <code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
Notice that the `HeroListComponent` doesn't know where the `HeroService` comes from. Notice that the `HeroListComponent` doesn't know where the `HeroService` comes from.
@ -431,7 +420,6 @@ under test:
例如,新建的 `HeroListComponent` 实例使用一个模拟 (mock) 服务,以便可以在测试中操纵它: 例如,新建的 `HeroListComponent` 实例使用一个模拟 (mock) 服务,以便可以在测试中操纵它:
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -490,7 +478,6 @@ The sample app's `Logger` service is quite simple:
这个范例应用的 `Logger` 服务非常简单: 这个范例应用的 `Logger` 服务非常简单:
<code-example path="dependency-injection/src/app/logger.service.ts" title="src/app/logger.service.ts"> <code-example path="dependency-injection/src/app/logger.service.ts" title="src/app/logger.service.ts">
</code-example> </code-example>
If the app didn't provide this `Logger`, If the app didn't provide this `Logger`,
@ -500,9 +487,7 @@ into the `HeroService`.
如果该应用没有提供这个 `Logger` 服务,当 Angular 试图把 `Logger` 注入到 `HeroService` 中时,就会抛出一个异常。 如果该应用没有提供这个 `Logger` 服务,当 Angular 试图把 `Logger` 注入到 `HeroService` 中时,就会抛出一个异常。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ERROR Error: No provider for Logger! ERROR Error: No provider for Logger!
</code-example> </code-example>
Because a singleton logger service is useful everywhere, Because a singleton logger service is useful everywhere,
@ -511,7 +496,6 @@ it's provided in the root `AppModule`.
因为 `Logger` 服务的单例应该随处可用,所以要在根模块 `AppModule` 中提供它。 因为 `Logger` 服务的单例应该随处可用,所以要在根模块 `AppModule` 中提供它。
<code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-2"> <code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-2">
</code-example> </code-example>
{@a injectable} {@a injectable}
@ -619,7 +603,6 @@ The `Logger` class itself is an obvious and natural provider.
`Logger` 类本身是一个显而易见而且自然而然的提供商。 `Logger` 类本身是一个显而易见而且自然而然的提供商。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger">
</code-example> </code-example>
But it's not the only way. But it's not the only way.
@ -651,7 +634,6 @@ Here's the class-provider syntax again.
下面是类提供商的另一种语法。 下面是类提供商的另一种语法。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger">
</code-example> </code-example>
This is actually a shorthand expression for a provider registration This is actually a shorthand expression for a provider registration
@ -661,7 +643,6 @@ using a _provider_ object literal with two properties:
使用的是一个带有两个属性的*提供商*对象字面量: 使用的是一个带有两个属性的*提供商*对象字面量:
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-3" > <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-3" >
</code-example> </code-example>
The `provide` property holds the [token](guide/dependency-injection#token) that serves as the key for both locating a dependency value The `provide` property holds the [token](guide/dependency-injection#token) that serves as the key for both locating a dependency value
@ -691,7 +672,6 @@ to return a `BetterLogger` when something asks for the `Logger`.
下列代码告诉注入器,当有人请求 `Logger` 时,返回 `BetterLogger` 下列代码告诉注入器,当有人请求 `Logger` 时,返回 `BetterLogger`
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-4" > <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-4" >
</code-example> </code-example>
{@a class-provider-dependencies} {@a class-provider-dependencies}
@ -709,7 +689,6 @@ which is also injected at the application level.
`UserService` 通常也会在应用级注入。 `UserService` 通常也会在应用级注入。
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false">
</code-example> </code-example>
Configure it like `BetterLogger`. Configure it like `BetterLogger`.
@ -717,7 +696,6 @@ Configure it like `BetterLogger`.
就像之前在 `BetterLogger` 中那样配置它。 就像之前在 `BetterLogger` 中那样配置它。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false">
</code-example> </code-example>
{@a aliased-class-providers} {@a aliased-class-providers}
@ -753,7 +731,6 @@ Unfortunately, that's what you get if you try to alias `OldLogger` to `NewLogger
不幸的是,如果尝试通过 `useClass` 来把 `OldLogger` 作为 `NewLogger` 的别名,就会导致这样的后果。 不幸的是,如果尝试通过 `useClass` 来把 `OldLogger` 作为 `NewLogger` 的别名,就会导致这样的后果。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false">
</code-example> </code-example>
The solution: alias with the `useExisting` option. The solution: alias with the `useExisting` option.
@ -761,7 +738,6 @@ The solution: alias with the `useExisting` option.
解决方案:使用 `useExisting` 选项指定别名。 解决方案:使用 `useExisting` 选项指定别名。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false">
</code-example> </code-example>
{@a value-provider} {@a value-provider}
@ -775,7 +751,6 @@ Sometimes it's easier to provide a ready-made object rather than ask the injecto
有时,提供一个预先做好的对象会比请求注入器从类中创建它更容易。 有时,提供一个预先做好的对象会比请求注入器从类中创建它更容易。
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger" linenums="false">
</code-example> </code-example>
Then you register a provider with the `useValue` option, Then you register a provider with the `useValue` option,
@ -784,7 +759,6 @@ which makes this object play the logger role.
于是可以通过 `useValue` 选项来注册提供商,它会让这个对象直接扮演 logger 的角色。 于是可以通过 `useValue` 选项来注册提供商,它会让这个对象直接扮演 logger 的角色。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false">
</code-example> </code-example>
See more `useValue` examples in the See more `useValue` examples in the
@ -843,7 +817,6 @@ Instead, the `HeroService` constructor takes a boolean flag to control display o
`HeroService` 的构造函数带上一个布尔型的标志,来控制是否显示隐藏的英雄。 `HeroService` 的构造函数带上一个布尔型的标志,来控制是否显示隐藏的英雄。
<code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" title="src/app/heroes/hero.service.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/heroes/hero.service.ts" region="internals" title="src/app/heroes/hero.service.ts (excerpt)" linenums="false">
</code-example> </code-example>
You can inject the `Logger`, but you can't inject the boolean `isAuthorized`. You can inject the `Logger`, but you can't inject the boolean `isAuthorized`.
@ -857,7 +830,6 @@ A factory provider needs a factory function:
工厂提供商需要一个工厂方法: 工厂提供商需要一个工厂方法:
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="factory" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
</code-example> </code-example>
Although the `HeroService` has no access to the `UserService`, the factory function does. Although the `HeroService` has no access to the `UserService`, the factory function does.
@ -870,7 +842,6 @@ and let the injector pass them along to the factory function:
同时把 `Logger``UserService` 注入到工厂提供商中,并且让注入器把它们传给工厂方法: 同时把 `Logger``UserService` 注入到工厂提供商中,并且让注入器把它们传给工厂方法:
<code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/heroes/hero.service.provider.ts" region="provider" title="src/app/heroes/hero.service.provider.ts (excerpt)" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -938,7 +909,6 @@ Here you get a `HeroService` directly from the injector by supplying the `HeroSe
在下面的代码中,`HeroService` 类型作为令牌,直接从注入器中获取 `HeroService` 实例: 在下面的代码中,`HeroService` 类型作为令牌,直接从注入器中获取 `HeroService` 实例:
<code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" title="src/app/injector.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/injector.component.ts" region="get-hero-service" title="src/app/injector.component.ts" linenums="false">
</code-example> </code-example>
You have similar good fortune when you write a constructor that requires an injected class-based dependency. You have similar good fortune when you write a constructor that requires an injected class-based dependency.
@ -951,7 +921,6 @@ service associated with that `HeroService` class token:
Angular 就会知道把跟 `HeroService` 类令牌关联的服务注入进来: Angular 就会知道把跟 `HeroService` 类令牌关联的服务注入进来:
<code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" title="src/app/heroes/hero-list.component.ts"> <code-example path="dependency-injection/src/app/heroes/hero-list.component.ts" region="ctor-signature" title="src/app/heroes/hero-list.component.ts">
</code-example> </code-example>
This is especially convenient when you consider that most dependency values are provided by classes. This is especially convenient when you consider that most dependency values are provided by classes.
@ -978,7 +947,6 @@ They can be object literals such as this one:
但是这些配置对象不总是类的实例,它们可能是对象,如下面这个: 但是这些配置对象不总是类的实例,它们可能是对象,如下面这个:
<code-example path="dependency-injection/src/app/app.config.ts" region="config" title="src/app/app.config.ts (excerpt)" linenums="false"> <code-example path="dependency-injection/src/app/app.config.ts" region="config" title="src/app/app.config.ts (excerpt)" linenums="false">
</code-example> </code-example>
What if you'd like to make this configuration object available for injection? What if you'd like to make this configuration object available for injection?
@ -1005,11 +973,9 @@ Unfortunately, you cannot use a TypeScript interface as a token:
`HERO_DI_CONFIG` 常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌: `HERO_DI_CONFIG` 常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
</code-example> </code-example>
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false">
</code-example> </code-example>
That seems strange if you're used to dependency injection in strongly typed languages, where That seems strange if you're used to dependency injection in strongly typed languages, where
@ -1042,7 +1008,6 @@ The definition of such a token looks like this:
定义方式是这样的: 定义方式是这样的:
<code-example path="dependency-injection/src/app/app.config.ts" region="token" title="src/app/app.config.ts" linenums="false"> <code-example path="dependency-injection/src/app/app.config.ts" region="token" title="src/app/app.config.ts" linenums="false">
</code-example> </code-example>
The type parameter, while optional, conveys the dependency's type to developers and tooling. The type parameter, while optional, conveys the dependency's type to developers and tooling.
@ -1056,7 +1021,6 @@ Register the dependency provider using the `InjectionToken` object:
使用这个 `InjectionToken` 对象注册依赖的提供商: 使用这个 `InjectionToken` 对象注册依赖的提供商:
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
</code-example> </code-example>
Now you can inject the configuration object into any constructor that needs it, with Now you can inject the configuration object into any constructor that needs it, with
@ -1065,7 +1029,6 @@ the help of an `@Inject` decorator:
现在,在 `@Inject` 装饰器的帮助下,这个配置对象可以注入到任何需要它的构造函数中: 现在,在 `@Inject` 装饰器的帮助下,这个配置对象可以注入到任何需要它的构造函数中:
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false"> <code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1098,11 +1061,9 @@ constructor argument with `@Optional()`:
可以把构造函数的参数标记为 `@Optional()`,告诉 Angular 该依赖是可选的: 可以把构造函数的参数标记为 `@Optional()`,告诉 Angular 该依赖是可选的:
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional"> <code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
</code-example> </code-example>
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false"> <code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false">
</code-example> </code-example>
When using `@Optional()`, your code must be prepared for a null value. If you When using `@Optional()`, your code must be prepared for a null value. If you
@ -1145,7 +1106,6 @@ here's an `InjectorComponent` that does.
但开发者很少直接使用它。 但开发者很少直接使用它。
<code-example path="dependency-injection/src/app/injector.component.ts" region="injector" title="src/app/injector.component.ts"> <code-example path="dependency-injection/src/app/injector.component.ts" region="injector" title="src/app/injector.component.ts">
</code-example> </code-example>
An `Injector` is itself an injectable service. An `Injector` is itself an injectable service.

View File

@ -23,9 +23,7 @@ For the simplest deployment, build for development and copy the output directory
使用开发环境进行构建 使用开发环境进行构建
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build ng build
</code-example> </code-example>
2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server. 2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server.
@ -42,9 +40,7 @@ For the simplest deployment, build for development and copy the output directory
比如,如果 `index.html` 位于服务器上的 `/my/app/index.html` 路径下,就要把 *base href* 设置为 `<base href="/my/app/">`,就像这样: 比如,如果 `index.html` 位于服务器上的 `/my/app/index.html` 路径下,就要把 *base href* 设置为 `<base href="/my/app/">`,就像这样:
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build --base-href=/my/app/ ng build --base-href=/my/app/
</code-example> </code-example>
You'll see that the `<base href>` is set properly in the generated `dist/index.html`.<br><br> You'll see that the `<base href>` is set properly in the generated `dist/index.html`.<br><br>
@ -84,9 +80,7 @@ starting with `--prod`.
### 使用 `--prod` 构建。 ### 使用 `--prod` 构建。
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build --prod ng build --prod
</code-example> </code-example>
The `--prod` _meta-flag_ engages the following optimization features. The `--prod` _meta-flag_ engages the following optimization features.
@ -126,9 +120,7 @@ You may further reduce bundle sizes by adding the `build-optimizer` flag.
你还可以添加 `build-optimizer` 标志来进一步缩减打包体积。 你还可以添加 `build-optimizer` 标志来进一步缩减打包体积。
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build --prod --build-optimizer ng build --prod --build-optimizer
</code-example> </code-example>
See the [CLI Documentation](https://github.com/angular/angular-cli/wiki/build) See the [CLI Documentation](https://github.com/angular/angular-cli/wiki/build)
@ -148,9 +140,7 @@ console:
Angular 应用默认运行在开发模式下,正如在浏览器控制台中看到的如下信息: Angular 应用默认运行在开发模式下,正如在浏览器控制台中看到的如下信息:
<code-example format="nocode"> <code-example format="nocode">
Angular is running in the development mode. Call enableProdMode() to enable the production mode. Angular is running in the development mode. Call enableProdMode() to enable the production mode.
</code-example> </code-example>
Switching to _production mode_ can make it run faster by disabling development specific checks such as the dual change detection cycles. Switching to _production mode_ can make it run faster by disabling development specific checks such as the dual change detection cycles.
@ -257,9 +247,7 @@ Install `source-map-explorer`:
安装 `source-map-explorer` 安装 `source-map-explorer`
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
npm install source-map-explorer --save-dev npm install source-map-explorer --save-dev
</code-example> </code-example>
Build your app for production _including the source maps_ Build your app for production _including the source maps_
@ -267,9 +255,7 @@ Build your app for production _including the source maps_
构建*带源码映射*的生产版本 构建*带源码映射*的生产版本
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ng build --prod --sourcemaps ng build --prod --sourcemaps
</code-example> </code-example>
List the generated bundles in the `dist/` folder. List the generated bundles in the `dist/` folder.
@ -277,9 +263,7 @@ List the generated bundles in the `dist/` folder.
列出 `dist/` 文件夹中生成的文件包。 列出 `dist/` 文件夹中生成的文件包。
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
ls dist/*.bundle.js ls dist/*.bundle.js
</code-example> </code-example>
Run the explorer to generate a graphical representation of one of the bundles. Run the explorer to generate a graphical representation of one of the bundles.
@ -289,9 +273,7 @@ The following example displays the graph for the _main_ bundle.
下面的例子中就是 `main` 这个文件包的图形。 下面的例子中就是 `main` 这个文件包的图形。
<code-example language="none" class="code-shell"> <code-example language="none" class="code-shell">
node_modules/.bin/source-map-explorer dist/main.*.bundle.js node_modules/.bin/source-map-explorer dist/main.*.bundle.js
</code-example> </code-example>
The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies, The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
@ -488,12 +470,10 @@ The list is by no means exhaustive, but should provide you with a good starting
[Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server)在开发服务器的配置中设置了 `historyApiFallback`,代码如下: [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server)在开发服务器的配置中设置了 `historyApiFallback`,代码如下:
<code-example> <code-example>
historyApiFallback: { historyApiFallback: {
disableDotRule: true, disableDotRule: true,
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
} }
</code-example> </code-example>
#### Production servers #### Production servers
@ -508,7 +488,6 @@ The list is by no means exhaustive, but should provide you with a good starting
代码如下([出处](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/) 代码如下([出处](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/)
<code-example format="."> <code-example format=".">
RewriteEngine On RewriteEngine On
&#35 If an existing asset or directory is requested go to it as it is &#35 If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR] RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
@ -517,7 +496,6 @@ The list is by no means exhaustive, but should provide you with a good starting
&#35 If the requested resource doesn't exist, use index.html &#35 If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html RewriteRule ^ /index.html
</code-example> </code-example>
* [NGinx](http://nginx.org/): use `try_files`, as described in * [NGinx](http://nginx.org/): use `try_files`, as described in
@ -527,9 +505,7 @@ modified to serve `index.html`:
[NGinx](http://nginx.org/):使用 `try_files` 指向 `index.html`,详细描述见[Web 应用的前端控制器模式](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps)。 [NGinx](http://nginx.org/):使用 `try_files` 指向 `index.html`,详细描述见[Web 应用的前端控制器模式](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps)。
<code-example format="."> <code-example format=".">
try_files $uri $uri/ /index.html; try_files $uri $uri/ /index.html;
</code-example> </code-example>
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown * [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
@ -538,7 +514,6 @@ modified to serve `index.html`:
[IIS](https://www.iis.net/):往 `web.config` 中添加一条重写规则,类似于[这里](http://stackoverflow.com/a/26152011/2116927) [IIS](https://www.iis.net/):往 `web.config` 中添加一条重写规则,类似于[这里](http://stackoverflow.com/a/26152011/2116927)
<code-example format='.'> <code-example format='.'>
&lt;system.webServer&gt; &lt;system.webServer&gt;
&lt;rewrite&gt; &lt;rewrite&gt;
&lt;rules&gt; &lt;rules&gt;
@ -577,7 +552,6 @@ and to
[Firebase 主机服务](https://firebase.google.com/docs/hosting/):添加一条[重写规则](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites)。 [Firebase 主机服务](https://firebase.google.com/docs/hosting/):添加一条[重写规则](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites)。
<code-example format="."> <code-example format=".">
"rewrites": [ { "rewrites": [ {
"source": "**", "source": "**",
"destination": "/index.html" "destination": "/index.html"
@ -605,7 +579,6 @@ The server must be configured to accept the application's requests.
Read about how to enable CORS for specific servers at Read about how to enable CORS for specific servers at
<a href="http://enable-cors.org/server.html" title="Enabling CORS server">enable-cors.org</a>. <a href="http://enable-cors.org/server.html" title="Enabling CORS server">enable-cors.org</a>.
客户端应用对这种错误无能为力。 客户端应用对这种错误无能为力。
服务器必须配置成可以接受来自该应用的请求。 服务器必须配置成可以接受来自该应用的请求。
要了解如何对特定的服务器开启 CORS参见<a href="http://enable-cors.org/server.html" target="_blank" title="Enabling CORS server">enable-cors.org</a> 要了解如何对特定的服务器开启 CORS参见<a href="http://enable-cors.org/server.html" target="_blank" title="Enabling CORS server">enable-cors.org</a>

View File

@ -173,9 +173,7 @@ In either style, the template data bindings have the same access to the componen
默认情况下Angular CLI 生成组件时会带有模板文件,你可以通过参数覆盖它: 默认情况下Angular CLI 生成组件时会带有模板文件,你可以通过参数覆盖它:
<code-example hideCopy language="sh" class="code-shell"> <code-example hideCopy language="sh" class="code-shell">
ng generate component hero -it ng generate component hero -it
</code-example> </code-example>
</div> </div>
@ -295,9 +293,7 @@ of hero names into an array of `Hero` objects. For that you'll need a `Hero` cla
要将此绑定转换成使用对象,需要把这个英雄名字数组变成 `Hero` 对象数组。但首先得有一个 `Hero` 类。 要将此绑定转换成使用对象,需要把这个英雄名字数组变成 `Hero` 对象数组。但首先得有一个 `Hero` 类。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate class hero ng generate class hero
</code-example> </code-example>
With the following code: With the following code:

View File

@ -305,17 +305,13 @@ But there are times when an inline snippet is the better choice.
For terminal input and output, put the content between `<code-example>` tags, set the CSS class to `code-shell`, and set the language attribute to `sh` as in this example. For terminal input and output, put the content between `<code-example>` tags, set the CSS class to `code-shell`, and set the language attribute to `sh` as in this example.
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm start npm start
</code-example> </code-example>
```html ```html
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm start npm start
</code-example> </code-example>
``` ```
@ -365,7 +361,6 @@ Here's the brief markup that produced that lengthy snippet:
<code-example <code-example
path="docs-style-guide/src/app/app.module.ts" path="docs-style-guide/src/app/app.module.ts"
title="src/app/app.module.ts"> title="src/app/app.module.ts">
</code-example> </code-example>
``` ```
@ -398,7 +393,6 @@ The preferred way to un-ignore a file is to update the `content/examples/.gitign
!my-guide/src/something.js !my-guide/src/something.js
!my-guide/more-javascript*.js !my-guide/more-javascript*.js
</code-example> </code-example>
</div> </div>
@ -430,7 +424,6 @@ Often you want to focus on a fragment of code within a sample code file. In this
<code-example <code-example
path="docs-style-guide/src/app/app.module.ts" path="docs-style-guide/src/app/app.module.ts"
region="class"> region="class">
</code-example> </code-example>
First you surround that fragment in the source file with a named _docregion_ as described [below](#source-code-markup). First you surround that fragment in the source file with a named _docregion_ as described [below](#source-code-markup).
@ -441,7 +434,6 @@ Then you reference that _docregion_ in the `region` attribute of the `<code-exam
<code-example <code-example
path="docs-style-guide/src/app/app.module.ts" path="docs-style-guide/src/app/app.module.ts"
region="class"> region="class">
</code-example> </code-example>
``` ```
@ -472,13 +464,11 @@ Here's the markup for an "avoid" example in the
path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts"
region="example" region="example"
title="app/heroes/hero-button/hero-button.component.ts"> title="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
``` ```
<code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/hero-button/hero-button.component.ts"> <code-example path="styleguide/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts" region="example" title="app/heroes/hero-button/hero-button.component.ts">
</code-example> </code-example>
{@a code-tabs} {@a code-tabs}
@ -503,7 +493,6 @@ The next example displays multiple code tabs, each with its own title.
It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels. It demonstrates control over display of line numbers at both the `<code-tabs>` and `<code-pane>` levels.
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.component.html" title="app.component.html"
path="docs-style-guide/src/app/app.component.html"> path="docs-style-guide/src/app/app.component.html">
@ -522,7 +511,6 @@ It demonstrates control over display of line numbers at both the `<code-tabs>` a
title="package.json (scripts)" title="package.json (scripts)"
path="docs-style-guide/package.1.json"> path="docs-style-guide/package.1.json">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
Here's the markup for that example. Here's the markup for that example.
@ -533,7 +521,6 @@ The `linenums` attribute in the second pane restores line numbering for _itself
```html ```html
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.component.html" title="app.component.html"
path="docs-style-guide/src/app/app.component.html"> path="docs-style-guide/src/app/app.component.html">
@ -552,7 +539,6 @@ The `linenums` attribute in the second pane restores line numbering for _itself
title="package.json (scripts)" title="package.json (scripts)"
path="docs-style-guide/package.1.json"> path="docs-style-guide/package.1.json">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
``` ```
@ -685,7 +671,6 @@ Examine the `src/app/app.component.ts` file which defines two nested _#docregion
The inner, `class-skeleton` region appears twice, once to capture the code that opens the class definition and once to capture the code that closes the class definition. The inner, `class-skeleton` region appears twice, once to capture the code that opens the class definition and once to capture the code that closes the class definition.
<code-example linenums="false"> <code-example linenums="false">
// #docplaster // #docplaster
... ...
// #docregion class, class-skeleton // #docregion class, class-skeleton
@ -701,13 +686,11 @@ export class AppComponent {
// #docregion class-skeleton // #docregion class-skeleton
} }
// #enddocregion class, class-skeleton // #enddocregion class, class-skeleton
</code-example> </code-example>
Here's are the two corresponding code snippets displayed side-by-side. Here's are the two corresponding code snippets displayed side-by-side.
<code-tabs> <code-tabs>
<code-pane <code-pane
title="app.component.ts (class)" title="app.component.ts (class)"
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
@ -718,7 +701,6 @@ Here's are the two corresponding code snippets displayed side-by-side.
path="docs-style-guide/src/app/app.component.ts" path="docs-style-guide/src/app/app.component.ts"
region="class-skeleton"> region="class-skeleton">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
Some observations: Some observations:
@ -953,7 +935,6 @@ For these reasons, it is often wise to add a custom anchor explicitly, just abov
text to which it applies, using the special `{@a name}` syntax like this. text to which it applies, using the special `{@a name}` syntax like this.
<code-example language="html"> <code-example language="html">
&#123;@a ugly-anchors&#125; &#123;@a ugly-anchors&#125;
#### Ugly, long section header anchors #### Ugly, long section header anchors
@ -1244,7 +1225,6 @@ Use HTML tables to present tabular data.
</style> </style>
<table> <table>
<tr> <tr>
<th> <th>
@ -1266,7 +1246,6 @@ Use HTML tables to present tabular data.
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1290,7 +1269,6 @@ Use HTML tables to present tabular data.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1316,7 +1294,6 @@ Use HTML tables to present tabular data.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1340,7 +1317,6 @@ Use HTML tables to present tabular data.
</td> </td>
</tr> </tr>
</table> </table>
Here is the markup for this table. Here is the markup for this table.
@ -1352,7 +1328,6 @@ Here is the markup for this table.
</style> </style>
<table> <table>
<tr> <tr>
<th> <th>
@ -1374,7 +1349,6 @@ Here is the markup for this table.
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1398,7 +1372,6 @@ Here is the markup for this table.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1424,7 +1397,6 @@ Here is the markup for this table.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1448,7 +1420,6 @@ Here is the markup for this table.
</td> </td>
</tr> </tr>
</table> </table>
``` ```

View File

@ -266,5 +266,4 @@ The final form looks like this:
[Back to top](guide/dynamic-form#top) [Back to top](guide/dynamic-form#top)
[回到顶部](guide/dynamic-form#top) [回到顶部](guide/dynamic-form#top)

View File

@ -12,7 +12,7 @@ A basic understanding of the following concepts:
* [Bootstrapping](guide/bootstrapping). * [Bootstrapping](guide/bootstrapping).
[引导](guide/bootstrapping)。 [引导启动](guide/bootstrapping)。
<hr /> <hr />
@ -35,11 +35,11 @@ There are two main kinds of entry components:
* The bootstrapped root component. * The bootstrapped root component.
引导用的根组件。 引导用的根组件。
* A component you specify in a route definition. * A component you specify in a route definition.
在路由定义中指定的组件。 在路由定义中指定的组件。
## A bootstrapped entry component ## A bootstrapped entry component
@ -172,16 +172,16 @@ You may also be interested in the following:
* [Types of NgModules](guide/module-types) * [Types of NgModules](guide/module-types)
[Angular 模块的分类](guide/module-types) [NgModule 的分类](guide/module-types).
* [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules). * [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules).
[使用 Angular 路由器实现惰性加载模块](guide/lazy-loading-ngmodules). [使用 Angular 路由器惰性加载模块](guide/lazy-loading-ngmodules)
* [Providers](guide/providers). * [Providers](guide/providers).
[服务提供商](guide/providers). [服务提供商](guide/providers)
* [NgModules FAQ](guide/ngmodule-faq). * [NgModules FAQ](guide/ngmodule-faq).
[NgModule 常见问题](guide/ngmodule-faq). [NgModule 常见问题](guide/ngmodule-faq).

View File

@ -16,15 +16,15 @@ A basic understanding of the following:
* [Bootstrapping](guide/bootstrapping). * [Bootstrapping](guide/bootstrapping).
[引导](guide/bootstrapping)。 [引导启动](guide/bootstrapping)。
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule). * [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
[JavaScript 模块与 NgModules](guide/ngmodule-vs-jsmodule)。 [JavaScript 模块与 NgModules](guide/ngmodule-vs-jsmodule)。
* [Frequently Used Modules](guide/frequent-ngmodules). * [Frequently Used Modules](guide/frequent-ngmodules).
[常用模块](guide/frequent-ngmodules). [常用模块](guide/frequent-ngmodules)
For the final sample app with a feature module that this page describes, For the final sample app with a feature module that this page describes,
see the <live-example></live-example>. see the <live-example></live-example>.
@ -118,7 +118,6 @@ This generates a folder for the new component within the customer-dashboard fold
这会在 `customer-dashboard` 中为新组件生成一个目录,并使用 `CustomerDashboardComponent` 的信息修改这个特性模块: 这会在 `customer-dashboard` 中为新组件生成一个目录,并使用 `CustomerDashboardComponent` 的信息修改这个特性模块:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="customer-dashboard-component" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
</code-example> </code-example>
The `CustomerDashboardComponent` is now in the JavaScript import list at the top and added to the `declarations` array, which lets Angular know to associate this new component with this feature module. The `CustomerDashboardComponent` is now in the JavaScript import list at the top and added to the `declarations` array, which lets Angular know to associate this new component with this feature module.
@ -134,7 +133,6 @@ To incorporate the feature module into your app, you have to let the root module
要想把这个特性模块包含进应用中,你还得让根模块 `app.module.ts` 知道它。注意,在 `customer-dashboard.module.ts` 的底部导出了 `CustomerDashboardModule`。这样就把它暴露出来,以便其它模块可以拿到它。要想把它导入到 `AppModule` 中,就把它加入 `app.module.ts` 的导入表中,并将其加入 `imports` 数组: 要想把这个特性模块包含进应用中,你还得让根模块 `app.module.ts` 知道它。注意,在 `customer-dashboard.module.ts` 的底部导出了 `CustomerDashboardModule`。这样就把它暴露出来,以便其它模块可以拿到它。要想把它导入到 `AppModule` 中,就把它加入 `app.module.ts` 的导入表中,并将其加入 `imports` 数组:
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" title="src/app/app.module.ts" linenums="false"> <code-example path="feature-modules/src/app/app.module.ts" region="app-module" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules dont expose their components. Now the `AppModule` knows about the feature module. If you were to add any service providers to the feature module, `AppModule` would know about those too, as would any other feature modules. However, NgModules dont expose their components.
@ -150,7 +148,6 @@ When the CLI generated the `CustomerDashboardComponent` for the feature module,
当 CLI 为这个特性模块生成 `CustomerDashboardComponent` 时,还包含一个模板 `customer-dashboard.component.html`,它带有如下页面脚本: 当 CLI 为这个特性模块生成 `CustomerDashboardComponent` 时,还包含一个模板 `customer-dashboard.component.html`,它带有如下页面脚本:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" title="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" region="feature-template" title="src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.html" linenums="false">
</code-example> </code-example>
To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`: To see this HTML in the `AppComponent`, you first have to export the `CustomerDashboardComponent` in the `CustomerDashboardModule`. In `customer-dashboard.module.ts`, just beneath the `declarations` array, add an `exports` array containing `CustomerDashboardModule`:
@ -159,7 +156,6 @@ To see this HTML in the `AppComponent`, you first have to export the `CustomerDa
`customer-dashboard.module.ts` 中,`declarations` 数组的紧下方,加入一个包含 `CustomerDashboardModule``exports` 数组: `customer-dashboard.module.ts` 中,`declarations` 数组的紧下方,加入一个包含 `CustomerDashboardModule``exports` 数组:
<code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false"> <code-example path="feature-modules/src/app/customer-dashboard/customer-dashboard.module.ts" region="component-exports" title="src/app/customer-dashboard/customer-dashboard.module.ts" linenums="false">
</code-example> </code-example>
Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`: Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-dashboard>`:
@ -167,7 +163,6 @@ Next, in the `AppComponent`, `app.component.html`, add the tag `<app-customer-da
然后,在 `AppComponent``app.component.html` 中,加入标签 `<app-customer-dashboard>` 然后,在 `AppComponent``app.component.html` 中,加入标签 `<app-customer-dashboard>`
<code-example path="feature-modules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false"> <code-example path="feature-modules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too: Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too:
@ -190,12 +185,12 @@ You may also be interested in the following:
* [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules). * [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules).
[使用 Angular 路由器实现惰性加载模块](guide/lazy-loading-ngmodules). [使用 Angular 路由器惰性加载模块](guide/lazy-loading-ngmodules)
* [Providers](guide/providers). * [Providers](guide/providers).
[服务提供商](guide/providers). [服务提供商](guide/providers)
* [Types of Feature Modules](guide/module-types). * [Types of Feature Modules](guide/module-types).
[Angular 模块的分类](guide/module-types) [特性模块的分类](guide/module-types)。

View File

@ -140,7 +140,6 @@ built-in validators&mdash;this time, in function form. See below:
{@a reactive-component-class} {@a reactive-component-class}
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="form-group" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="form-group" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
</code-example> </code-example>
Note that: Note that:
@ -169,7 +168,6 @@ If you look at the template for the name input again, it is fairly similar to th
如果你到模板中找到 name 输入框,就会发现它和模板驱动的例子很相似。 如果你到模板中找到 name 输入框,就会发现它和模板驱动的例子很相似。
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" title="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.html" region="name-with-error-msg" title="reactive/hero-form-reactive.component.html (name with error msg)" linenums="false">
</code-example> </code-example>
Key takeaways: Key takeaways:
@ -201,7 +199,6 @@ this guide. Here's what the definition of that function looks like:
考虑前面的[例子](guide/form-validation#reactive-component-class)中的 `forbiddenNameValidator` 函数。该函数的定义看起来是这样的: 考虑前面的[例子](guide/form-validation#reactive-component-class)中的 `forbiddenNameValidator` 函数。该函数的定义看起来是这样的:
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" title="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="custom-validator" title="shared/forbidden-name.directive.ts (forbiddenNameValidator)" linenums="false">
</code-example> </code-example>
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function. The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
@ -241,7 +238,6 @@ to the `FormControl`.
在响应式表单组件中,添加自定义验证器相当简单。你所要做的一切就是直接把这个函数传给 `FormControl` 在响应式表单组件中,添加自定义验证器相当简单。你所要做的一切就是直接把这个函数传给 `FormControl`
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="custom-validator" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false"> <code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="custom-validator" title="reactive/hero-form-reactive.component.ts (validator functions)" linenums="false">
</code-example> </code-example>
### Adding to template-driven forms ### Adding to template-driven forms
@ -263,7 +259,6 @@ with the `NG_VALIDATORS` provider, a provider with an extensible collection of v
Angular 在验证流程中的识别出指令的作用,是因为指令把自己注册到了 `NG_VALIDATORS` 提供商中,该提供商拥有一组可扩展的验证器。 Angular 在验证流程中的识别出指令的作用,是因为指令把自己注册到了 `NG_VALIDATORS` 提供商中,该提供商拥有一组可扩展的验证器。
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" title="shared/forbidden-name.directive.ts (providers)" linenums="false"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive-providers" title="shared/forbidden-name.directive.ts (providers)" linenums="false">
</code-example> </code-example>
The directive class then implements the `Validator` interface, so that it can easily integrate The directive class then implements the `Validator` interface, so that it can easily integrate
@ -273,7 +268,6 @@ comes together:
然后该指令类实现了 `Validator` 接口,以便它能简单的与 Angular 表单集成在一起。这个指令的其余部分有助于你理解它们是如何协作的: 然后该指令类实现了 `Validator` 接口,以便它能简单的与 Angular 表单集成在一起。这个指令的其余部分有助于你理解它们是如何协作的:
<code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" title="shared/forbidden-name.directive.ts (directive)"> <code-example path="form-validation/src/app/shared/forbidden-name.directive.ts" region="directive" title="shared/forbidden-name.directive.ts (directive)">
</code-example> </code-example>
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example: Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
@ -330,5 +324,4 @@ set the color of each form control's border.
**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.** **You can run the <live-example></live-example> to see the complete reactive and template-driven example code.**
**你可以运行<live-example></live-example>来查看完整的响应式和模板驱动表单的代码。** **你可以运行<live-example></live-example>来查看完整的响应式和模板驱动表单的代码。**

View File

@ -49,7 +49,7 @@ This page shows you how to build a simple form from scratch. Along the way you'l
You can run the <live-example></live-example> in Stackblitz and download the code from there. You can run the <live-example></live-example> in Stackblitz and download the code from there.
运行<live-example></live-example>来试用本页的代码。 你可以运行<live-example></live-example>,在 Stackblitz 中试用并下载本页的代码。
{@a template-driven} {@a template-driven}

View File

@ -8,7 +8,7 @@
A basic understanding of [Bootstrapping](guide/bootstrapping). A basic understanding of [Bootstrapping](guide/bootstrapping).
对[引导](guide/bootstrapping)有基本的解。 对[引导](guide/bootstrapping)有基本的解。
<hr> <hr>
@ -287,4 +287,4 @@ You may also be interested in the following:
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule). * [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
[JavaScript 模块与 NgModules](guide/ngmodule-vs-jsmodule). [JavaScript 模块与 NgModules](guide/ngmodule-vs-jsmodule)

View File

@ -83,7 +83,6 @@ For example, imagine three ES2015 modules in a `heroes` folder:
例如,设想在 `heroes` 目录下有三个 ES2015 模块: 例如,设想在 `heroes` 目录下有三个 ES2015 模块:
<code-example> <code-example>
// heroes/hero.component.ts // heroes/hero.component.ts
export class HeroComponent {} export class HeroComponent {}
@ -92,7 +91,6 @@ For example, imagine three ES2015 modules in a `heroes` folder:
// heroes/hero.service.ts // heroes/hero.service.ts
export class HeroService {} export class HeroService {}
</code-example> </code-example>
Without a barrel, a consumer needs three import statements: Without a barrel, a consumer needs three import statements:
@ -100,11 +98,9 @@ Without a barrel, a consumer needs three import statements:
如果没有封装桶,消费者需要三条导入语句: 如果没有封装桶,消费者需要三条导入语句:
<code-example> <code-example>
import { HeroComponent } from '../heroes/hero.component.ts'; import { HeroComponent } from '../heroes/hero.component.ts';
import { Hero } from '../heroes/hero.model.ts'; import { Hero } from '../heroes/hero.model.ts';
import { HeroService } from '../heroes/hero.service.ts'; import { HeroService } from '../heroes/hero.service.ts';
</code-example> </code-example>
You can add a barrel to the `heroes` folder (called `index`, by convention) that exports all of these items: You can add a barrel to the `heroes` folder (called `index`, by convention) that exports all of these items:
@ -112,11 +108,9 @@ You can add a barrel to the `heroes` folder (called `index`, by convention) that
`heroes` 目录下添加一个封装桶(按约定叫做 `index`),它导出所有这三项: `heroes` 目录下添加一个封装桶(按约定叫做 `index`),它导出所有这三项:
<code-example> <code-example>
export * from './hero.model.ts'; // re-export all of its exports export * from './hero.model.ts'; // re-export all of its exports
export * from './hero.service.ts'; // re-export all of its exports export * from './hero.service.ts'; // re-export all of its exports
export { HeroComponent } from './hero.component.ts'; // re-export the named thing export { HeroComponent } from './hero.component.ts'; // re-export the named thing
</code-example> </code-example>
Now a consumer can import what it needs from the barrel. Now a consumer can import what it needs from the barrel.
@ -124,9 +118,7 @@ Now a consumer can import what it needs from the barrel.
现在,消费者就就可以从这个封装桶中导入它需要的东西了。 现在,消费者就就可以从这个封装桶中导入它需要的东西了。
<code-example> <code-example>
import { Hero, HeroService } from '../heroes'; // index is implied import { Hero, HeroService } from '../heroes'; // index is implied
</code-example> </code-example>
The Angular [scoped packages](guide/glossary#scoped-package) each have a barrel named `index`. The Angular [scoped packages](guide/glossary#scoped-package) each have a barrel named `index`.
@ -615,7 +607,6 @@ or displayed between element tags, as in this example.
在被赋值给元素属性或者显示在元素标签中之前,这些文本可能会先与周边的文本合并,参见下面的例子。 在被赋值给元素属性或者显示在元素标签中之前,这些文本可能会先与周边的文本合并,参见下面的例子。
<code-example language="html" escape="html"> <code-example language="html" escape="html">
<label>My current hero is {{hero.name}}</label> <label>My current hero is {{hero.name}}</label>
</code-example> </code-example>
@ -870,7 +861,6 @@ Angular 管道是一个函数,用于把输入值转换成输出值以供[视
下面这个例子中,用内置的 `currency` 管道把数字值显示为本地货币格式。 下面这个例子中,用内置的 `currency` 管道把数字值显示为本地货币格式。
<code-example language="html" escape="html"> <code-example language="html" escape="html">
<label>Price: </label>{{product.price | currency}} <label>Price: </label>{{product.price | currency}}
</code-example> </code-example>
@ -1251,5 +1241,4 @@ Angular 会在一个 Zone 区域中运行应用程序,在这个区域中,它
Learn more about zones in this Learn more about zones in this
[Brian Ford video](https://www.youtube.com/watch?v=3IqtmUscE_U). [Brian Ford video](https://www.youtube.com/watch?v=3IqtmUscE_U).
更多信息,见 [Brian Ford 的视频](https://www.youtube.com/watch?v=3IqtmUscE_U)。 更多信息,见 [Brian Ford 的视频](https://www.youtube.com/watch?v=3IqtmUscE_U)。

View File

@ -45,7 +45,6 @@ Most apps do so in the root `AppModule`.
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="sketch" region="sketch"
title="app/app.module.ts (excerpt)" linenums="false"> title="app/app.module.ts (excerpt)" linenums="false">
</code-example> </code-example>
Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient` Having imported `HttpClientModule` into the `AppModule`, you can inject the `HttpClient`
@ -57,7 +56,6 @@ into an application class as shown in the following `ConfigService` example.
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="proto" region="proto"
title="app/config/config.service.ts (excerpt)" linenums="false"> title="app/config/config.service.ts (excerpt)" linenums="false">
</code-example> </code-example>
## Getting JSON data ## Getting JSON data
@ -74,7 +72,6 @@ that specifies resource URLs.
<code-example <code-example
path="http/src/assets/config.json" path="http/src/assets/config.json"
title="assets/config.json" linenums="false"> title="assets/config.json" linenums="false">
</code-example> </code-example>
The `ConfigService` fetches this file with a `get()` method on `HttpClient`. The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
@ -85,7 +82,6 @@ The `ConfigService` fetches this file with a `get()` method on `HttpClient`.
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_1" region="getConfig_1"
title="app/config/config.service.ts (getConfig v.1)" linenums="false"> title="app/config/config.service.ts (getConfig v.1)" linenums="false">
</code-example> </code-example>
A component, such as `ConfigComponent`, injects the `ConfigService` and calls A component, such as `ConfigComponent`, injects the `ConfigService` and calls
@ -97,7 +93,6 @@ the `getConfig` service method.
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v1" region="v1"
title="app/config/config.component.ts (showConfig v.1)" linenums="false"> title="app/config/config.component.ts (showConfig v.1)" linenums="false">
</code-example> </code-example>
Because the service method returns an `Observable` of configuration data, Because the service method returns an `Observable` of configuration data,
@ -148,7 +143,6 @@ The subscribe callback above requires bracket notation to extract the data value
<code-example <code-example
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v1_callback" linenums="false"> region="v1_callback" linenums="false">
</code-example> </code-example>
You can't write `data.heroesUrl` because TypeScript correctly complains that the `data` object from the service does not have a `heroesUrl` property. You can't write `data.heroesUrl` because TypeScript correctly complains that the `data` object from the service does not have a `heroesUrl` property.
@ -170,7 +164,6 @@ First, define an interface with the correct shape:
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="config-interface" linenums="false"> region="config-interface" linenums="false">
</code-example> </code-example>
Then, specify that interface as the `HttpClient.get()` call's type parameter in the service: Then, specify that interface as the `HttpClient.get()` call's type parameter in the service:
@ -181,7 +174,6 @@ Then, specify that interface as the `HttpClient.get()` call's type parameter in
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_2" region="getConfig_2"
title="app/config/config.service.ts (getConfig v.2)" linenums="false"> title="app/config/config.service.ts (getConfig v.2)" linenums="false">
</code-example> </code-example>
The callback in the updated component method receives a typed data object, which is The callback in the updated component method receives a typed data object, which is
@ -193,7 +185,6 @@ easier and safer to consume:
path="http/src/app/config/config.component.ts" path="http/src/app/config/config.component.ts"
region="v2" region="v2"
title="app/config/config.component.ts (showConfig v.2)" linenums="false"> title="app/config/config.component.ts (showConfig v.2)" linenums="false">
</code-example> </code-example>
### Reading the full response ### Reading the full response
@ -211,7 +202,6 @@ Tell `HttpClient` that you want the full response with the `observe` option:
<code-example <code-example
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfigResponse" linenums="false"> region="getConfigResponse" linenums="false">
</code-example> </code-example>
Now `HttpClient.get()` returns an `Observable` of typed `HttpResponse` rather than just the JSON data. Now `HttpClient.get()` returns an `Observable` of typed `HttpResponse` rather than just the JSON data.
@ -227,7 +217,6 @@ The component's `showConfigResponse()` method displays the response headers as w
region="showConfigResponse" region="showConfigResponse"
title="app/config/config.component.ts (showConfigResponse)" title="app/config/config.component.ts (showConfigResponse)"
linenums="false"> linenums="false">
</code-example> </code-example>
As you can see, the response object has a `body` property of the correct type. As you can see, the response object has a `body` property of the correct type.
@ -251,7 +240,6 @@ You _could_ handle in the component by adding a second callback to the `.subscri
region="v3" region="v3"
title="app/config/config.component.ts (showConfig v.3 with error handling)" title="app/config/config.component.ts (showConfig v.3 with error handling)"
linenums="false"> linenums="false">
</code-example> </code-example>
It's certainly a good idea to give the user some kind of feedback when data access fails. It's certainly a good idea to give the user some kind of feedback when data access fails.
@ -296,7 +284,6 @@ You might first devise an error handler like this one:
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="handleError" region="handleError"
title="app/config/config.service.ts (handleError)" linenums="false"> title="app/config/config.service.ts (handleError)" linenums="false">
</code-example> </code-example>
Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message. Notice that this handler returns an RxJS [`ErrorObservable`](#rxjs) with a user-friendly error message.
@ -315,7 +302,6 @@ and _pipe them through_ to the error handler.
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig_3" region="getConfig_3"
title="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false"> title="app/config/config.service.ts (getConfig v.3 with error handler)" linenums="false">
</code-example> </code-example>
### `retry()` ### `retry()`
@ -341,7 +327,6 @@ _Pipe_ it onto the `HttpClient` method result just before the error handler.
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="getConfig" region="getConfig"
title="app/config/config.service.ts (getConfig with retry)" linenums="false"> title="app/config/config.service.ts (getConfig with retry)" linenums="false">
</code-example> </code-example>
{@a rxjs} {@a rxjs}
@ -377,7 +362,6 @@ If you're following along with these code snippets, note that you must import th
path="http/src/app/config/config.service.ts" path="http/src/app/config/config.service.ts"
region="rxjs-imports" region="rxjs-imports"
title="app/config/config.service.ts (RxJS imports)" linenums="false"> title="app/config/config.service.ts (RxJS imports)" linenums="false">
</code-example> </code-example>
## Requesting non-JSON data ## Requesting non-JSON data
@ -396,7 +380,6 @@ as an `Observable<string>`.
path="http/src/app/downloader/downloader.service.ts" path="http/src/app/downloader/downloader.service.ts"
region="getTextFile" region="getTextFile"
title="app/downloader/downloader.service.ts (getTextFile)" linenums="false"> title="app/downloader/downloader.service.ts (getTextFile)" linenums="false">
</code-example> </code-example>
`HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option. `HttpClient.get()` returns a string rather than the default JSON because of the `responseType` option.
@ -415,7 +398,6 @@ A `download()` method in the `DownloaderComponent` initiates the request by subs
path="http/src/app/downloader/downloader.component.ts" path="http/src/app/downloader/downloader.component.ts"
region="download" region="download"
title="app/downloader/downloader.component.ts (download)" linenums="false"> title="app/downloader/downloader.component.ts (download)" linenums="false">
</code-example> </code-example>
## Sending data to the server ## Sending data to the server
@ -457,7 +439,6 @@ to every `HttpClient` save method.
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="http-options" region="http-options"
title="app/heroes/heroes.service.ts (httpOptions)" linenums="false"> title="app/heroes/heroes.service.ts (httpOptions)" linenums="false">
</code-example> </code-example>
### Making a POST request ### Making a POST request
@ -474,7 +455,6 @@ In the following example, the `HeroService` posts when adding a hero to the data
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="addHero" region="addHero"
title="app/heroes/heroes.service.ts (addHero)" linenums="false"> title="app/heroes/heroes.service.ts (addHero)" linenums="false">
</code-example> </code-example>
The `HttpClient.post()` method is similar to `get()` in that it has a type parameter The `HttpClient.post()` method is similar to `get()` in that it has a type parameter
@ -510,7 +490,6 @@ the `Observable` returned by this service method.
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="add-hero-subscribe" region="add-hero-subscribe"
title="app/heroes/heroes.component.ts (addHero)" linenums="false"> title="app/heroes/heroes.component.ts (addHero)" linenums="false">
</code-example> </code-example>
When the server responds successfully with the newly added hero, the component adds When the server responds successfully with the newly added hero, the component adds
@ -531,7 +510,6 @@ in the request URL.
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="deleteHero" region="deleteHero"
title="app/heroes/heroes.service.ts (deleteHero)" linenums="false"> title="app/heroes/heroes.service.ts (deleteHero)" linenums="false">
</code-example> </code-example>
The `HeroesComponent` initiates the actual DELETE operation by subscribing to The `HeroesComponent` initiates the actual DELETE operation by subscribing to
@ -543,7 +521,6 @@ the `Observable` returned by this service method.
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="delete-hero-subscribe" region="delete-hero-subscribe"
title="app/heroes/heroes.component.ts (deleteHero)" linenums="false"> title="app/heroes/heroes.component.ts (deleteHero)" linenums="false">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -570,7 +547,6 @@ Merely calling `HeroService.deleteHero()` **does not initiate the DELETE request
<code-example <code-example
path="http/src/app/heroes/heroes.component.ts" path="http/src/app/heroes/heroes.component.ts"
region="delete-hero-no-subscribe" linenums="false"> region="delete-hero-no-subscribe" linenums="false">
</code-example> </code-example>
{@a always-subscribe} {@a always-subscribe}
@ -643,7 +619,6 @@ The following `HeroService` example is just like the POST example.
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="updateHero" region="updateHero"
title="app/heroes/heroes.service.ts (updateHero)" linenums="false"> title="app/heroes/heroes.service.ts (updateHero)" linenums="false">
</code-example> </code-example>
For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()` For the reasons [explained above](#always-subscribe), the caller (`HeroesComponent.update()` in this case) must `subscribe()` to the observable returned from the `HttpClient.put()`
@ -698,7 +673,6 @@ before making the next request.
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="update-headers" linenums="false"> region="update-headers" linenums="false">
</code-example> </code-example>
#### URL Parameters #### URL Parameters
@ -714,14 +688,13 @@ Here is a `searchHeroes` method that queries for heroes whose names contain the
<code-example <code-example
path="http/src/app/heroes/heroes.service.ts" path="http/src/app/heroes/heroes.service.ts"
region="searchHeroes" linenums="false"> region="searchHeroes" linenums="false">
</code-example> </code-example>
If there is a search term, the code constructs an options object with an HTML URL encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`. If there is a search term, the code constructs an options object with an HTML URL encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
如果有搜索词,这段代码就会构造一个包含进行过 URL 编码的搜索词的选项对象。如果这个搜索词是“foo”这个 GET 请求的 URL 就会是 `api/heroes/?name=foo` 如果有搜索词,这段代码就会构造一个包含进行过 URL 编码的搜索词的选项对象。如果这个搜索词是“foo”这个 GET 请求的 URL 就会是 `api/heroes/?name=foo`
The `HttpParams` are immutable so you'll have to use the `set()` method to update the options. The `HttpParms` are immutable so you'll have to use the `set()` method to update the options.
`HttpParams` 是不可变的,所以你也要使用 `set()` 方法来修改这些选项。 `HttpParams` 是不可变的,所以你也要使用 `set()` 方法来修改这些选项。
@ -746,7 +719,6 @@ Here's a pertinent excerpt from the template:
path="http/src/app/package-search/package-search.component.html" path="http/src/app/package-search/package-search.component.html"
region="search" region="search"
title="app/package-search/package-search.component.html (search)"> title="app/package-search/package-search.component.html (search)">
</code-example> </code-example>
The `(keyup)` event binding sends every keystroke to the component's `search()` method. The `(keyup)` event binding sends every keystroke to the component's `search()` method.
@ -765,7 +737,6 @@ That's easy to implement with RxJS operators, as shown in this excerpt.
path="http/src/app/package-search/package-search.component.ts" path="http/src/app/package-search/package-search.component.ts"
region="debounce" region="debounce"
title="app/package-search/package-search.component.ts (excerpt))"> title="app/package-search/package-search.component.ts (excerpt))">
</code-example> </code-example>
The `searchText$` is the sequence of search-box values coming from the user. The `searchText$` is the sequence of search-box values coming from the user.
@ -875,15 +846,14 @@ To implement an interceptor, declare a class that implements the `intercept()` m
要实现拦截器,就要实现一个实现了 `HttpInterceptor` 接口中的 `intercept()` 方法的类。 要实现拦截器,就要实现一个实现了 `HttpInterceptor` 接口中的 `intercept()` 方法的类。
Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it: Here is a do-nothing _noop_ interceptor that simply passes the request through without touching it:
这里是一个什么也不做的*空白*拦截器,它只会不做任何修改的传递这个请求。 这里是一个什么也不做的*空白*拦截器,它只会不做任何修改的传递这个请求。
<code-example <code-example
path="http/src/app/http-interceptors/noop-interceptor.ts" path="http/src/app/http-interceptors/noop-interceptor.ts"
title="app/http-interceptors/noop-interceptor.ts" title="app/http-interceptors/noop-interceptor.ts"
linenums="false"> linenums="false">
</code-example> </code-example>
The `intercept` method transforms a request into an `Observable` that eventually returns the HTTP response. The `intercept` method transforms a request into an `Observable` that eventually returns the HTTP response.
@ -963,7 +933,6 @@ write the `NoopInterceptor` provider like this:
<code-example <code-example
path="http/src/app/http-interceptors/index.ts" path="http/src/app/http-interceptors/index.ts"
region="noop-provider" linenums="false"> region="noop-provider" linenums="false">
</code-example> </code-example>
Note the `multi: true` option. Note the `multi: true` option.
@ -990,7 +959,6 @@ Consider creating a "barrel" file that gathers all the interceptor providers int
path="http/src/app/http-interceptors/index.ts" path="http/src/app/http-interceptors/index.ts"
region="interceptor-providers" region="interceptor-providers"
title="app/http-interceptors/index.ts" linenums="false"> title="app/http-interceptors/index.ts" linenums="false">
</code-example> </code-example>
Then import and add it to the `AppModule` _providers array_ like this: Then import and add it to the `AppModule` _providers array_ like this:
@ -1001,7 +969,6 @@ Then import and add it to the `AppModule` _providers array_ like this:
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="interceptor-providers" region="interceptor-providers"
title="app/app.module.ts (interceptor providers)" linenums="false"> title="app/app.module.ts (interceptor providers)" linenums="false">
</code-example> </code-example>
As you create new interceptors, add them to the `httpInterceptorProviders` array and As you create new interceptors, add them to the `httpInterceptorProviders` array and
@ -1100,7 +1067,6 @@ You can clone and modify the request in a single step as in this example.
path="http/src/app/http-interceptors/ensure-https-interceptor.ts" path="http/src/app/http-interceptors/ensure-https-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false"> title="app/http-interceptors/ensure-https-interceptor.ts (excerpt)" linenums="false">
</code-example> </code-example>
The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others. The `clone()` method's hash argument allows you to mutate specific properties of the request while copying the others.
@ -1131,7 +1097,6 @@ If you must mutate the request body, copy it first, change the copy,
path="http/src/app/http-interceptors/trim-name-interceptor.ts" path="http/src/app/http-interceptors/trim-name-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false"> title="app/http-interceptors/trim-name-interceptor.ts (excerpt)" linenums="false">
</code-example> </code-example>
##### Clearing the request body ##### Clearing the request body
@ -1174,7 +1139,6 @@ adds an authorization header with that token to every outgoing request:
<code-example <code-example
path="http/src/app/http-interceptors/auth-interceptor.ts" path="http/src/app/http-interceptors/auth-interceptor.ts"
title="app/http-interceptors/auth-interceptor.ts"> title="app/http-interceptors/auth-interceptor.ts">
</code-example> </code-example>
The practice of cloning a request to set new headers is so common that The practice of cloning a request to set new headers is so common that
@ -1185,7 +1149,6 @@ there's a `setHeaders` shortcut for it:
<code-example <code-example
path="http/src/app/http-interceptors/auth-interceptor.ts" path="http/src/app/http-interceptors/auth-interceptor.ts"
region="set-header-shortcut"> region="set-header-shortcut">
</code-example> </code-example>
An interceptor that alters headers can be used for a number of different operations, including: An interceptor that alters headers can be used for a number of different operations, including:
@ -1223,7 +1186,6 @@ with the injected `MessageService`.
path="http/src/app/http-interceptors/logging-interceptor.ts" path="http/src/app/http-interceptors/logging-interceptor.ts"
region="excerpt" region="excerpt"
title="app/http-interceptors/logging-interceptor.ts)"> title="app/http-interceptors/logging-interceptor.ts)">
</code-example> </code-example>
The RxJS `tap` operator captures whether the request succeed or failed. The RxJS `tap` operator captures whether the request succeed or failed.
@ -1259,7 +1221,6 @@ The `CachingInterceptor` demonstrates this approach.
path="http/src/app/http-interceptors/caching-interceptor.ts" path="http/src/app/http-interceptors/caching-interceptor.ts"
region="v1" region="v1"
title="app/http-interceptors/caching-interceptor.ts)" linenums="false"> title="app/http-interceptors/caching-interceptor.ts)" linenums="false">
</code-example> </code-example>
The `isCachable()` function determines if the request is cachable. The `isCachable()` function determines if the request is cachable.
@ -1287,7 +1248,6 @@ If a cachable request is not in cache, the code calls `sendRequest`.
<code-example <code-example
path="http/src/app/http-interceptors/caching-interceptor.ts" path="http/src/app/http-interceptors/caching-interceptor.ts"
region="send-request"> region="send-request">
</code-example> </code-example>
The `sendRequest` function creates a [request clone](#immutability) without headers The `sendRequest` function creates a [request clone](#immutability) without headers
@ -1343,7 +1303,6 @@ and emits again later with the updated search results.
<code-example <code-example
path="http/src/app/http-interceptors/caching-interceptor.ts" path="http/src/app/http-interceptors/caching-interceptor.ts"
region="intercept-refresh"> region="intercept-refresh">
</code-example> </code-example>
The _cache-then-refresh_ option is triggered by the presence of a **custom `x-refresh` header**. The _cache-then-refresh_ option is triggered by the presence of a **custom `x-refresh` header**.
@ -1407,7 +1366,6 @@ with the `reportProgress` option set true to enable tracking of progress events.
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="upload-request" region="upload-request"
title="app/uploader/uploader.service.ts (upload request)"> title="app/uploader/uploader.service.ts (upload request)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -1427,7 +1385,6 @@ returns an `Observable` of `HttpEvents`, the same events processed by intercepto
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="upload-body" region="upload-body"
title="app/uploader/uploader.service.ts (upload body)" linenums="false"> title="app/uploader/uploader.service.ts (upload body)" linenums="false">
</code-example> </code-example>
The `getEventMessage` method interprets each type of `HttpEvent` in the event stream. The `getEventMessage` method interprets each type of `HttpEvent` in the event stream.
@ -1438,7 +1395,6 @@ The `getEventMessage` method interprets each type of `HttpEvent` in the event st
path="http/src/app/uploader/uploader.service.ts" path="http/src/app/uploader/uploader.service.ts"
region="getEventMessage" region="getEventMessage"
title="app/uploader/uploader.service.ts (getEventMessage)" linenums="false"> title="app/uploader/uploader.service.ts (getEventMessage)" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1501,7 +1457,6 @@ use `HttpClientXsrfModule.withOptions()` to override the defaults.
path="http/src/app/app.module.ts" path="http/src/app/app.module.ts"
region="xsrf" region="xsrf"
linenums="false"> linenums="false">
</code-example> </code-example>
## Testing HTTP requests ## Testing HTTP requests
@ -1565,7 +1520,6 @@ along with the other symbols your tests require.
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="imports" region="imports"
title="app/testing/http-client.spec.ts (imports)" linenums="false"> title="app/testing/http-client.spec.ts (imports)" linenums="false">
</code-example> </code-example>
Then add the `HttpClientTestingModule` to the `TestBed` and continue with Then add the `HttpClientTestingModule` to the `TestBed` and continue with
@ -1577,7 +1531,6 @@ the setup of the _service-under-test_.
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="setup" region="setup"
title="app/testing/http-client.spec.ts(setup)" linenums="false"> title="app/testing/http-client.spec.ts(setup)" linenums="false">
</code-example> </code-example>
Now requests made in the course of your tests will hit the testing backend instead of the normal backend. Now requests made in the course of your tests will hit the testing backend instead of the normal backend.
@ -1601,7 +1554,6 @@ Now you can write a test that expects a GET Request to occur and provides a mock
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="get-test" region="get-test"
title="app/testing/http-client.spec.ts(httpClient.get)" linenums="false"> title="app/testing/http-client.spec.ts(httpClient.get)" linenums="false">
</code-example> </code-example>
The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step: The last step, verifying that no requests remain outstanding, is common enough for you to move it into an `afterEach()` step:
@ -1612,7 +1564,6 @@ The last step, verifying that no requests remain outstanding, is common enough f
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="afterEach" region="afterEach"
linenums="false"> linenums="false">
</code-example> </code-example>
#### Custom request expectations #### Custom request expectations
@ -1629,7 +1580,6 @@ For example, you could look for an outgoing request that has an authorization he
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="predicate" region="predicate"
linenums="false"> linenums="false">
</code-example> </code-example>
As with the previous `expectOne()`, As with the previous `expectOne()`,
@ -1652,7 +1602,6 @@ you are responsible for flushing and verifying them.
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="multi-request" region="multi-request"
linenums="false"> linenums="false">
</code-example> </code-example>
### Testing for errors ### Testing for errors
@ -1671,5 +1620,4 @@ Call `request.error()` with an `ErrorEvent` instead of `request.flush()`, as in
path="http/src/testing/http-client.spec.ts" path="http/src/testing/http-client.spec.ts"
region="404" region="404"
linenums="false"> linenums="false">
</code-example> </code-example>

View File

@ -85,9 +85,7 @@ of the locale id that you want to use:
要把你的应用的地区改为其它值,可以使用 CLI 参数 `--locale` 来传入你要使用的地区标识: 要把你的应用的地区改为其它值,可以使用 CLI 参数 `--locale` 来传入你要使用的地区标识:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng serve --aot --locale fr ng serve --aot --locale fr
</code-example> </code-example>
If you use JIT, you also need to define the `LOCALE_ID` provider in your main module: If you use JIT, you also need to define the `LOCALE_ID` provider in your main module:
@ -95,7 +93,6 @@ If you use JIT, you also need to define the `LOCALE_ID` provider in your main mo
如果要使用 JIT你就得在你的主模块中定义 `LOCALE_ID` 这个服务提供商: 如果要使用 JIT你就得在你的主模块中定义 `LOCALE_ID` 这个服务提供商:
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
For more information about Unicode locale identifiers, see the For more information about Unicode locale identifiers, see the
@ -150,7 +147,6 @@ If you want to import locale data for other languages, you can do it manually:
如果还要为其它语言导入本地化数据,你可以手工完成它: 如果还要为其它语言导入本地化数据,你可以手工完成它:
<code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
The first parameter is an object containing the locale data imported from `@angular/common/locales`. The first parameter is an object containing the locale data imported from `@angular/common/locales`.
@ -174,7 +170,6 @@ import from `@angular/common/locales/extra`. An error message informs you when t
不过有些高级的格式选项只存在于从 `@angular/common/locales/extra` 中导入的扩展数据集中。遇到这种情况,你就会收到一条错误信息。 不过有些高级的格式选项只存在于从 `@angular/common/locales/extra` 中导入的扩展数据集中。遇到这种情况,你就会收到一条错误信息。
<code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -243,7 +238,6 @@ In the example below, an `<h1>` tag displays a simple English language greeting,
在下面的例子中,`<h1>`标签显示了一句简单的英文问候语“Hello i18n!” 在下面的例子中,`<h1>`标签显示了一句简单的英文问候语“Hello i18n!”
<code-example path="i18n/doc-files/app.component.html" region="greeting" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="greeting" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag. To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
@ -251,7 +245,6 @@ To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag
要想把它标记为需要翻译的文本,就给 `<h1>` 标签添加上 `i18n` 属性。 要想把它标记为需要翻译的文本,就给 `<h1>` 标签添加上 `i18n` 属性。
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -280,7 +273,6 @@ example below:
你可以用 `i18n` 属性的值来添加这些文本信息的描述,例子如下: 你可以用 `i18n` 属性的值来添加这些文本信息的描述,例子如下:
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The translator may also need to know the meaning or intent of the text message within this particular The translator may also need to know the meaning or intent of the text message within this particular
@ -294,7 +286,6 @@ separating it from the _description_ with the `|` character: `<meaning>|<descrip
在描述的前面,你可以用 `i18n` 开头的属性值来为指定的字符串添加一些上下文含义,用 `|` 将其与描述文字隔开(`<意图>|<描述>`)。 在描述的前面,你可以用 `i18n` 开头的属性值来为指定的字符串添加一些上下文含义,用 `|` 将其与描述文字隔开(`<意图>|<描述>`)。
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
All occurrences of a text message that have the same meaning will have the same translation. All occurrences of a text message that have the same meaning will have the same translation.
@ -323,7 +314,6 @@ attribute in a template. By default, it assigns each translation unit a unique i
Angular 的 `i18n` 提取工具会为模板中每个带有 `i18n` 属性的元素生成一个*翻译单元translation unit*条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的 `id`,就像这样: Angular 的 `i18n` 提取工具会为模板中每个带有 `i18n` 属性的元素生成一个*翻译单元translation unit*条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的 `id`,就像这样:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id" linenums="false">
</code-example> </code-example>
When you change the translatable text, the extractor tool generates a new id for that translation unit. When you change the translatable text, the extractor tool generates a new id for that translation unit.
@ -339,7 +329,6 @@ The example below defines the custom id `introductionHeader`:
下面这个例子就定义了一个自定义 id `introductionHeader` 下面这个例子就定义了一个自定义 id `introductionHeader`
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' title='app/app.component.html' linenums="false">
</code-example> </code-example>
When you specify a custom id, the extractor tool and compiler generate a translation unit with that When you specify a custom id, the extractor tool and compiler generate a translation unit with that
@ -348,7 +337,6 @@ custom id.
一旦你指定了自定义 id提取工具和编译器就会用*你的自定义 id` 生成一个翻译单元,而不会再改变它。 一旦你指定了自定义 id提取工具和编译器就会用*你的自定义 id` 生成一个翻译单元,而不会再改变它。
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id" linenums="false">
</code-example> </code-example>
The custom id is persistent. The extractor tool does not change it when the translatable text changes. The custom id is persistent. The extractor tool does not change it when the translatable text changes.
@ -369,7 +357,6 @@ by the custom `id`:
下面的例子中,`i18n` 的属性中中就包含了一条跟在自定义 `id` 后面的描述信息: 下面的例子中,`i18n` 的属性中中就包含了一条跟在自定义 `id` 后面的描述信息:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false">
</code-example> </code-example>
You also can add a meaning, as shown in this example: You also can add a meaning, as shown in this example:
@ -377,7 +364,6 @@ You also can add a meaning, as shown in this example:
你还可以添加含义,例子如下: 你还可以添加含义,例子如下:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false"> <code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false">
</code-example> </code-example>
#### Define unique custom ids #### Define unique custom ids
@ -446,7 +432,6 @@ The `<ng-container>` is transformed into an html comment:
但如果由于某些原因(比如 CSS 结构方面的考虑),你可能不希望仅仅为了翻译而创建一个新的 DOM 元素,那么也可以把这段文本包裹进一个 `<ng-container>` 元素中。`<ng-container>` 将被转换成一个 HTML 注释: 但如果由于某些原因(比如 CSS 结构方面的考虑),你可能不希望仅仅为了翻译而创建一个新的 DOM 元素,那么也可以把这段文本包裹进一个 `<ng-container>` 元素中。`<ng-container>` 将被转换成一个 HTML 注释:
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a translate-attributes} {@a translate-attributes}
@ -462,7 +447,6 @@ For example, assume that your template has an image with a `title` attribute:
比如,假设你的模板中有一个带 `title` 属性的图片: 比如,假设你的模板中有一个带 `title` 属性的图片:
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/doc-files/app.component.html" region="i18n-title" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
This `title` attribute needs to be translated. This `title` attribute needs to be translated.
@ -477,7 +461,6 @@ where `x` is the name of the attribute to translate. The following example shows
下面的例子中演示了如何通过给 `img` 标签添加 `i18n-title` 属性来把 `title` 属性标记为待翻译的。 下面的例子中演示了如何通过给 `img` 标签添加 `i18n-title` 属性来把 `title` 属性标记为待翻译的。
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
This technique works for any attribute of any element. This technique works for any attribute of any element.
@ -514,7 +497,6 @@ based on when the update occurred:
下面这个例子示范了如何使用 ICU 表达式 `plural` 来根据这次修改发生的时间显示这三个选项之一: 下面这个例子示范了如何使用 ICU 表达式 `plural` 来根据这次修改发生的时间显示这三个选项之一:
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
* The first parameter is the key. It is bound to the component property (`minutes`), which determines * The first parameter is the key. It is bound to the component property (`minutes`), which determines
@ -620,7 +602,6 @@ The message maps those values to the appropriate translations:
这个消息会把那些值映射到适当的翻译文本: 这个消息会把那些值映射到适当的翻译文本:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a nesting-ICUS} {@a nesting-ICUS}
@ -634,7 +615,6 @@ You can also nest different ICU expressions together, as shown in this example:
你也可以把不同的 ICU 表达式嵌套在一起,比如: 你也可以把不同的 ICU 表达式嵌套在一起,比如:
<code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html"> <code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html">
</code-example> </code-example>
{@a ng-xi18n} {@a ng-xi18n}
@ -653,9 +633,7 @@ Open a terminal window at the root of the app project and enter the `ng xi18n` c
在应用的项目根目录打开一个终端窗口,并输入 `ng xi18n` 命令: 在应用的项目根目录打开一个终端窗口,并输入 `ng xi18n` 命令:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng xi18n ng xi18n
</code-example> </code-example>
By default, the tool generates a translation file named `messages.xlf` in the By default, the tool generates a translation file named `messages.xlf` in the
@ -711,11 +689,9 @@ these example commands:
你可以使用 `--i18nFormat` 来明确指定想用的格式,范例如下: 你可以使用 `--i18nFormat` 来明确指定想用的格式,范例如下:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng xi18n --i18nFormat=xlf ng xi18n --i18nFormat=xlf
ng xi18n --i18nFormat=xlf2 ng xi18n --i18nFormat=xlf2
ng xi18n --i18nFormat=xmb ng xi18n --i18nFormat=xmb
</code-example> </code-example>
The sample in this guide uses the default XLIFF 1.2 format. The sample in this guide uses the default XLIFF 1.2 format.
@ -870,7 +846,8 @@ This sample file is easy to translate without a special editor or knowledge of F
打开 `messages.fr.xlf` 并找到第一个 `<trans-unit>` 区: 打开 `messages.fr.xlf` 并找到第一个 `<trans-unit>` 区:
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"></code-example> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example>
> This XML element represents the translation of the `<h1>` greeting tag that you marked with the > This XML element represents the translation of the `<h1>` greeting tag that you marked with the
`i18n` attribute earlier in this guide. `i18n` attribute earlier in this guide.
@ -891,13 +868,15 @@ This sample file is easy to translate without a special editor or knowledge of F
复制 `<source/>` 标记,把它改名为 `target`,并把它的内容改为法语版的 “greeting”。 复制 `<source/>` 标记,把它改名为 `target`,并把它的内容改为法语版的 “greeting”。
如果你要做的是更复杂的翻译,可能会使用由源文本、描述信息和含义等提供的信息和上下文来给出更恰当的法语翻译。 如果你要做的是更复杂的翻译,可能会使用由源文本、描述信息和含义等提供的信息和上下文来给出更恰当的法语翻译。
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;, after translation)" linenums="false"></code-example> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;, after translation)" linenums="false">
</code-example>
3. Translate the other text nodes the same way: 3. Translate the other text nodes the same way:
用同样的方式翻译其它文本节点: 用同样的方式翻译其它文本节点:
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"></code-example> > <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -942,7 +921,6 @@ To translate a `plural`, translate its ICU format match values:
要翻译一个复数,就要翻译它的 ICU 格式中匹配的值: 要翻译一个复数,就要翻译它的 ICU 格式中匹配的值:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
You can add or remove plural cases, with each language having its own cardinality. (See You can add or remove plural cases, with each language having its own cardinality. (See
@ -961,7 +939,6 @@ Below is the content of our example `select` ICU expression in the component tem
下面是组件模板中的 ICU 表达式 `select` 的例子: 下面是组件模板中的 ICU 表达式 `select` 的例子:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false"> <code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The extraction tool broke that into two translation units because ICU expressions are extracted The extraction tool broke that into two translation units because ICU expressions are extracted
@ -980,7 +957,6 @@ the placeholder, the ICU expression will not be present in your translated app.
如果删除了占位符ICU 表达式就不会出现在翻译后的应用中。 如果删除了占位符ICU 表达式就不会出现在翻译后的应用中。
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The second translation unit, immediately below the first one, contains the `select` message. The second translation unit, immediately below the first one, contains the `select` message.
@ -989,7 +965,6 @@ Translate that as well.
第一个翻译单元的紧下方就是第二个翻译单元,包含 `select` 中的消息。照样翻译它。 第一个翻译单元的紧下方就是第二个翻译单元,包含 `select` 中的消息。照样翻译它。
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
Here they are together, after translation: Here they are together, after translation:
@ -997,7 +972,6 @@ Here they are together, after translation:
在翻译之后,它们会放在一起: 在翻译之后,它们会放在一起:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
{@a translate-nested} {@a translate-nested}
@ -1013,7 +987,6 @@ two translation units. The first one contains the text outside of the nested exp
第一个包含嵌套表达式之外的文本: 第一个包含嵌套表达式之外的文本:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The second unit contains the complete nested expression: The second unit contains the complete nested expression:
@ -1021,7 +994,6 @@ The second unit contains the complete nested expression:
第二个包含完整的嵌套表达式: 第二个包含完整的嵌套表达式:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
And both together: And both together:
@ -1029,7 +1001,6 @@ And both together:
放在一起时: 放在一起时:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false"> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" title="src/locale/messages.fr.xlf (&lt;trans-unit&gt;)" linenums="false">
</code-example> </code-example>
The entire template translation is complete. The next section describes how to load that translation The entire template translation is complete. The next section describes how to load that translation
@ -1048,7 +1019,6 @@ The sample app and its translation file are now as follows:
下面是例子应用及其翻译文件: 下面是例子应用及其翻译文件:
<code-tabs> <code-tabs>
<code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html"> <code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html">
</code-pane> </code-pane>
<code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts"> <code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
@ -1059,7 +1029,6 @@ The sample app and its translation file are now as follows:
</code-pane> </code-pane>
<code-pane title="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html"> <code-pane title="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a merge} {@a merge}
@ -1144,9 +1113,7 @@ guide:
下面的例子演示了如何使用前面部分创建的法语文件来启动开发服务器: 下面的例子演示了如何使用前面部分创建的法语文件来启动开发服务器:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng serve --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr ng serve --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr
</code-example> </code-example>
{@a merge-jit} {@a merge-jit}
@ -1196,7 +1163,6 @@ behavior of the compiler. You can use it to provide the translation providers:
在下面的 `src/app/i18n-providers.ts` 文件的 `getTranslationProviders()` 函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商: 在下面的 `src/app/i18n-providers.ts` 文件的 `getTranslationProviders()` 函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商:
<code-example path="i18n/doc-files/main.2.ts" title="src/main.ts"> <code-example path="i18n/doc-files/main.2.ts" title="src/main.ts">
</code-example> </code-example>
Then provide the `LOCALE_ID` in the main module: Then provide the `LOCALE_ID` in the main module:
@ -1204,7 +1170,6 @@ Then provide the `LOCALE_ID` in the main module:
然后在主文件包中提供 `LOCALE_ID` 然后在主文件包中提供 `LOCALE_ID`
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
{@a missing-translation} {@a missing-translation}
@ -1238,9 +1203,7 @@ If you use the AOT compiler, specify the warning level by using the CLI paramete
如果你使用 AOT 编译器,可以使用 CLI 参数 `--missingTranslation` 来指定警告级别。下面的例子示范了如何把警告级别设置为 `error` 如果你使用 AOT 编译器,可以使用 CLI 参数 `--missingTranslation` 来指定警告级别。下面的例子示范了如何把警告级别设置为 `error`
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng serve --aot --missingTranslation=error ng serve --aot --missingTranslation=error
</code-example> </code-example>
If you use the JIT compiler, specify the warning level in the compiler config at bootstrap by adding If you use the JIT compiler, specify the warning level in the compiler config at bootstrap by adding
@ -1250,5 +1213,4 @@ error:
如果你要使用 JIT 编译器,就在启动时往编译器的配置中添加一个 `MissingTranslationStrategy` 属性来指定警告级别。下面的例子示范了如何把警告级别设置为 `error` 如果你要使用 JIT 编译器,就在启动时往编译器的配置中添加一个 `MissingTranslationStrategy` 属性来指定警告级别。下面的例子示范了如何把警告级别设置为 `error`
<code-example path="i18n/doc-files/main.3.ts" title="src/main.ts"> <code-example path="i18n/doc-files/main.3.ts" title="src/main.ts">
</code-example> </code-example>

View File

@ -257,5 +257,4 @@ For more in-depth information, see the
For more information, see [Chuck Jazdzewski's presentation](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) on the Angular Language For more information, see [Chuck Jazdzewski's presentation](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) on the Angular Language
Service from [ng-conf](https://www.ng-conf.org/) 2017. Service from [ng-conf](https://www.ng-conf.org/) 2017.
要了解更多信息,参见 [ng-conf](https://www.ng-conf.org/) 2017 中 [Chuck Jazdzewski 的演讲](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) 中讲解的 Angular 语言服务。 要了解更多信息,参见 [ng-conf](https://www.ng-conf.org/) 2017 中 [Chuck Jazdzewski 的演讲](https://www.youtube.com/watch?v=ez3R0Gi4z5A&t=368s) 中讲解的 Angular 语言服务。

View File

@ -355,7 +355,7 @@ CLI 还会把 `RouterModule.forChild(routes)` 添加到各个特性模块中。
You may also be interested in the following: You may also be interested in the following:
你可能还对下列内容感兴趣: 你可能还对下列内容感兴趣:
* [Routing and Navigation](guide/router). * [Routing and Navigation](guide/router).
@ -363,8 +363,8 @@ You may also be interested in the following:
* [Providers](guide/providers). * [Providers](guide/providers).
[提供商](guide/providers)。 [服务提供商](guide/providers)。
* [Types of Feature Modules](guide/module-types). * [Types of Feature Modules](guide/module-types).
[特性模块的分类](guide/module-types)。 [特性模块的分类](guide/module-types)。

View File

@ -62,7 +62,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
<table width="100%"> <table width="100%">
<col width="20%"></col> <col width="20%"></col>
<col width="80%"></col> <col width="80%"></col>
<tr> <tr>
<th> <th>
@ -82,7 +81,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</th> </th>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -106,7 +104,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -129,7 +126,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -151,7 +147,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -173,7 +168,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -195,7 +189,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -217,7 +210,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -239,7 +231,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -263,7 +254,6 @@ calls the lifecycle hook methods in the following sequence at specific moments:
</td> </td>
</tr> </tr>
</table> </table>
{@a interface-optional} {@a interface-optional}
@ -335,7 +325,6 @@ Here's a brief description of each exercise:
<table width="100%"> <table width="100%">
<col width="20%"></col> <col width="20%"></col>
<col width="80%"></col> <col width="80%"></col>
<tr> <tr>
<th> <th>
@ -355,7 +344,6 @@ Here's a brief description of each exercise:
</th> </th>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -374,7 +362,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -399,7 +386,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -420,7 +406,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -440,7 +425,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -460,7 +444,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -481,7 +464,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
<tr style='vertical-align:top'> <tr style='vertical-align:top'>
<td> <td>
@ -510,7 +492,6 @@ Here's a brief description of each exercise:
</td> </td>
</tr> </tr>
</table> </table>
The remainder of this page discusses selected exercises in further detail. The remainder of this page discusses selected exercises in further detail.

View File

@ -115,7 +115,6 @@ typical characteristics, in real world apps, you may see hybrids.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -299,7 +298,6 @@ The following table summarizes the key characteristics of each feature module gr
下表中汇总了各种特性模块类型的关键特征。 下表中汇总了各种特性模块类型的关键特征。
<table> <table>
<tr> <tr>
<th style="vertical-align: top"> <th style="vertical-align: top">
@ -559,7 +557,6 @@ The following table summarizes the key characteristics of each feature module gr
</td> </td>
</tr> </tr>
</table> </table>
<hr /> <hr />
@ -570,7 +567,7 @@ The following table summarizes the key characteristics of each feature module gr
You may also be interested in the following: You may also be interested in the following:
你可能还对下列内容感兴趣: 你可能还对下列内容感兴趣:
* [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules). * [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules).
@ -578,4 +575,4 @@ You may also be interested in the following:
* [Providers](guide/providers). * [Providers](guide/providers).
[服务提供商](guide/providers)。 [服务提供商](guide/providers)。

View File

@ -139,7 +139,9 @@ The following table summarizes the `@NgModule` metadata properties.
</li> </li>
</ul> </ul>
</li> </li>
</ol> </ol>
Components, directives, and pipes must belong to _exactly_ one module. Components, directives, and pipes must belong to _exactly_ one module.
@ -402,8 +404,8 @@ You may also be interested in the following:
* [Providers](guide/providers). * [Providers](guide/providers).
[提供商](guide/providers)。 [服务提供商](guide/providers)。
* [Types of Feature Modules](guide/module-types). * [Types of Feature Modules](guide/module-types).
[特性模块的分类](guide/module-types)。 [特性模块的分类](guide/module-types)。

View File

@ -803,7 +803,6 @@ Here is a custom constructor for an NgModule called `CoreModule`.
某些 Angular 模块(例如 `BrowserModule`)就实现了一个像 Angular 模块那一章的 `CoreModule` 构造函数那样的守卫。 某些 Angular 模块(例如 `BrowserModule`)就实现了一个像 Angular 模块那一章的 `CoreModule` 构造函数那样的守卫。
<code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts (Constructor)" linenums="false"> <code-example path="ngmodule-faq/src/app/core/core.module.ts" region="ctor" title="src/app/core/core.module.ts (Constructor)" linenums="false">
</code-example> </code-example>
<hr/> <hr/>
@ -1133,5 +1132,4 @@ the Angular compiler incorporates them into compiled component code too.
`@NgModule` metadata tells the Angular compiler what components to compile for this module and `@NgModule` metadata tells the Angular compiler what components to compile for this module and
how to link this module with other modules. how to link this module with other modules.
`@NgModule` 元数据告诉*Angular 编译器*要为当前模块编译哪些组件,以及如何把当前模块和其它模块链接起来。 `@NgModule` 元数据告诉*Angular 编译器*要为当前模块编译哪些组件,以及如何把当前模块和其它模块链接起来。

View File

@ -126,4 +126,4 @@ For more information on NgModules, see:
* [Providers](guide/providers). * [Providers](guide/providers).
[服务提供商](guide/providers). [服务提供商](guide/providers)

View File

@ -121,7 +121,6 @@ The CLI generates the following basic app module when creating a new app.
CLI 在创建新应用时会生成下列基本的应用模块。 CLI 在创建新应用时会生成下列基本的应用模块。
<code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" title="src/app/app.module.ts" linenums="false"> <code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping). At the top are the import statements. The next section is where you configure the `@NgModule` by stating what components and directives belong to it (`declarations`) as well as which other modules it uses (`imports`). This page builds on [Bootstrapping](guide/bootstrapping), which covers the structure of an NgModule in detail. If you need more information on the structure of an `@NgModule`, be sure to read [Bootstrapping](guide/bootstrapping).
@ -137,7 +136,7 @@ At the top are the import statements. The next section is where you configure th
You may also be interested in the following: You may also be interested in the following:
你可能还对下列内容感兴趣: 你可能还对下列内容感兴趣:
* [Feature Modules](guide/feature-modules). * [Feature Modules](guide/feature-modules).
@ -149,8 +148,8 @@ You may also be interested in the following:
* [Providers](guide/providers). * [Providers](guide/providers).
[提供商](guide/providers)。 [服务提供商](guide/providers)。
* [Types of NgModules](guide/module-types). * [Types of NgModules](guide/module-types).
[NgModule 的分类](guide/module-types). [NgModule 的分类](guide/module-types).

View File

@ -280,5 +280,4 @@ The browser downloads this bundle, not the original package files.
See the [Deployment](guide/deployment) to learn more. See the [Deployment](guide/deployment) to learn more.
参见[部署](guide/deployment)一章了解详情。 参见[部署](guide/deployment)一章了解详情。

View File

@ -52,11 +52,11 @@ A handler for receiving observable notifications implements the `Observer` inter
用于接收可观察对象通知的处理器要实现 `Observer` 接口。这个对象定义了一些回调函数来处理可观察对象可能会发来的三种通知: 用于接收可观察对象通知的处理器要实现 `Observer` 接口。这个对象定义了一些回调函数来处理可观察对象可能会发来的三种通知:
| <p>Notification type</p><p>通知类型</p> | <p>Description</p><p>说明</p> | | <t>Notification type</t><t>通知类型</t> | <t>Description</t><t>说明</t> |
|:---------|:-------------------------------------------| |:---------|:-------------------------------------------|
| `next` | <p>Required. A handler for each delivered value. Called zero or more times after execution starts.</p><p>必要。用来处理每个送达值。在开始执行后可能执行零次或多次。</p>| | `next` | <t>Required. A handler for each delivered value. Called zero or more times after execution starts.</t><t>必要。用来处理每个送达值。在开始执行后可能执行零次或多次。</t>|
| `error` | <p>Optional. A handler for an error notification. An error halts execution of the observable instance.</p><p> 可选。用来处理错误通知。错误会中断这个可观察对象实例的执行过程。 </p>| | `error` | <t>Optional. A handler for an error notification. An error halts execution of the observable instance.</t><t> 可选。用来处理错误通知。错误会中断这个可观察对象实例的执行过程。 </t>|
| `complete` | <p>Optional. A handler for the execution-complete notification. Delayed values can continue to be delivered to the next handler after execution is complete.</p><p> 可选。用来处理执行完毕complete通知。当执行完毕后这些值就会继续传给下一个处理器。 </p>| | `complete` | <t>Optional. A handler for the execution-complete notification. Delayed values can continue to be delivered to the next handler after execution is complete.</t><t> 可选。用来处理执行完毕complete通知。当执行完毕后这些值就会继续传给下一个处理器。 </t>|
An observer object can define any combination of these handlers. If you don't supply a handler for a notification type, the observer ignores notifications of that type. An observer object can define any combination of these handlers. If you don't supply a handler for a notification type, the observer ignores notifications of that type.
@ -107,7 +107,7 @@ In either case, a `next` handler is required. The `error` and `complete` handler
无论哪种情况,`next` 处理器都是必要的,而 `error``complete` 处理器是可选的。 无论哪种情况,`next` 处理器都是必要的,而 `error``complete` 处理器是可选的。
Note that a `next()` function could receive, for instance, message strings, or event objects, numeric values, or structures, depending on context. As a general term, we refer to data published by an observable as a *stream*. Any type of value can be represented with an observable, and the values are published as a stream. Note that a `next()` function could receive, for instance, message strings, or event objects, numeric values, or stuctures, depending on context. As a general term, we refer to data published by an observable as a *stream*. Any type of value can be represented with an observable, and the values are published as a stream.
注意,`next()` 函数可以接受消息字符串、事件对象、数字值或各种结构,具体类型取决于上下文。 注意,`next()` 函数可以接受消息字符串、事件对象、数字值或各种结构,具体类型取决于上下文。
为了更通用一点,我们把由可观察对象发布出来的数据统称为*流*。任何类型的值都可以表示为可观察对象,而这些值会被发布为一个流。 为了更通用一点,我们把由可观察对象发布出来的数据统称为*流*。任何类型的值都可以表示为可观察对象,而这些值会被发布为一个流。
@ -196,12 +196,10 @@ Because observables produce values asynchronously, try/catch will not effectivel
由于可观察对象会异步生成值,所以用 `try/catch` 是无法捕获错误的。你应该在观察者中指定一个 `error` 回调来处理错误。发生错误时还会导致可观察对象清理现有的订阅,并且停止生成值。可观察对象可以生成值(调用 `next` 回调),也可以调用 `complete``error` 回调来主动结束。 由于可观察对象会异步生成值,所以用 `try/catch` 是无法捕获错误的。你应该在观察者中指定一个 `error` 回调来处理错误。发生错误时还会导致可观察对象清理现有的订阅,并且停止生成值。可观察对象可以生成值(调用 `next` 回调),也可以调用 `complete``error` 回调来主动结束。
<code-example> <code-example>
myObservable.subscribe({ myObservable.subscribe({
next(num) { console.log('Next num: ' + num)}, next(num) { console.log('Next num: ' + num)},
error(err) { console.log('Received an errror: ' + err)} error(err) { console.log('Received an errror: ' + err)}
}); });
</code-example> </code-example>
Error handling (and specifically recovering from an error) is covered in more detail in a later section. Error handling (and specifically recovering from an error) is covered in more detail in a later section.

View File

@ -32,7 +32,7 @@ Introducing Angular pipes, a way to write display-value transformations that you
You can run the <live-example></live-example> in Stackblitz and download the code from there. You can run the <live-example></live-example> in Stackblitz and download the code from there.
运行<live-example></live-example>来试用本页的代码。 你可以运行<live-example></live-example>,在 Stackblitz 中试用并下载本页的代码。
## Using pipes ## Using pipes
@ -249,7 +249,6 @@ Now you need a component to demonstrate the pipe.
现在,你需要一个组件来演示这个管道。 现在,你需要一个组件来演示这个管道。
<code-example path="pipes/src/app/power-booster.component.ts" title="src/app/power-booster.component.ts" linenums="false"> <code-example path="pipes/src/app/power-booster.component.ts" title="src/app/power-booster.component.ts" linenums="false">
</code-example> </code-example>
<figure> <figure>
@ -780,10 +779,8 @@ The list might be sorted by hero `name` and `planet` of origin properties in the
虽然不是很明显,但代码最小化方面也存在风险。想象一个用于英雄列表的排序管道。该列表可能根据英雄原始属性中的 `name``planet` 进行排序,就像这样: 虽然不是很明显,但代码最小化方面也存在风险。想象一个用于英雄列表的排序管道。该列表可能根据英雄原始属性中的 `name``planet` 进行排序,就像这样:
<code-example language="html"> <code-example language="html">
&lt;!-- NOT REAL CODE! --> &lt;!-- NOT REAL CODE! -->
&lt;div *ngFor="let hero of heroes | orderBy:'name,planet'">&lt;/div> &lt;div *ngFor="let hero of heroes | orderBy:'name,planet'">&lt;/div>
</code-example> </code-example>
You identify the sort fields by text strings, expecting the pipe to reference a property value by indexing You identify the sort fields by text strings, expecting the pipe to reference a property value by indexing
@ -817,5 +814,4 @@ Angular 开发组和一些有经验的 Angular 开发者强烈建议你:把你
If these performance and minification considerations don't apply to you, you can always create your own such pipes If these performance and minification considerations don't apply to you, you can always create your own such pipes
(similar to the [FlyingHeroesPipe](guide/pipes#impure-flying-heroes)) or find them in the community. (similar to the [FlyingHeroesPipe](guide/pipes#impure-flying-heroes)) or find them in the community.
如果你不需要顾虑这些性能和最小化问题,也可以创建自己的管道来实现这些功能(参考[FlyingHeroesPipe](guide/pipes#impure-flying-heroes)中的写法)或到社区中去找找。 如果你不需要顾虑这些性能和最小化问题,也可以创建自己的管道来实现这些功能(参考[FlyingHeroesPipe](guide/pipes#impure-flying-heroes)中的写法)或到社区中去找找。

View File

@ -12,7 +12,7 @@
* Familiarity with [Frequently Used Modules](guide/frequent-ngmodules). * Familiarity with [Frequently Used Modules](guide/frequent-ngmodules).
熟悉[常用模块](guide/frequent-ngmodules). 熟悉[常用模块](guide/frequent-ngmodules)
For the final sample app using the provider that this page describes, For the final sample app using the provider that this page describes,
see the <live-example></live-example>. see the <live-example></live-example>.
@ -45,7 +45,6 @@ of the file and adding it to the `providers` array:
这将会创建一个名叫 `UserService` 的服务。你现在要让该服务在你的应用注入器中可用,就要修改 `app.module.ts` 文件。先在文件的顶部导入它,然后把它加入 `providers` 数组中: 这将会创建一个名叫 `UserService` 的服务。你现在要让该服务在你的应用注入器中可用,就要修改 `app.module.ts` 文件。先在文件的顶部导入它,然后把它加入 `providers` 数组中:
<code-example path="providers/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="providers/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
## Provider scope ## Provider scope
@ -101,7 +100,6 @@ the same module cant access it.)
在组件中提供服务,会限定该服务只能在该组件中有效(同一模块中的其它组件不能访问它)。 在组件中提供服务,会限定该服务只能在该组件中有效(同一模块中的其它组件不能访问它)。
<code-example path="providers/src/app/app.component.ts" region="component-providers" title="src/app/app.component.ts" linenums="false"> <code-example path="providers/src/app/app.component.ts" region="component-providers" title="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
## Providing services in modules vs. components ## Providing services in modules vs. components
@ -132,7 +130,7 @@ Register a provider with a component when you must limit a service instance to a
You may also be interested in: You may also be interested in:
你可能对下列内容感兴趣: 可能对下列内容感兴趣:
* [Singleton Services](guide/singleton-services), which elaborates on the concepts covered on this page. * [Singleton Services](guide/singleton-services), which elaborates on the concepts covered on this page.
@ -140,8 +138,8 @@ You may also be interested in:
* [Lazy Loading Modules](guide/lazy-loading-ngmodules). * [Lazy Loading Modules](guide/lazy-loading-ngmodules).
[惰性加载模块](guide/lazy-loading-ngmodules). [惰性加载模块](guide/lazy-loading-ngmodules)
* [NgModule FAQ](guide/ngmodule-faq). * [NgModule FAQ](guide/ngmodule-faq).
[NgModule 常见问题](guide/ngmodule-faq)。 [NgModule 常见问题](guide/ngmodule-faq)。

View File

@ -59,7 +59,6 @@ Then **install the [Angular CLI](https://github.com/angular/angular-cli)** globa
然后全局安装 **[Angular CLI](https://github.com/angular/angular-cli)** 。 然后全局安装 **[Angular CLI](https://github.com/angular/angular-cli)** 。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm install -g @angular/cli npm install -g @angular/cli
</code-example> </code-example>
@ -77,7 +76,6 @@ Generate a new project and skeleton application by running the following command
运行下列命令来生成一个新项目以及应用的骨架代码: 运行下列命令来生成一个新项目以及应用的骨架代码:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng new my-app ng new my-app
</code-example> </code-example>
@ -101,10 +99,8 @@ Go to the project directory and launch the server.
进入项目目录,并启动服务器。 进入项目目录,并启动服务器。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
cd my-app cd my-app
ng serve --open ng serve --open
</code-example> </code-example>
The `ng serve` command launches the server, watches your files, The `ng serve` command launches the server, watches your files,
@ -282,7 +278,6 @@ Any files outside of this folder are meant to support building your app.
</col> </col>
<col width="80%"> <col width="80%">
</col> </col>
<tr> <tr>
<th> <th>
@ -302,7 +297,6 @@ Any files outside of this folder are meant to support building your app.
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -323,7 +317,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -345,7 +338,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -364,7 +356,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -385,14 +376,13 @@ Any files outside of this folder are meant to support building your app.
这个文件夹中包括为各个目标环境准备的文件,它们导出了一些应用中要用到的配置变量。 这个文件夹中包括为各个目标环境准备的文件,它们导出了一些应用中要用到的配置变量。
这些文件会在构建应用时被替换。 这些文件会在构建应用时被替换。
比如你可能在产环境中使用不同的 API 端点地址,或使用不同的统计 Token 参数。 比如你可能在产环境中使用不同的 API 端点地址,或使用不同的统计 Token 参数。
甚至使用一些模拟服务。 甚至使用一些模拟服务。
所有这些CLI 都替你考虑到了。 所有这些CLI 都替你考虑到了。
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -412,7 +402,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -435,7 +424,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -459,7 +447,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -482,7 +469,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -503,7 +489,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -524,7 +509,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -543,7 +527,6 @@ Any files outside of this folder are meant to support building your app.
</td> </td>
</tr> </tr>
</table> </table>
### The root folder ### The root folder
@ -610,7 +593,6 @@ These files go in the root folder next to `src/`.
</col> </col>
<col width="80%"> <col width="80%">
</col> </col>
<tr> <tr>
<th> <th>
@ -625,12 +607,11 @@ These files go in the root folder next to `src/`.
Purpose Purpose
目的 用途
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -653,7 +634,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -672,7 +652,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -695,7 +674,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -717,7 +695,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -735,7 +712,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -754,7 +730,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -774,7 +749,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -793,7 +767,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -814,7 +787,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -832,7 +804,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -853,7 +824,6 @@ These files go in the root folder next to `src/`.
</td> </td>
</tr> </tr>
</table> </table>
<div class="l-sub-section"> <div class="l-sub-section">

View File

@ -427,7 +427,7 @@ This guide uses four fundamental classes to build a reactive form:
`FormControl`, `FormGroup`, and `FormArray`. `FormControl`, `FormGroup`, and `FormArray`.
It provides their common behaviors and properties. It provides their common behaviors and properties.
[`AbstractControl`](api/forms/AbstractControl "API Reference: FormControl")是这三个具体表单类的抽象基类。 [`AbstractControl`](api/forms/AbstractControl "API Reference: FormControl")是这三个具体表单类的抽象基类。
并为它们提供了一些共同的行为和属性。 并为它们提供了一些共同的行为和属性。
</td> </td>
@ -1156,7 +1156,6 @@ which is covered in the section on [`FormArray`](guide/reactive-forms#form-array
`Hero` 有一个住址数组。这个表单模型只表示了一个住址,稍后的 [`FormArray`] (guide/reactive-forms#form-array "Form arrays")则可以表示多个。 `Hero` 有一个住址数组。这个表单模型只表示了一个住址,稍后的 [`FormArray`] (guide/reactive-forms#form-array "Form arrays")则可以表示多个。
Keeping the two models close in shape facilitates copying the data model properties Keeping the two models close in shape facilitates copying the data model properties
to the form model with the `patchValue()` and `setValue()` methods in the next section. to the form model with the `patchValue()` and `setValue()` methods in the next section.

View File

@ -214,7 +214,6 @@ _after_ a `RouterOutlet` that you've placed in the host view's HTML.
有了这份配置,当本应用在浏览器中的 URL 变为 `/heroes` 时,路由器就会匹配到 `path``heroes``Route`,并在宿主视图中的*`RouterOutlet`*之后显示 `HeroListComponent` 组件。 有了这份配置,当本应用在浏览器中的 URL 变为 `/heroes` 时,路由器就会匹配到 `path``heroes``Route`,并在宿主视图中的*`RouterOutlet`*之后显示 `HeroListComponent` 组件。
<code-example language="html"> <code-example language="html">
&lt;router-outlet>&lt;/router-outlet> &lt;router-outlet>&lt;/router-outlet>
&lt;!-- Routed views go here --> &lt;!-- Routed views go here -->
@ -294,7 +293,6 @@ It has a great deal of useful information including:
它有一大堆有用的信息,包括: 它有一大堆有用的信息,包括:
<table> <table>
<tr> <tr>
<th> <th>
@ -496,7 +494,6 @@ It has a great deal of useful information including:
</td> </td>
</tr> </tr>
</table> </table>
<div class="l-sub-section"> <div class="l-sub-section">
@ -525,7 +522,6 @@ During each navigation, the `Router` emits navigation events through the `Router
在每次导航中,`Router` 都会通过 `Router.events` 属性发布一些导航事件。这些事件的范围涵盖了从开始导航到结束导航之间的很多时间点。下表中列出了全部导航事件: 在每次导航中,`Router` 都会通过 `Router.events` 属性发布一些导航事件。这些事件的范围涵盖了从开始导航到结束导航之间的很多时间点。下表中列出了全部导航事件:
<table> <table>
<tr> <tr>
<th> <th>
@ -674,7 +670,6 @@ During each navigation, the `Router` emits navigation events through the `Router
</td> </td>
</tr> </tr>
</table> </table>
These events are logged to the console when the `enableTracing` option is enabled also. Since the events are provided as an `Observable`, you can `filter()` for events of interest and `subscribe()` to them to make decisions based on the sequence of events in the navigation process. These events are logged to the console when the `enableTracing` option is enabled also. Since the events are provided as an `Observable`, you can `filter()` for events of interest and `subscribe()` to them to make decisions based on the sequence of events in the navigation process.
@ -748,8 +743,6 @@ Here are the key `Router` terms and their meanings:
<code>RouterModule</code> <code>RouterModule</code>
<code>RouterModule</code>(路由器模块)
</td> </td>
<td> <td>
@ -1218,7 +1211,6 @@ That's why the example code replaces the `<base href...>` with a script that wri
这就是为什么范例代码中要用一个脚本动态写入 `<base>` 标签,而不是直接写 `<base href...>` 这就是为什么范例代码中要用一个脚本动态写入 `<base>` 标签,而不是直接写 `<base href...>`
<code-example language="html"> <code-example language="html">
&lt;script>document.write('&lt;base href="' + document.location + '" />');&lt;/script> &lt;script>document.write('&lt;base href="' + document.location + '" />');&lt;/script>
</code-example> </code-example>
@ -1344,7 +1336,7 @@ The corresponding component template looks like this:
### *RouterOutlet* ### *RouterOutlet*
### *RouterOutlet* 指令 ### 路由出口
The `RouterOutlet` is a directive from the router library that marks The `RouterOutlet` is a directive from the router library that marks
the spot in the template where the router should display the views for that outlet. the spot in the template where the router should display the views for that outlet.
@ -1525,9 +1517,7 @@ When the application launches, the initial URL in the browser bar is something l
应用启动时,浏览器地址栏中的初始 URL 是这样的: 应用启动时,浏览器地址栏中的初始 URL 是这样的:
<code-example> <code-example>
localhost:3000 localhost:3000
</code-example> </code-example>
That doesn't match any of the concrete configured routes which means That doesn't match any of the concrete configured routes which means
@ -1560,7 +1550,6 @@ It's just above the wildcard route in the following excerpt showing the complete
在下方的代码片段中,它出现在通配符路由的紧上方,展示了这个里程碑的完整 `appRoutes` 在下方的代码片段中,它出现在通配符路由的紧上方,展示了这个里程碑的完整 `appRoutes`
<code-example path="router/src/app/app-routing.module.1.ts" linenums="false" title="src/app/app-routing.module.ts (appRoutes)" region="appRoutes"> <code-example path="router/src/app/app-routing.module.1.ts" linenums="false" title="src/app/app-routing.module.ts (appRoutes)" region="appRoutes">
</code-example> </code-example>
A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route. A redirect route requires a `pathMatch` property to tell the router how to match a URL to the path of a route.
@ -2361,7 +2350,6 @@ you expect a hero id to appear in the browser URL like this:
如果要告诉路由器导航到详情组件并让它显示“Magneta”你会期望这个英雄的 `id` 像这样显示在浏览器的 URL 中: 如果要告诉路由器导航到详情组件并让它显示“Magneta”你会期望这个英雄的 `id` 像这样显示在浏览器的 URL 中:
<code-example format="nocode"> <code-example format="nocode">
localhost:3000/hero/15 localhost:3000/hero/15
</code-example> </code-example>
@ -2505,7 +2493,6 @@ to handle parameter access for both route parameters (`paramMap`) and query para
`ParamMap` API 是参照[URLSearchParams 接口](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)来设计的。它提供了一些方法来处理对路由参数(`paramMap`)和查询参数(`queryParamMap`)中的参数访问。 `ParamMap` API 是参照[URLSearchParams 接口](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)来设计的。它提供了一些方法来处理对路由参数(`paramMap`)和查询参数(`queryParamMap`)中的参数访问。
<table> <table>
<tr> <tr>
<th> <th>
@ -2597,7 +2584,6 @@ to handle parameter access for both route parameters (`paramMap`) and query para
</td> </td>
</tr> </tr>
</table> </table>
{@a reuse} {@a reuse}
@ -2745,7 +2731,6 @@ as you do when navigating to the `HeroDetailComponent` in order to view the hero
如果想导航到 `HeroDetailComponent` 以对 id 为 15 的英雄进行查看并编辑,就要在路由的 URL 中使用[*路由参数*](guide/router#route-parameters)来指定*必要*参数值。 如果想导航到 `HeroDetailComponent` 以对 id 为 15 的英雄进行查看并编辑,就要在路由的 URL 中使用[*路由参数*](guide/router#route-parameters)来指定*必要*参数值。
<code-example format="nocode"> <code-example format="nocode">
localhost:3000/hero/15 localhost:3000/hero/15
</code-example> </code-example>
@ -2866,7 +2851,6 @@ It should look something like this, depending on where you run it:
它应该是这样的,不过也取决于你在哪里运行它: 它应该是这样的,不过也取决于你在哪里运行它:
<code-example language="bash"> <code-example language="bash">
localhost:3000/heroes;id=15;foo=foo localhost:3000/heroes;id=15;foo=foo
</code-example> </code-example>
@ -3413,7 +3397,6 @@ Add the following `crisis-center.component.ts` to the `crisis-center` folder:
`crisis-center` 目录下添加下列 `crisis-center.component.ts` 文件: `crisis-center` 目录下添加下列 `crisis-center.component.ts` 文件:
<code-example path="router/src/app/crisis-center/crisis-center.component.ts" linenums="false" title="src/app/crisis-center/crisis-center.component.ts"> <code-example path="router/src/app/crisis-center/crisis-center.component.ts" linenums="false" title="src/app/crisis-center/crisis-center.component.ts">
</code-example> </code-example>
The `CrisisCenterComponent` has the following in common with the `AppComponent`: The `CrisisCenterComponent` has the following in common with the `AppComponent`:
@ -3455,7 +3438,6 @@ As a host page for the "Crisis Center" feature, add the following `crisis-center
把下面这个 `crisis-center-home.component.ts` 添加到 `crisis-center` 目录下,作为 "危机中心" 特性区的宿主页面。 把下面这个 `crisis-center-home.component.ts` 添加到 `crisis-center` 目录下,作为 "危机中心" 特性区的宿主页面。
<code-example path="router/src/app/crisis-center/crisis-center-home.component.ts" linenums="false" title="src/app/crisis-center/crisis-center-home.component.ts" > <code-example path="router/src/app/crisis-center/crisis-center-home.component.ts" linenums="false" title="src/app/crisis-center/crisis-center-home.component.ts" >
</code-example> </code-example>
Create a `crisis-center-routing.module.ts` file as you did the `heroes-routing.module.ts` file. Create a `crisis-center-routing.module.ts` file as you did the `heroes-routing.module.ts` file.
@ -3465,7 +3447,6 @@ This time, you define **child routes** *within* the parent `crisis-center` route
但这次,你要把**子路由**定义在父路由 `crisis-center` 中。 但这次,你要把**子路由**定义在父路由 `crisis-center` 中。
<code-example path="router/src/app/crisis-center/crisis-center-routing.module.1.ts" linenums="false" title="src/app/crisis-center/crisis-center-routing.module.ts (Routes)" region="routes"> <code-example path="router/src/app/crisis-center/crisis-center-routing.module.1.ts" linenums="false" title="src/app/crisis-center/crisis-center-routing.module.ts (Routes)" region="routes">
</code-example> </code-example>
Notice that the parent `crisis-center` route has a `children` property Notice that the parent `crisis-center` route has a `children` property
@ -3529,7 +3510,6 @@ The absolute URL for the latter example, including the `localhost` origin, is
本例子中包含站点部分的绝对 URL就是 本例子中包含站点部分的绝对 URL就是
<code-example> <code-example>
localhost:3000/crisis-center/2 localhost:3000/crisis-center/2
</code-example> </code-example>
@ -3882,7 +3862,6 @@ you should see something like the following URL in the browser address bar.
导航到*危机中心*并点击“Contact”你将会在浏览器的地址栏看到如下 URL 导航到*危机中心*并点击“Contact”你将会在浏览器的地址栏看到如下 URL
<code-example> <code-example>
http://.../crisis-center(popup:compose) http://.../crisis-center(popup:compose)
</code-example> </code-example>
@ -3908,9 +3887,7 @@ Click the _Heroes_ link and look at the URL again.
点击 *Heroes* 链接,并再次查看 URL 点击 *Heroes* 链接,并再次查看 URL
<code-example> <code-example>
http://.../heroes(popup:compose) http://.../heroes(popup:compose)
</code-example> </code-example>
The primary navigation part has changed; the secondary route is the same. The primary navigation part has changed; the secondary route is the same.
@ -5723,7 +5700,6 @@ Here's the *Crisis Center* URL in this "HTML5 pushState" style:
下面是*危机中心*的 URL 在“HTML 5 pushState”风格下的样子 下面是*危机中心*的 URL 在“HTML 5 pushState”风格下的样子
<code-example format="nocode"> <code-example format="nocode">
localhost:3002/crisis-center/ localhost:3002/crisis-center/
</code-example> </code-example>
@ -5736,7 +5712,6 @@ URLs with hashes. Here's a "hash URL" that routes to the *Crisis Center*.
老旧的浏览器在当前地址的 URL 变化时总会往服务器发送页面请求……唯一的例外规则是:当这些变化位于“#”被称为“hash”后面时不会发送。通过把应用内的路由 URL 拼接在 `#` 之后,路由器可以获得这条“例外规则”带来的优点。下面是到*危机中心*路由的“hash URL” 老旧的浏览器在当前地址的 URL 变化时总会往服务器发送页面请求……唯一的例外规则是:当这些变化位于“#”被称为“hash”后面时不会发送。通过把应用内的路由 URL 拼接在 `#` 之后,路由器可以获得这条“例外规则”带来的优点。下面是到*危机中心*路由的“hash URL”
<code-example format="nocode"> <code-example format="nocode">
localhost:3002/src/#/crisis-center/ localhost:3002/src/#/crisis-center/
</code-example> </code-example>

View File

@ -15,7 +15,7 @@ For more information about the attacks and mitigations described below, see [OWA
You can run the <live-example></live-example> in Stackblitz and download the code from there. You can run the <live-example></live-example> in Stackblitz and download the code from there.
运行<live-example></live-example>来试用本页的代码。 你可以运行<live-example></live-example>,在 Stackblitz 中试用并下载本页的代码。
<h2 id='report-issues'>Reporting vulnerabilities</h2> <h2 id='report-issues'>Reporting vulnerabilities</h2>
@ -426,6 +426,5 @@ must be audited as such. Angular-specific APIs that should be audited in a secur
such as the [_bypassSecurityTrust_](guide/security#bypass-security-apis) methods, are marked in the documentation such as the [_bypassSecurityTrust_](guide/security#bypass-security-apis) methods, are marked in the documentation
as security sensitive. as security sensitive.
Angular 应用应该遵循和常规 Web 应用一样的安全原则并按照这些原则进行审计。Angular 中某些应该在安全评审中被审计的 API Angular 应用应该遵循和常规 Web 应用一样的安全原则并按照这些原则进行审计。Angular 中某些应该在安全评审中被审计的 API
比如[_bypassSecurityTrust_](guide/security#bypass-security-apis) API都在文档中被明确标记为安全性敏感的。 比如[_bypassSecurityTrust_](guide/security#bypass-security-apis) API都在文档中被明确标记为安全性敏感的。

View File

@ -16,7 +16,7 @@ A basic understanding of the following:
* [Getting Started with Service Workers](guide/service-worker-getting-started). * [Getting Started with Service Workers](guide/service-worker-getting-started).
[Service Worker 快速起步](guide/service-worker-getting-started). [Service Worker 快速起步](guide/service-worker-getting-started)
<hr /> <hr />
@ -101,8 +101,8 @@ Doing this could break lazy-loading into currently running apps, especially if t
You may also be interested in the following: You may also be interested in the following:
你可能对下列内容感兴趣: 你可能对下列内容感兴趣:
* [Service Worker in Production](guide/service-worker-devops). * [Service Worker in Production](guide/service-worker-devops).
[环境下的 Service Worker](guide/service-worker-devops). [产环境下的 Service Worker](guide/service-worker-devops)

View File

@ -14,7 +14,7 @@ A basic understanding of the following:
* [Service Worker in Production](guide/service-worker-devops). * [Service Worker in Production](guide/service-worker-devops).
[环境下的 Service Worker](guide/service-worker-devops). [产环境下的 Service Worker](guide/service-worker-devops)
<hr /> <hr />
@ -313,5 +313,4 @@ Angular Service Worker 可以使用两种缓存策略之一来获取数据资源
* `freshness` optimizes for currency of data, preferentially fetching requested data from the network. Only if the network times out, according to `timeout`, does the request fall back to the cache. This is useful for resources that change frequently; for example, account balances. * `freshness` optimizes for currency of data, preferentially fetching requested data from the network. Only if the network times out, according to `timeout`, does the request fall back to the cache. This is useful for resources that change frequently; for example, account balances.
`freshness` 为数据的即时性而优化,优先从网络获取请求的数据。只有当网络超时时,请求才会根据 `timeout` 的设置回退到缓存中。这对于那些频繁变化的资源很有用,例如账户余额。 `freshness` 为数据的即时性而优化,优先从网络获取请求的数据。只有当网络超时时,请求才会根据 `timeout` 的设置回退到缓存中。这对于那些频繁变化的资源很有用,例如账户余额。

View File

@ -1,11 +1,11 @@
# Service worker in production # Service worker in production
# 产环境下的 Service Worker # 产环境下的 Service Worker
This page is a reference for deploying and supporting production apps that use the Angular service worker. It explains how the Angular service worker fits into the larger production environment, the service worker's behavior under various conditions, and available recourses and fail-safes. This page is a reference for deploying and supporting production apps that use the Angular service worker. It explains how the Angular service worker fits into the larger production environment, the service worker's behavior under various conditions, and available recourses and fail-safes.
本页讲的是如何使用 Angular Service Worker 发布和支持产环境下的应用。 本页讲的是如何使用 Angular Service Worker 发布和支持产环境下的应用。
它解释了 Angular Service Worker 如何满足大规模产环境的需求、Service Worker 在多种条件下有哪些行为以及有哪些可用的资源和故障保护机制。 它解释了 Angular Service Worker 如何满足大规模产环境的需求、Service Worker 在多种条件下有哪些行为以及有哪些可用的资源和故障保护机制。
#### Prerequisites #### Prerequisites
@ -557,8 +557,8 @@ the past on your site.
You may also be interested in the following: You may also be interested in the following:
你可能对下列内容感兴趣: 你可能对下列内容感兴趣:
* [Service Worker Configuration](guide/service-worker-config). * [Service Worker Configuration](guide/service-worker-config).
[Service Worker 配置](guide/service-worker-config). [Service Worker 配置](guide/service-worker-config)

View File

@ -120,7 +120,7 @@ At the top of the root module, `src/app/app.module.ts`, import `ServiceWorkerMod
Add `ServiceWorkerModule` to the `@NgModule` `imports` array. Use the `register()` helper to take care of registering the service worker, taking care to disable the service worker when not running in production mode. Add `ServiceWorkerModule` to the `@NgModule` `imports` array. Use the `register()` helper to take care of registering the service worker, taking care to disable the service worker when not running in production mode.
`ServiceWorkerModule` 添加到 `@NgModule``imports` 数组中。使用 `register()` 来帮助管理 Service Worker 的注册并在非产环境下运行时禁用 Service Worker。 `ServiceWorkerModule` 添加到 `@NgModule``imports` 数组中。使用 `register()` 来帮助管理 Service Worker 的注册并在非产环境下运行时禁用 Service Worker。
<code-example path="service-worker-getting-started/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-module"> </code-example> <code-example path="service-worker-getting-started/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-module"> </code-example>
@ -367,8 +367,8 @@ Service Worker *在后台*安装好了这个更新后的版本,下次加载或
You may also be interested in the following: You may also be interested in the following:
你可能对下列内容感兴趣: 你可能对下列内容感兴趣:
* [Communicating with service workers](guide/service-worker-communications). * [Communicating with service workers](guide/service-worker-communications).
[与 Service Worker 通讯](guide/service-worker-communications). [与 Service Worker 通讯](guide/service-worker-communications)

View File

@ -122,8 +122,8 @@ The remainder of this Angular documentation specifically addresses the Angular i
You may also be interested in the following: You may also be interested in the following:
你可能还对下列内容感兴趣: 你可能还对下列内容感兴趣:
* [Getting Started with service workers](guide/service-worker-getting-started). * [Getting Started with service workers](guide/service-worker-getting-started).
[Service Worker 快速起步](guide/service-worker-getting-started). [Service Worker 快速起步](guide/service-worker-getting-started)

View File

@ -22,9 +22,7 @@ The obvious approach is to bind a property of the component to the HTML `<title>
显而易见的方法是把组件的属性绑定到 HTML 的 `<title>` 标签上,像这样: 显而易见的方法是把组件的属性绑定到 HTML 的 `<title>` 标签上,像这样:
<code-example format=''> <code-example format=''>
&lt;title&gt;{{This_Does_Not_Work}}&lt;/title&gt; &lt;title&gt;{{This_Does_Not_Work}}&lt;/title&gt;
</code-example> </code-example>
Sorry but that won't work. Sorry but that won't work.
@ -89,11 +87,9 @@ Here's the complete solution:
这里是完整的方案(代码)。 这里是完整的方案(代码)。
<code-tabs> <code-tabs>
<code-pane title="src/main.ts" path="set-document-title/src/main.ts"></code-pane> <code-pane title="src/main.ts" path="set-document-title/src/main.ts"></code-pane>
<code-pane title="src/app/app.module.ts" path="set-document-title/src/app/app.module.ts"></code-pane> <code-pane title="src/app/app.module.ts" path="set-document-title/src/app/app.module.ts"></code-pane>
<code-pane title="src/app/app.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane> <code-pane title="src/app/app.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane>
</code-tabs> </code-tabs>
## Why provide the `Title` service in `bootstrap` ## Why provide the `Title` service in `bootstrap`
@ -116,5 +112,4 @@ you'll have to provide a different `Title` service that understands
the concept of a "document title" for that specific platform. the concept of a "document title" for that specific platform.
Ideally, the application itself neither knows nor cares about the runtime environment. Ideally, the application itself neither knows nor cares about the runtime environment.
你的做法正是如此。这里的 `Title` 服务是 Angular*浏览器平台*的一部分。如果在其它平台上引导应用程序,就得提供另一个专为那个平台准备的 `Title` 服务。 你的做法正是如此。这里的 `Title` 服务是 Angular*浏览器平台*的一部分。如果在其它平台上引导应用程序,就得提供另一个专为那个平台准备的 `Title` 服务。

View File

@ -394,9 +394,7 @@ If you do, this page can help you understand their purpose.
**SystemJS** 模块加载器指定去哪儿查找在 JavaScript 的 `import` 语句中引用的模块。例如: **SystemJS** 模块加载器指定去哪儿查找在 JavaScript 的 `import` 语句中引用的模块。例如:
<code-example language="ts"> <code-example language="ts">
import { Component } from '@angular/core; import { Component } from '@angular/core;
</code-example> </code-example>
Don't touch this file unless you are fully versed in SystemJS configuration. Don't touch this file unless you are fully versed in SystemJS configuration.

View File

@ -32,7 +32,6 @@ Perform the _clone-to-launch_ steps with these terminal commands.
运行下列命令来执行*克隆并启动*步骤。 运行下列命令来执行*克隆并启动*步骤。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
git clone https://github.com/angular/quickstart.git quickstart git clone https://github.com/angular/quickstart.git quickstart
cd quickstart cd quickstart
npm install npm install
@ -61,7 +60,6 @@ and unzip it into your project folder. Then perform the remaining steps with the
并解压到你的项目目录中。然后执行下面的命令完成剩余步骤。 并解压到你的项目目录中。然后执行下面的命令完成剩余步骤。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
cd quickstart cd quickstart
npm install npm install
npm start npm start
@ -103,7 +101,6 @@ Open a terminal window in the project folder and enter the following commands fo
### OS/X (bash) ### OS/X (bash)
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
xargs rm -rf &lt; non-essential-files.osx.txt xargs rm -rf &lt; non-essential-files.osx.txt
rm src/app/*.spec*.ts rm src/app/*.spec*.ts
rm non-essential-files.osx.txt rm non-essential-files.osx.txt
@ -113,7 +110,6 @@ Open a terminal window in the project folder and enter the following commands fo
### Windows ### Windows
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
for /f %i in (non-essential-files.txt) do del %i /F /S /Q for /f %i in (non-essential-files.txt) do del %i /F /S /Q
rd .git /s /q rd .git /s /q
rd e2e /s /q rd e2e /s /q

View File

@ -28,7 +28,7 @@ A basic understanding of the following:
* [Lazy loading modules](guide/lazy-loading-ngmodules). * [Lazy loading modules](guide/lazy-loading-ngmodules).
[惰性加载模块](guide/lazy-loading-ngmodules). [惰性加载模块](guide/lazy-loading-ngmodules)
<!--* Components (#TBD) We dont have a page just on the concept of components, but I think one would be helpful for beginners.--> <!--* Components (#TBD) We dont have a page just on the concept of components, but I think one would be helpful for beginners.-->
@ -123,12 +123,12 @@ To read about sharing services, see [Providers](guide/providers).
You may also be interested in the following: You may also be interested in the following:
你可能还对下列内容感兴趣: 你可能还对下列内容感兴趣:
* [Providers](guide/providers). * [Providers](guide/providers).
[提供商](guide/providers)。 [服务提供商](guide/providers)。
* [Types of Feature Modules](guide/module-types). * [Types of Feature Modules](guide/module-types).
[特性模块的分类](guide/module-types). [特性模块的分类](guide/module-types)

View File

@ -44,7 +44,6 @@ a way of providing services from a designated NgModule.
下面的范例模块习惯上叫做 `CoreModule`。`@NgModule` 用来创建结构良好的基础设施,让你能够在一个指定的模块中提供服务。 下面的范例模块习惯上叫做 `CoreModule`。`@NgModule` 用来创建结构良好的基础设施,让你能够在一个指定的模块中提供服务。
<code-example path="ngmodules/src/app/core/core.module.ts" region="user-service" title="src/app/core/core.module.ts" linenums="false"> <code-example path="ngmodules/src/app/core/core.module.ts" region="user-service" title="src/app/core/core.module.ts" linenums="false">
</code-example> </code-example>
Here, `CoreModule` provides the `UserService`, and because `AppModule` Here, `CoreModule` provides the `UserService`, and because `AppModule`
@ -269,7 +268,6 @@ Here are the two files in their entirety for reference:
以下这两个文件仅供参考: 以下这两个文件仅供参考:
<code-tabs linenums="false"> <code-tabs linenums="false">
<code-pane <code-pane
title="app.module.ts" title="app.module.ts"
path="ngmodules/src/app/app.module.ts"> path="ngmodules/src/app/app.module.ts">
@ -279,7 +277,6 @@ Here are the two files in their entirety for reference:
region="whole-core-module" region="whole-core-module"
path="ngmodules/src/app/core/core.module.ts"> path="ngmodules/src/app/core/core.module.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
<hr> <hr>
@ -298,8 +295,8 @@ You may also be interested in:
* [Lazy Loading Modules](guide/lazy-loading-ngmodules). * [Lazy Loading Modules](guide/lazy-loading-ngmodules).
[惰性加载模块](guide/lazy-loading-ngmodules). [惰性加载模块](guide/lazy-loading-ngmodules)
* [NgModule FAQ](guide/ngmodule-faq). * [NgModule FAQ](guide/ngmodule-faq).
[NgModule 常见问题](guide/ngmodule-faq)。 [NgModule 常见问题](guide/ngmodule-faq)。

View File

@ -723,7 +723,6 @@ It's more like the curly braces in a JavaScript `if`-block:
它不是一个指令、组件、类或接口,更像是 JavaScript 中 `if` 块中的花括号。 它不是一个指令、组件、类或接口,更像是 JavaScript 中 `if` 块中的花括号。
<code-example language="javascript"> <code-example language="javascript">
if (someCondition) { if (someCondition) {
statement1; statement1;
statement2; statement2;

View File

@ -509,10 +509,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Component({ ... }) @Component({ ... })
export class AppComponent { } export class AppComponent { }
</code-example> </code-example>
</td> </td>
@ -530,10 +528,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Component({ ... }) @Component({ ... })
export class HeroesComponent { } export class HeroesComponent { }
</code-example> </code-example>
</td> </td>
@ -551,10 +547,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Component({ ... }) @Component({ ... })
export class HeroListComponent { } export class HeroListComponent { }
</code-example> </code-example>
</td> </td>
@ -572,10 +566,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Component({ ... }) @Component({ ... })
export class HeroDetailComponent { } export class HeroDetailComponent { }
</code-example> </code-example>
</td> </td>
@ -593,10 +585,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Directive({ ... }) @Directive({ ... })
export class ValidationDirective { } export class ValidationDirective { }
</code-example> </code-example>
</td> </td>
@ -614,10 +604,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@NgModule({ ... }) @NgModule({ ... })
export class AppModule export class AppModule
</code-example> </code-example>
</td> </td>
@ -635,10 +623,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Pipe({ name: 'initCaps' }) @Pipe({ name: 'initCaps' })
export class InitCapsPipe implements PipeTransform { } export class InitCapsPipe implements PipeTransform { }
</code-example> </code-example>
</td> </td>
@ -656,10 +642,8 @@ and reference assets of different types.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Injectable() @Injectable()
export class UserProfileService { } export class UserProfileService { }
</code-example> </code-example>
</td> </td>
@ -775,10 +759,8 @@ As always, strive for consistency.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Injectable() @Injectable()
export class HeroDataService { } export class HeroDataService { }
</code-example> </code-example>
</td> </td>
@ -796,10 +778,8 @@ As always, strive for consistency.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Injectable() @Injectable()
export class CreditService { } export class CreditService { }
</code-example> </code-example>
</td> </td>
@ -817,10 +797,8 @@ As always, strive for consistency.
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Injectable() @Injectable()
export class Logger { } export class Logger { }
</code-example> </code-example>
</td> </td>
@ -1126,10 +1104,8 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Pipe({ name: 'ellipsis' }) @Pipe({ name: 'ellipsis' })
export class EllipsisPipe implements PipeTransform { } export class EllipsisPipe implements PipeTransform { }
</code-example> </code-example>
</td> </td>
@ -1147,10 +1123,8 @@ For example, the prefix `toh` represents from **T**our **o**f **H**eroes and the
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@Pipe({ name: 'initCaps' }) @Pipe({ name: 'initCaps' })
export class InitCapsPipe implements PipeTransform { } export class InitCapsPipe implements PipeTransform { }
</code-example> </code-example>
</td> </td>
@ -1520,10 +1494,8 @@ A consistent class and file name convention make these modules easy to spot and
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@NgModule({ ... }) @NgModule({ ... })
export class AppModule { } export class AppModule { }
</code-example> </code-example>
</td> </td>
@ -1541,10 +1513,8 @@ A consistent class and file name convention make these modules easy to spot and
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@NgModule({ ... }) @NgModule({ ... })
export class HeroesModule { } export class HeroesModule { }
</code-example> </code-example>
</td> </td>
@ -1562,10 +1532,8 @@ A consistent class and file name convention make these modules easy to spot and
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@NgModule({ ... }) @NgModule({ ... })
export class VillainsModule { } export class VillainsModule { }
</code-example> </code-example>
</td> </td>
@ -1583,10 +1551,8 @@ A consistent class and file name convention make these modules easy to spot and
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@NgModule({ ... }) @NgModule({ ... })
export class AppRoutingModule { } export class AppRoutingModule { }
</code-example> </code-example>
</td> </td>
@ -1604,10 +1570,8 @@ A consistent class and file name convention make these modules easy to spot and
<td> <td>
<code-example hideCopy class="no-box"> <code-example hideCopy class="no-box">
@NgModule({ ... }) @NgModule({ ... })
export class HeroesRoutingModule { } export class HeroesRoutingModule { }
</code-example> </code-example>
</td> </td>
@ -4667,5 +4631,4 @@ Useful tools and tips for Angular.
<a href="#toc">Back to top</a> <a href="#toc">Back to top</a>
<a href="#toc">回到顶部</a> <a href="#toc">回到顶部</a>

View File

@ -75,7 +75,6 @@ You met the double-curly braces of interpolation, `{{` and `}}`, early in your A
在以前的 Angular 教程中,你遇到过由双花括号括起来的插值表达式,`{{` 和 `}}` 在以前的 Angular 教程中,你遇到过由双花括号括起来的插值表达式,`{{` 和 `}}`
<code-example path="template-syntax/src/app/app.component.html" region="first-interpolation" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="first-interpolation" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments. You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
@ -83,7 +82,6 @@ You use interpolation to weave calculated strings into the text between HTML ele
插值表达式可以把计算后的字符串插入到 HTML 元素标签内的文本或对标签的属性进行赋值。 插值表达式可以把计算后的字符串插入到 HTML 元素标签内的文本或对标签的属性进行赋值。
<code-example path="template-syntax/src/app/app.component.html" region="title+image" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="title+image" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The text between the braces is often the name of a component property. Angular replaces that name with the The text between the braces is often the name of a component property. Angular replaces that name with the
@ -101,7 +99,6 @@ and then **converts to a string**. The following interpolation illustrates the p
下列插值表达式通过把括号中的两个数字相加说明了这一点: 下列插值表达式通过把括号中的两个数字相加说明了这一点:
<code-example path="template-syntax/src/app/app.component.html" region="sum-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="sum-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The expression can invoke methods of the host component such as `getVal()`, seen here: The expression can invoke methods of the host component such as `getVal()`, seen here:
@ -109,7 +106,6 @@ The expression can invoke methods of the host component such as `getVal()`, seen
这个表达式可以调用宿主组件的方法,就像下面用的 `getVal()` 这个表达式可以调用宿主组件的方法,就像下面用的 `getVal()`
<code-example path="template-syntax/src/app/app.component.html" region="sum-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="sum-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Angular evaluates all expressions in double curly braces, Angular evaluates all expressions in double curly braces,
@ -178,7 +174,7 @@ JavaScript 中那些具有或可能引发副作用的表达式是被禁止的,
* increment and decrement operators (`++` and `--`) * increment and decrement operators (`++` and `--`)
自增或自减操作符 (`++` 和 `--`) 自增和自减运算符:`++` 和 `--`
Other notable differences from JavaScript syntax include: Other notable differences from JavaScript syntax include:
@ -206,7 +202,6 @@ In the following snippets, the `title` within double-curly braces and the
在下面的代码片段中,双花括号中的 `title` 和引号中的 `isUnchanged` 所引用的都是 `AppComponent` 中的属性。 在下面的代码片段中,双花括号中的 `title` 和引号中的 `isUnchanged` 所引用的都是 `AppComponent` 中的属性。
<code-example path="template-syntax/src/app/app.component.html" region="context-component-expression" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-component-expression" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
An expression may also refer to properties of the _template's_ context An expression may also refer to properties of the _template's_ context
@ -217,7 +212,6 @@ or a [template reference variable](guide/template-syntax#ref-vars) (`#heroInput`
比如[模板输入变量](guide/template-syntax#template-input-variable) (`let hero`)和[模板引用变量](guide/template-syntax#ref-vars)(`#heroInput`)就是备选的上下文对象之一。 比如[模板输入变量](guide/template-syntax#template-input-variable) (`let hero`)和[模板引用变量](guide/template-syntax#ref-vars)(`#heroInput`)就是备选的上下文对象之一。
<code-example path="template-syntax/src/app/app.component.html" region="context-var" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-var" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The context for terms in an expression is a blend of the _template variables_, The context for terms in an expression is a blend of the _template variables_,
@ -368,7 +362,6 @@ appearing in quotes to the right of the `=`&nbsp;symbol as in `(event)="statemen
模板语句将在[事件绑定](guide/template-syntax#event-binding)一节看到,它出现在 `=` 号右侧的引号中,就像这样:`(event)="statement"`。 模板语句将在[事件绑定](guide/template-syntax#event-binding)一节看到,它出现在 `=` 号右侧的引号中,就像这样:`(event)="statement"`。
<code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
A template statement *has a side effect*. A template statement *has a side effect*.
@ -432,7 +425,6 @@ The *deleteHero* in `(click)="deleteHero()"` is a method of the data-bound compo
`(click)="deleteHero()"` 中的 *deleteHero* 就是这个数据绑定组件上的一个方法。 `(click)="deleteHero()"` 中的 *deleteHero* 就是这个数据绑定组件上的一个方法。
<code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-component-statement" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The statement context may also refer to properties of the template's own context. The statement context may also refer to properties of the template's own context.
@ -445,7 +437,6 @@ are passed to an event handling method of the component.
在下面的例子中,就把模板的 `$event` 对象、[模板输入变量](guide/template-syntax#template-input-variable) (`let hero`)和[模板引用变量](guide/template-syntax#ref-vars) (`#heroForm`)传给了组件中的一个事件处理器方法。 在下面的例子中,就把模板的 `$event` 对象、[模板输入变量](guide/template-syntax#template-input-variable) (`let hero`)和[模板引用变量](guide/template-syntax#ref-vars) (`#heroForm`)传给了组件中的一个事件处理器方法。
<code-example path="template-syntax/src/app/app.component.html" region="context-var-statement" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="context-var-statement" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Template context names take precedence over component context names. Template context names take precedence over component context names.
@ -518,7 +509,6 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
</col> </col>
<col width="20%"> <col width="20%">
</col> </col>
<tr> <tr>
<th> <th>
@ -546,7 +536,6 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -560,11 +549,9 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
<td> <td>
<code-example> <code-example>
{{expression}} {{expression}}
[target]="expression" [target]="expression"
bind-target="expression" bind-target="expression"
</code-example> </code-example>
</td> </td>
@ -598,10 +585,8 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
<td> <td>
<code-example> <code-example>
(target)="statement" (target)="statement"
on-target="statement" on-target="statement"
</code-example> </code-example>
</td> </td>
@ -615,7 +600,6 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -629,10 +613,8 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
<td> <td>
<code-example> <code-example>
[(target)]="expression" [(target)]="expression"
bindon-target="expression" bindon-target="expression"
</code-example> </code-example>
</td> </td>
@ -646,9 +628,7 @@ from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _
</td> </td>
</tr> </tr>
</tr> </tr>
</table> </table>
@ -704,7 +684,6 @@ you modify those elements by setting element attributes with string constants.
通过把字符串常量设置到元素的 attribute 来修改那些元素。 通过把字符串常量设置到元素的 attribute 来修改那些元素。
<code-example path="template-syntax/src/app/app.component.html" region="img+button" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="img+button" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You still create a structure and initialize attribute values this way in Angular templates. You still create a structure and initialize attribute values this way in Angular templates.
@ -717,7 +696,6 @@ and drop them into templates as if they were native HTML elements.
然后,用封装了 HTML 的组件创建新元素,并把它们当作原生 HTML 元素在模板中使用。 然后,用封装了 HTML 的组件创建新元素,并把它们当作原生 HTML 元素在模板中使用。
<code-example path="template-syntax/src/app/app.component.html" region="hero-detail-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="hero-detail-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
That's HTML Plus. That's HTML Plus.
@ -729,7 +707,6 @@ Then you learn about data binding. The first binding you meet might look like th
现在开始学习数据绑定。你碰到的第一种数据绑定是这样的: 现在开始学习数据绑定。你碰到的第一种数据绑定是这样的:
<code-example path="template-syntax/src/app/app.component.html" region="disabled-button-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="disabled-button-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You'll get to that peculiar bracket notation in a moment. Looking beyond it, You'll get to that peculiar bracket notation in a moment. Looking beyond it,
@ -880,7 +857,6 @@ The following table summarizes:
</col> </col>
<col width="75%"> <col width="75%">
</col> </col>
<tr> <tr>
<th> <th>
@ -908,7 +884,6 @@ The following table summarizes:
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -934,13 +909,11 @@ The following table summarizes:
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-syntax-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -966,13 +939,11 @@ The following table summarizes:
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-syntax-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -994,13 +965,11 @@ The following table summarizes:
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="2-way-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="2-way-binding-syntax-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1021,13 +990,11 @@ The following table summarizes:
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="attribute-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="attribute-binding-syntax-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1047,13 +1014,11 @@ The following table summarizes:
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-syntax-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -1073,13 +1038,11 @@ The following table summarizes:
<td> <td>
<code-example path="template-syntax/src/app/app.component.html" region="style-binding-syntax-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="style-binding-syntax-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
</td> </td>
</tr> </tr>
</table> </table>
With this broad view in mind, you're ready to look at binding types in detail. With this broad view in mind, you're ready to look at binding types in detail.
@ -1106,7 +1069,6 @@ binding the `src` property of an image element to a component's `heroImageUrl` p
下面这个例子中image 元素的 `src` 属性会被绑定到组件的 `heroImageUrl` 属性上: 下面这个例子中image 元素的 `src` 属性会被绑定到组件的 `heroImageUrl` 属性上:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Another example is disabling a button when the component says that it `isUnchanged`: Another example is disabling a button when the component says that it `isUnchanged`:
@ -1114,7 +1076,6 @@ Another example is disabling a button when the component says that it `isUnchang
另一个例子是当组件说它 `isUnchanged`(未改变)时禁用按钮: 另一个例子是当组件说它 `isUnchanged`(未改变)时禁用按钮:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Another is setting a property of a directive: Another is setting a property of a directive:
@ -1122,7 +1083,6 @@ Another is setting a property of a directive:
另一个例子是设置指令的属性: 另一个例子是设置指令的属性:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Yet another is setting the model property of a custom component (a great way Yet another is setting the model property of a custom component (a great way
@ -1131,7 +1091,6 @@ for parent and child components to communicate):
还有另一个例子是设置自定义组件的模型属性(这是父子组件之间通讯的重要途径): 还有另一个例子是设置自定义组件的模型属性(这是父子组件之间通讯的重要途径):
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
### One-way *in* ### One-way *in*
@ -1181,7 +1140,6 @@ The target property in the following code is the image element's `src` property.
包裹在方括号中的元素属性名标记着目标属性。下列代码中的目标属性是 image 元素的 `src` 属性。 包裹在方括号中的元素属性名标记着目标属性。下列代码中的目标属性是 image 元素的 `src` 属性。
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Some people prefer the `bind-` prefix alternative, known as the *canonical form*: Some people prefer the `bind-` prefix alternative, known as the *canonical form*:
@ -1189,7 +1147,6 @@ Some people prefer the `bind-` prefix alternative, known as the *canonical form*
有些人喜欢用 `bind-` 前缀的可选形式,并称之为*规范形式* 有些人喜欢用 `bind-` 前缀的可选形式,并称之为*规范形式*
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-5" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-5" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The target name is always the name of a property, even when it appears to be the name of something else. The target name is always the name of a property, even when it appears to be the name of something else.
@ -1205,7 +1162,6 @@ as it is in the following example:
元素属性可能是最常见的绑定目标,但 Angular 会先去看这个名字是否是某个已知指令的属性名,就像下面的例子中一样: 元素属性可能是最常见的绑定目标,但 Angular 会先去看这个名字是否是某个已知指令的属性名,就像下面的例子中一样:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1269,7 +1225,6 @@ The `hero` property of the `HeroDetail` component expects a `Hero` object, which
`HeroDetail` 组件的 `hero` 属性想要一个 `Hero` 对象,那就在属性绑定中精确地给它一个 `Hero` 对象: `HeroDetail` 组件的 `hero` 属性想要一个 `Hero` 对象,那就在属性绑定中精确地给它一个 `Hero` 对象:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-4" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
### Remember the brackets ### Remember the brackets
@ -1290,7 +1245,6 @@ Don't make the following mistake:
不要出现这样的失误: 不要出现这样的失误:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-6" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-6" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
{@a one-time-initialization} {@a one-time-initialization}
@ -1324,7 +1278,6 @@ not a template expression. Angular sets it and forgets about it.
下面这个例子把 `HeroDetailComponent``prefix` 属性初始化为固定的字符串而不是模板表达式。Angular 设置它,然后忘记它。 下面这个例子把 `HeroDetailComponent``prefix` 属性初始化为固定的字符串而不是模板表达式。Angular 设置它,然后忘记它。
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-7" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-7" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property. The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property.
@ -1344,7 +1297,6 @@ The following binding pairs do the same thing:
下列这几对绑定做的事情完全相同: 下列这几对绑定做的事情完全相同:
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
_Interpolation_ is a convenient alternative to _property binding_ in many cases. _Interpolation_ is a convenient alternative to _property binding_ in many cases.
@ -1375,7 +1327,6 @@ Imagine the following *malicious content*.
假设下面的*恶意内容* 假设下面的*恶意内容*
<code-example path="template-syntax/src/app/app.component.ts" region="evil-title" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="evil-title" title="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
Fortunately, Angular data binding is on alert for dangerous HTML. Fortunately, Angular data binding is on alert for dangerous HTML.
@ -1388,7 +1339,6 @@ nor property binding.
不管是插值表达式还是属性绑定,都**不会**允许带有 script 标签的 HTML 泄漏到浏览器中。 不管是插值表达式还是属性绑定,都**不会**允许带有 script 标签的 HTML 泄漏到浏览器中。
<code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation-sanitization" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="property-binding-vs-interpolation-sanitization" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Interpolation handles the script tags differently than property binding but both approaches render the Interpolation handles the script tags differently than property binding but both approaches render the
@ -1453,9 +1403,7 @@ This fact becomes painfully obvious when you write something like this.
如果想写出类似下面这样的东西,就会暴露出痛点了: 如果想写出类似下面这样的东西,就会暴露出痛点了:
<code-example language="html"> <code-example language="html">
&lt;tr&gt;&lt;td colspan="{{1 + 1}}"&gt;Three-Four&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt;&lt;td colspan="{{1 + 1}}"&gt;Three-Four&lt;/td&gt;&lt;/tr&gt;
</code-example> </code-example>
And you get this error: And you get this error:
@ -1463,10 +1411,8 @@ And you get this error:
会得到这个错误: 会得到这个错误:
<code-example format="nocode"> <code-example format="nocode">
Template parse errors: Template parse errors:
Can't bind to 'colspan' since it isn't a known native property Can't bind to 'colspan' since it isn't a known native property
</code-example> </code-example>
As the message says, the `<td>` element does not have a `colspan` property. As the message says, the `<td>` element does not have a `colspan` property.
@ -1494,7 +1440,6 @@ Bind `[attr.colspan]` to a calculated value:
这里把 `[attr.colspan]` 绑定到一个计算值: 这里把 `[attr.colspan]` 绑定到一个计算值:
<code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-colspan" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-colspan" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Here's how the table renders: Here's how the table renders:
@ -1517,16 +1462,10 @@ Here's how the table renders:
<td> <td>
Five Five</td><td>Six
</td> </td>
<td>
Six
</td>
</tr> </tr>
</table> </table>
@ -1538,7 +1477,6 @@ attribute 绑定的主要用例之一是设置 ARIA attribute译注ARIA
就像这个例子中一样: 就像这个例子中一样:
<code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-aria" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="attrib-binding-aria" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<hr/> <hr/>
@ -1566,7 +1504,6 @@ with class bindings. Here's how to set the attribute without binding:
下列例子示范了如何通过 CSS 类绑定来添加和移除应用的 "special" 类。不用绑定直接设置 attribute 时是这样的: 下列例子示范了如何通过 CSS 类绑定来添加和移除应用的 "special" 类。不用绑定直接设置 attribute 时是这样的:
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding. You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding.
@ -1575,7 +1512,6 @@ You can replace that with a binding to a string of the desired class names; this
(译注:即当 badCurly 有值时 class 这个 attribute 设置的内容会被完全覆盖) (译注:即当 badCurly 有值时 class 这个 attribute 设置的内容会被完全覆盖)
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Finally, you can bind to a specific class name. Finally, you can bind to a specific class name.
@ -1586,7 +1522,6 @@ It removes the class when the expression is falsy.
当模板表达式的求值结果是真值时Angular 会添加这个类,反之则移除它。 当模板表达式的求值结果是真值时Angular 会添加这个类,反之则移除它。
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1617,7 +1552,6 @@ followed by a dot (`.`) and the name of a CSS style property: `[style.style-prop
形如:`[style.style-property]`。 形如:`[style.style-property]`。
<code-example path="template-syntax/src/app/app.component.html" region="style-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="style-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Some style binding styles have a unit extension. Some style binding styles have a unit extension.
@ -1626,7 +1560,6 @@ The following example conditionally sets the font size in “em” and “%”
有些样式绑定中的样式带有单位。在这里,以根据条件用 “em” 和 “%” 来设置字体大小的单位。 有些样式绑定中的样式带有单位。在这里,以根据条件用 “em” 和 “%” 来设置字体大小的单位。
<code-example path="template-syntax/src/app/app.component.html" region="style-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="style-binding-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1685,7 +1618,6 @@ the component's `onSave()` method whenever a click occurs:
下面事件绑定监听按钮的点击事件。每当点击发生时,都会调用组件的 `onSave()` 方法。 下面事件绑定监听按钮的点击事件。每当点击发生时,都会调用组件的 `onSave()` 方法。
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
### Target event ### Target event
@ -1698,7 +1630,6 @@ identifies the target event. In the following example, the target is the button'
**圆括号中的名称** —— 比如 `(click)` —— 标记出目标事件。在下面例子中,目标是按钮的 click 事件。 **圆括号中的名称** —— 比如 `(click)` —— 标记出目标事件。在下面例子中,目标是按钮的 click 事件。
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Some people prefer the `on-` prefix alternative, known as the **canonical form**: Some people prefer the `on-` prefix alternative, known as the **canonical form**:
@ -1706,7 +1637,6 @@ Some people prefer the `on-` prefix alternative, known as the **canonical form**
有些人更喜欢带 `on-` 前缀的备选形式,称之为**规范形式** 有些人更喜欢带 `on-` 前缀的备选形式,称之为**规范形式**
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Element events may be the more common targets, but Angular looks first to see if the name matches an event property Element events may be the more common targets, but Angular looks first to see if the name matches an event property
@ -1715,7 +1645,6 @@ of a known directive, as it does in the following example:
元素事件可能是更常见的目标,但 Angular 会先看这个名字是否能匹配上已知指令的事件属性,就像下面这个例子: 元素事件可能是更常见的目标,但 Angular 会先看这个名字是否能匹配上已知指令的事件属性,就像下面这个例子:
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1766,7 +1695,6 @@ Consider this example:
考虑这个范例: 考虑这个范例:
<code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
This code sets the input box `value` property by binding to the `name` property. This code sets the input box `value` property by binding to the `name` property.
@ -1818,11 +1746,9 @@ Here are the pertinent excerpts from that `HeroDetailComponent`:
下面的代码节选自 `HeroDetailComponent` 下面的代码节选自 `HeroDetailComponent`
<code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" title="src/app/hero-detail.component.ts (template)" region="template-1"> <code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" title="src/app/hero-detail.component.ts (template)" region="template-1">
</code-example> </code-example>
<code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" title="src/app/hero-detail.component.ts (deleteRequest)" region="deleteRequest"> <code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" title="src/app/hero-detail.component.ts (deleteRequest)" region="deleteRequest">
</code-example> </code-example>
The component defines a `deleteRequest` property that returns an `EventEmitter`. The component defines a `deleteRequest` property that returns an `EventEmitter`.
@ -1837,7 +1763,6 @@ Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s
现在,假设有个宿主的父组件,它绑定了 `HeroDetailComponent``deleteRequest` 事件。 现在,假设有个宿主的父组件,它绑定了 `HeroDetailComponent``deleteRequest` 事件。
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component">
</code-example> </code-example>
When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method, When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method,
@ -1908,7 +1833,6 @@ It has a `size` value property and a companion `sizeChange` event:
下面的 `SizerComponent` 符合这个模式。它有 `size` 属性和伴随的 `sizeChange` 事件: 下面的 `SizerComponent` 符合这个模式。它有 `size` 属性和伴随的 `sizeChange` 事件:
<code-example path="template-syntax/src/app/sizer.component.ts" title="src/app/sizer.component.ts"> <code-example path="template-syntax/src/app/sizer.component.ts" title="src/app/sizer.component.ts">
</code-example> </code-example>
The initial `size` is an input value from a property binding. The initial `size` is an input value from a property binding.
@ -1924,7 +1848,6 @@ Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the
下面的例子中,`AppComponent.fontSize` 被双向绑定到 `SizerComponent` 下面的例子中,`AppComponent.fontSize` 被双向绑定到 `SizerComponent`
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (two-way-1)" region="two-way-1"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (two-way-1)" region="two-way-1">
</code-example> </code-example>
The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value.
@ -1943,7 +1866,6 @@ Angular _desugars_ the `SizerComponent` binding into this:
Angular 将 `SizerComponent` 的绑定分解成这样: Angular 将 `SizerComponent` 的绑定分解成这样:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (two-way-2)" region="two-way-2"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (two-way-2)" region="two-way-2">
</code-example> </code-example>
The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. The `$event` variable contains the payload of the `SizerComponent.sizeChange` event.
@ -1990,7 +1912,6 @@ Why create a directive to handle a click when you can write a simple binding suc
如果能用简单的绑定达到目的,为什么还要创建指令来处理点击事件呢? 如果能用简单的绑定达到目的,为什么还要创建指令来处理点击事件呢?
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You still benefit from directives that simplify complex tasks. You still benefit from directives that simplify complex tasks.
@ -2060,7 +1981,6 @@ A [class binding](guide/template-syntax#class-binding) is a good way to add or r
[CSS 类绑定](guide/template-syntax#class-binding) 是添加或删除*单个*类的最佳途径。 [CSS 类绑定](guide/template-syntax#class-binding) 是添加或删除*单个*类的最佳途径。
<code-example path="template-syntax/src/app/app.component.html" region="class-binding-3a" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="class-binding-3a" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To add or remove *many* CSS classes at the same time, the `NgClass` directive may be the better choice. To add or remove *many* CSS classes at the same time, the `NgClass` directive may be the better choice.
@ -2080,7 +2000,6 @@ Consider a `setCurrentClasses` component method that sets a component property,
组件方法 `setCurrentClasses` 可以把组件的属性 `currentClasses` 设置为一个对象,它将会根据三个其它组件的状态为 `true``false` 而添加或移除三个类。 组件方法 `setCurrentClasses` 可以把组件的属性 `currentClasses` 设置为一个对象,它将会根据三个其它组件的状态为 `true``false` 而添加或移除三个类。
<code-example path="template-syntax/src/app/app.component.ts" region="setClasses" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="setClasses" title="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
Adding an `ngClass` property binding to `currentClasses` sets the element's classes accordingly: Adding an `ngClass` property binding to `currentClasses` sets the element's classes accordingly:
@ -2088,7 +2007,6 @@ Adding an `ngClass` property binding to `currentClasses` sets the element's clas
`NgClass` 属性绑定到 `currentClasses`,根据它来设置此元素的 CSS 类: `NgClass` 属性绑定到 `currentClasses`,根据它来设置此元素的 CSS 类:
<code-example path="template-syntax/src/app/app.component.html" region="NgClass-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgClass-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -2116,7 +2034,6 @@ A [style binding](guide/template-syntax#style-binding) is an easy way to set a *
[样式绑定](guide/template-syntax#style-binding)是设置*单一*样式值的简单方式。 [样式绑定](guide/template-syntax#style-binding)是设置*单一*样式值的简单方式。
<code-example path="template-syntax/src/app/app.component.html" region="NgStyle-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgStyle-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
To set *many* inline styles at the same time, the `NgStyle` directive may be the better choice. To set *many* inline styles at the same time, the `NgStyle` directive may be the better choice.
@ -2135,7 +2052,6 @@ with an object that defines three styles, based on the state of three other comp
来看看组件的 `setCurrentStyles` 方法,它会根据另外三个属性的状态把组件的 `currentStyles` 属性设置为一个定义了三个样式的对象: 来看看组件的 `setCurrentStyles` 方法,它会根据另外三个属性的状态把组件的 `currentStyles` 属性设置为一个定义了三个样式的对象:
<code-example path="template-syntax/src/app/app.component.ts" region="setStyles" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="setStyles" title="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
Adding an `ngStyle` property binding to `currentStyles` sets the element's styles accordingly: Adding an `ngStyle` property binding to `currentStyles` sets the element's styles accordingly:
@ -2143,7 +2059,6 @@ Adding an `ngStyle` property binding to `currentStyles` sets the element's style
`NgStyle` 属性绑定到 `currentStyles`,以据此设置此元素的样式: `NgStyle` 属性绑定到 `currentStyles`,以据此设置此元素的样式:
<code-example path="template-syntax/src/app/app.component.html" region="NgStyle-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgStyle-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -2172,7 +2087,6 @@ Two-way data binding with the `NgModel` directive makes that easy. Here's an exa
使用 `NgModel` 指令进行双向数据绑定可以简化这种工作。例子如下: 使用 `NgModel` 指令进行双向数据绑定可以简化这种工作。例子如下:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (NgModel-1)" region="NgModel-1"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (NgModel-1)" region="NgModel-1">
</code-example> </code-example>
#### _FormsModule_ is required to use _ngModel_ #### _FormsModule_ is required to use _ngModel_
@ -2192,7 +2106,6 @@ Here's how to import the `FormsModule` to make `[(ngModel)]` available.
导入 `FormsModule` 并让 `[(ngModel)]` 可用的代码如下: 导入 `FormsModule` 并让 `[(ngModel)]` 可用的代码如下:
<code-example path="template-syntax/src/app/app.module.1.ts" linenums="false" title="src/app/app.module.ts (FormsModule import)"> <code-example path="template-syntax/src/app/app.module.1.ts" linenums="false" title="src/app/app.module.ts (FormsModule import)">
</code-example> </code-example>
#### Inside <span class="syntax">[(ngModel)]</span> #### Inside <span class="syntax">[(ngModel)]</span>
@ -2206,7 +2119,6 @@ the `<input>` element's `value` property and `input` event.
回头看看 `name` 绑定,注意,你可以通过分别绑定到 `<input>` 元素的 `value` 属性和 `input` 事件来达到同样的效果。 回头看看 `name` 绑定,注意,你可以通过分别绑定到 `<input>` 元素的 `value` 属性和 `input` 事件来达到同样的效果。
<code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
That's cumbersome. Who can remember which element property to set and which element event emits user changes? That's cumbersome. Who can remember which element property to set and which element event emits user changes?
@ -2221,7 +2133,6 @@ That `ngModel` directive hides these onerous details behind its own `ngModel` i
`ngModel` 指令通过自己的输入属性 `ngModel` 和输出属性 `ngModelChange` 隐藏了那些细节。 `ngModel` 指令通过自己的输入属性 `ngModel` 和输出属性 `ngModelChange` 隐藏了那些细节。
<code-example path="template-syntax/src/app/app.component.html" region="NgModel-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgModel-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -2270,7 +2181,6 @@ with a single declaration, which it can with the `[(ngModel)]` syntax:
你不用被迫两次引用这个数据属性Angular 可以捕获该元素的数据属性,并且通过一个简单的声明来设置它,这样它就可以使用 `[(ngModel)]` 语法了。 你不用被迫两次引用这个数据属性Angular 可以捕获该元素的数据属性,并且通过一个简单的声明来设置它,这样它就可以使用 `[(ngModel)]` 语法了。
<code-example path="template-syntax/src/app/app.component.html" region="NgModel-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgModel-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Is `[(ngModel)]` all you need? Is there ever a reason to fall back to its expanded form? Is `[(ngModel)]` all you need? Is there ever a reason to fall back to its expanded form?
@ -2288,7 +2198,6 @@ The following contrived example forces the input value to uppercase:
下面这个生造的例子强制输入框的内容变成大写: 下面这个生造的例子强制输入框的内容变成大写:
<code-example path="template-syntax/src/app/app.component.html" region="NgModel-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgModel-4" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Here are all variations in action, including the uppercase version: Here are all variations in action, including the uppercase version:
@ -2368,7 +2277,6 @@ Bind the directive to a condition expression like `isActive` in this example.
在下面的例子中,该指令绑定到了类似于 `isActive` 这样的条件表达式。 在下面的例子中,该指令绑定到了类似于 `isActive` 这样的条件表达式。
<code-example path="template-syntax/src/app/app.component.html" region="NgIf-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgIf-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -2395,7 +2303,6 @@ You can control the visibility of an element with a
你也可以通过[类绑定](guide/template-syntax#class-binding)或[样式绑定](guide/template-syntax#style-binding)来显示或隐藏一个元素。 你也可以通过[类绑定](guide/template-syntax#class-binding)或[样式绑定](guide/template-syntax#style-binding)来显示或隐藏一个元素。
<code-example path="template-syntax/src/app/app.component.html" region="NgIf-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgIf-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Hiding an element is quite different from removing an element with `NgIf`. Hiding an element is quite different from removing an element with `NgIf`.
@ -2445,7 +2352,6 @@ The `nullHero` will never be displayed.
`nullHero` 永远不会显示。 `nullHero` 永远不会显示。
<code-example path="template-syntax/src/app/app.component.html" region="NgIf-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgIf-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -2477,7 +2383,6 @@ Here is an example of `NgForOf` applied to a simple `<div>`:
下例中,`NgFor` 应用在一个简单的 `<div>` 上: 下例中,`NgFor` 应用在一个简单的 `<div>` 上:
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can also apply an `NgForOf` to a component element, as in this example: You can also apply an `NgForOf` to a component element, as in this example:
@ -2485,7 +2390,6 @@ You can also apply an `NgForOf` to a component element, as in this example:
也可以把 `NgFor` 应用在一个组件元素上,就下例这样: 也可以把 `NgFor` 应用在一个组件元素上,就下例这样:
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -2552,7 +2456,6 @@ and then passed in a binding to the `hero` property of the `<hero-detail>` compo
这里它首先在一个插值表达式中被引用到,然后通过一个绑定把它传给了 `<hero-detail>` 组件的 `hero` 属性。 这里它首先在一个插值表达式中被引用到,然后通过一个绑定把它传给了 `<hero-detail>` 组件的 `hero` 属性。
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-1-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-1-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Learn more about _template input variables_ in the Learn more about _template input variables_ in the
@ -2575,7 +2478,6 @@ The next example captures the `index` in a variable named `i` and displays it wi
下面这个例子把 `index` 捕获到了 `i` 变量中,并且把它显示在英雄名字的前面。 下面这个例子把 `index` 捕获到了 `i` 变量中,并且把它显示在英雄名字的前面。
<code-example path="template-syntax/src/app/app.component.html" region="NgFor-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgFor-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -2621,7 +2523,6 @@ In this case, that value is the hero's `id`.
在这里,这个值就是英雄的 `id` 在这里,这个值就是英雄的 `id`
<code-example path="template-syntax/src/app/app.component.ts" region="trackByHeroes" title="src/app/app.component.ts" linenums="false"> <code-example path="template-syntax/src/app/app.component.ts" region="trackByHeroes" title="src/app/app.component.ts" linenums="false">
</code-example> </code-example>
In the microsyntax expression, set `trackBy` to this method. In the microsyntax expression, set `trackBy` to this method.
@ -2629,7 +2530,6 @@ In the microsyntax expression, set `trackBy` to this method.
在微语法中,把 `trackBy` 设置为该方法。 在微语法中,把 `trackBy` 设置为该方法。
<code-example path="template-syntax/src/app/app.component.html" region="trackBy" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="trackBy" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Here is an illustration of the _trackBy_ effect. Here is an illustration of the _trackBy_ effect.
@ -2674,7 +2574,6 @@ Angular 只会把*选中的*元素放进 DOM 中。
`NgSwitch` 实际上包括三个相互协作的指令:`NgSwitch`、`NgSwitchCase` 和 `NgSwitchDefault`,例子如下: `NgSwitch` 实际上包括三个相互协作的指令:`NgSwitch`、`NgSwitchCase` 和 `NgSwitchDefault`,例子如下:
<code-example path="template-syntax/src/app/app.component.html" region="NgSwitch" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgSwitch" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<figure> <figure>
@ -2726,7 +2625,6 @@ For example, you could replace the `<confused-hero>` switch case with the follow
比如,你可以把 `<confused-hero>` 分支改成这样: 比如,你可以把 `<confused-hero>` 分支改成这样:
<code-example path="template-syntax/src/app/app.component.html" region="NgSwitch-div" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="NgSwitch-div" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<hr/> <hr/>
@ -2754,7 +2652,6 @@ The `#phone` declares a `phone` variable on an `<input>` element.
`#phone` 的意思就是声明一个名叫 `phone` 的变量来引用 `<input>` 元素。 `#phone` 的意思就是声明一个名叫 `phone` 的变量来引用 `<input>` 元素。
<code-example path="template-syntax/src/app/app.component.html" region="ref-var" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="ref-var" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You can refer to a template reference variable _anywhere_ in the template. You can refer to a template reference variable _anywhere_ in the template.
@ -2765,7 +2662,6 @@ consumed in a `<button>` on the other side of the template
比如声明在 `<input>` 上的 `phone` 变量就是在模板另一侧的 `<button>` 上使用的。 比如声明在 `<input>` 上的 `phone` 变量就是在模板另一侧的 `<button>` 上使用的。
<code-example path="template-syntax/src/app/app.component.html" region="ref-phone" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="ref-phone" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<h3 class="no-toc">How a reference variable gets its value</h3> <h3 class="no-toc">How a reference variable gets its value</h3>
@ -2789,7 +2685,6 @@ The following is a *simplified* version of the form example in the [Forms](guide
下面是[表单](guide/forms)一章中表单范例的*简化版*。 下面是[表单](guide/forms)一章中表单范例的*简化版*。
<code-example path="template-syntax/src/app/hero-form.component.html" title="src/app/hero-form.component.html" linenums="false"> <code-example path="template-syntax/src/app/hero-form.component.html" title="src/app/hero-form.component.html" linenums="false">
</code-example> </code-example>
A template reference variable, `heroForm`, appears three times in this example, separated A template reference variable, `heroForm`, appears three times in this example, separated
@ -2841,7 +2736,6 @@ This example declares the `fax` variable as `ref-fax` instead of `#fax`.
下面的例子中就用把 `fax` 变量声明成了 `ref-fax` 而不是 `#fax` 下面的例子中就用把 `fax` 变量声明成了 `ref-fax` 而不是 `#fax`
<code-example path="template-syntax/src/app/app.component.html" region="ref-fax" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="ref-fax" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
<hr/> <hr/>
@ -2892,7 +2786,6 @@ In such binding expressions, the component's property or method is to the _right
在下面的例子中,`iconUrl` 和 `onSave` 是组件的成员,它们在 `=` 右侧引号语法中被引用了。 在下面的例子中,`iconUrl` 和 `onSave` 是组件的成员,它们在 `=` 右侧引号语法中被引用了。
<code-example path="template-syntax/src/app/app.component.html" region="io-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="io-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `iconUrl` and `onSave` are members of the `AppComponent` class. The `iconUrl` and `onSave` are members of the `AppComponent` class.
@ -2930,7 +2823,6 @@ In the following example, the `AppComponent` template binds `AppComponent` class
下面的例子中,`AppComponent` 的模板把 `AppComponent` 类的成员绑定到了 `HeroDetailComponent`(选择器为 `'app-hero-detail'` 的属性上。 下面的例子中,`AppComponent` 的模板把 `AppComponent` 类的成员绑定到了 `HeroDetailComponent`(选择器为 `'app-hero-detail'` 的属性上。
<code-example path="template-syntax/src/app/app.component.html" region="io-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="io-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The Angular compiler _may_ reject these bindings with errors like this one: The Angular compiler _may_ reject these bindings with errors like this one:
@ -2938,10 +2830,8 @@ The Angular compiler _may_ reject these bindings with errors like this one:
Angular 的编译器*可能*会对这些绑定报错,就像这样: Angular 的编译器*可能*会对这些绑定报错,就像这样:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
Uncaught Error: Template parse errors: Uncaught Error: Template parse errors:
Can't bind to 'hero' since it isn't a known property of 'app-hero-detail' Can't bind to 'hero' since it isn't a known property of 'app-hero-detail'
</code-example> </code-example>
You know that `HeroDetailComponent` has `hero` and `deleteRequest` properties. You know that `HeroDetailComponent` has `hero` and `deleteRequest` properties.
@ -3013,7 +2903,6 @@ because the data bound properties are annotated with `@Input()` and `@Output()`
在本章的例子中,绑定到 `HeroDetailComponent` 不会失败,这是因为这些要进行数据绑定的属性都带有 `@Input()``@Output()` 装饰器。 在本章的例子中,绑定到 `HeroDetailComponent` 不会失败,这是因为这些要进行数据绑定的属性都带有 `@Input()``@Output()` 装饰器。
<code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-1" title="src/app/hero-detail.component.ts" linenums="false"> <code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-1" title="src/app/hero-detail.component.ts" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -3024,7 +2913,6 @@ of the directive metadata, as in this example:
另外,还可以在指令元数据的 `inputs``outputs` 数组中标记出这些成员。比如这个例子: 另外,还可以在指令元数据的 `inputs``outputs` 数组中标记出这些成员。比如这个例子:
<code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-2" title="src/app/hero-detail.component.ts" linenums="false"> <code-example path="template-syntax/src/app/hero-detail.component.ts" region="input-output-2" title="src/app/hero-detail.component.ts" linenums="false">
</code-example> </code-example>
</div> </div>
@ -3077,7 +2965,6 @@ you expect to bind to an event property that is also called `myClick`.
希望绑定的事件属性也叫 `myClick` 希望绑定的事件属性也叫 `myClick`
<code-example path="template-syntax/src/app/app.component.html" region="myClick" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="myClick" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
However, the directive name is often a poor choice for the name of a property within the directive class. However, the directive name is often a poor choice for the name of a property within the directive class.
@ -3101,7 +2988,6 @@ You can specify the alias for the property name by passing it into the input/out
把别名传进@Input/@Output 装饰器,就可以为属性指定别名,就像这样: 把别名传进@Input/@Output 装饰器,就可以为属性指定别名,就像这样:
<code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick" title="src/app/click.directive.ts" linenums="false"> <code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick" title="src/app/click.directive.ts" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -3114,7 +3000,6 @@ the directive property name on the *left* and the public alias on the *right*:
可以写一个冒号 (`:`) 分隔的字符串,*左侧*是指令中的属性名,*右侧*则是公共别名。 可以写一个冒号 (`:`) 分隔的字符串,*左侧*是指令中的属性名,*右侧*则是公共别名。
<code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick2" title="src/app/click.directive.ts" linenums="false"> <code-example path="template-syntax/src/app/click.directive.ts" region="output-myClick2" title="src/app/click.directive.ts" linenums="false">
</code-example> </code-example>
</div> </div>
@ -3153,7 +3038,6 @@ Angular [管道](guide/pipes)对像这样的小型转换来说是个明智的选
它们很容易用于模板表达式中,只要使用**管道操作符 (`|`) **就行了。 它们很容易用于模板表达式中,只要使用**管道操作符 (`|`) **就行了。
<code-example path="template-syntax/src/app/app.component.html" region="pipes-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="pipes-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The pipe operator passes the result of an expression on the left to a pipe function on the right. The pipe operator passes the result of an expression on the left to a pipe function on the right.
@ -3165,7 +3049,6 @@ You can chain expressions through multiple pipes:
还可以通过多个管道串联表达式: 还可以通过多个管道串联表达式:
<code-example path="template-syntax/src/app/app.component.html" region="pipes-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="pipes-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
And you can also [apply parameters](guide/pipes#parameterizing-a-pipe) to a pipe: And you can also [apply parameters](guide/pipes#parameterizing-a-pipe) to a pipe:
@ -3173,7 +3056,6 @@ And you can also [apply parameters](guide/pipes#parameterizing-a-pipe) to a pipe
还能对它们使用参数: 还能对它们使用参数:
<code-example path="template-syntax/src/app/app.component.html" region="pipes-3" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="pipes-3" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `json` pipe is particularly helpful for debugging bindings: The `json` pipe is particularly helpful for debugging bindings:
@ -3181,7 +3063,6 @@ The `json` pipe is particularly helpful for debugging bindings:
`json` 管道对调试绑定特别有用: `json` 管道对调试绑定特别有用:
<code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (pipes-json)" region="pipes-json"> <code-example path="template-syntax/src/app/app.component.html" linenums="false" title="src/app/app.component.html (pipes-json)" region="pipes-json">
</code-example> </code-example>
The generated output would look something like this The generated output would look something like this
@ -3189,12 +3070,10 @@ The generated output would look something like this
它生成的输出是这样的: 它生成的输出是这样的:
<code-example language="json"> <code-example language="json">
{ "id": 0, "name": "Hercules", "emotion": "happy", { "id": 0, "name": "Hercules", "emotion": "happy",
"birthdate": "1970-02-25T08:00:00.000Z", "birthdate": "1970-02-25T08:00:00.000Z",
"url": "http://www.imdb.com/title/tt0065832/", "url": "http://www.imdb.com/title/tt0065832/",
"rate": 325 } "rate": 325 }
</code-example> </code-example>
<hr/> <hr/>
@ -3213,7 +3092,6 @@ Angular 的**安全导航操作符 (`?.`) **是一种流畅而便利的方式,
下例中,当 `currentHero` 为空时,保护视图渲染器,让它免于失败。 下例中,当 `currentHero` 为空时,保护视图渲染器,让它免于失败。
<code-example path="template-syntax/src/app/app.component.html" region="safe-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
What happens when the following data bound `title` property is null? What happens when the following data bound `title` property is null?
@ -3221,7 +3099,6 @@ What happens when the following data bound `title` property is null?
如果下列数据绑定中 `title` 属性为空,会发生什么? 如果下列数据绑定中 `title` 属性为空,会发生什么?
<code-example path="template-syntax/src/app/app.component.html" region="safe-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The view still renders but the displayed value is blank; you see only "The title is" with nothing after it. The view still renders but the displayed value is blank; you see only "The title is" with nothing after it.
@ -3236,9 +3113,7 @@ that displays the `name` of a null hero.
假设模板表达式涉及属性路径,在下例中,显示一个空 (null) 英雄的 `firstName` 假设模板表达式涉及属性路径,在下例中,显示一个空 (null) 英雄的 `firstName`
<code-example language="html"> <code-example language="html">
The null hero's name is {{nullHero.name}} The null hero's name is {{nullHero.name}}
</code-example> </code-example>
JavaScript throws a null reference error, and so does Angular: JavaScript throws a null reference error, and so does Angular:
@ -3246,9 +3121,7 @@ JavaScript throws a null reference error, and so does Angular:
JavaScript 抛出了空引用错误Angular 也是如此: JavaScript 抛出了空引用错误Angular 也是如此:
<code-example format="nocode"> <code-example format="nocode">
TypeError: Cannot read property 'name' of null in [null]. TypeError: Cannot read property 'name' of null in [null].
</code-example> </code-example>
Worse, the *entire view disappears*. Worse, the *entire view disappears*.
@ -3283,7 +3156,6 @@ You could code around that problem with [*ngIf](guide/template-syntax#ngIf).
可以通过用[NgIf](guide/template-syntax#ngIf)代码环绕它来解决这个问题。 可以通过用[NgIf](guide/template-syntax#ngIf)代码环绕它来解决这个问题。
<code-example path="template-syntax/src/app/app.component.html" region="safe-4" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-4" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
You could try to chain parts of the property path with `&&`, knowing that the expression bails out You could try to chain parts of the property path with `&&`, knowing that the expression bails out
@ -3292,7 +3164,6 @@ when it encounters the first null.
或者可以尝试通过 `&&` 来把属性路径的各部分串起来,让它在遇到第一个空值的时候,就返回空。 或者可以尝试通过 `&&` 来把属性路径的各部分串起来,让它在遇到第一个空值的时候,就返回空。
<code-example path="template-syntax/src/app/app.component.html" region="safe-5" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-5" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
These approaches have merit but can be cumbersome, especially if the property path is long. These approaches have merit but can be cumbersome, especially if the property path is long.
@ -3310,7 +3181,6 @@ Angular 安全导航操作符 (`?.`) 是在属性路径中保护空值的更加
显示是空的,但应用正常工作,而没有发生错误。 显示是空的,但应用正常工作,而没有发生错误。
<code-example path="template-syntax/src/app/app.component.html" region="safe-6" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="safe-6" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
It works perfectly with long property paths such as `a?.b?.c?.d`. It works perfectly with long property paths such as `a?.b?.c?.d`.
@ -3352,7 +3222,6 @@ For example, after you use [*ngIf](guide/template-syntax#ngIf) to check that `he
例如,在用[*ngIf](guide/template-syntax#ngIf)来检查过 `hero` 是已定义的之后,就可以断言 `hero` 属性一定是已定义的。 例如,在用[*ngIf](guide/template-syntax#ngIf)来检查过 `hero` 是已定义的之后,就可以断言 `hero` 属性一定是已定义的。
<code-example path="template-syntax/src/app/app.component.html" region="non-null-assertion-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="non-null-assertion-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
When the Angular compiler turns your template into TypeScript code, When the Angular compiler turns your template into TypeScript code,
@ -3390,7 +3259,6 @@ the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/b
有时候,绑定表达式可能会报类型错误,并且它不能或很难指定类型。要消除这种报错,你可以使用 `$any` 转换函数来把表达式转换成 [`any` 类型](http://www.typescriptlang.org/docs/handbook/basic-types.html#any)。 有时候,绑定表达式可能会报类型错误,并且它不能或很难指定类型。要消除这种报错,你可以使用 `$any` 转换函数来把表达式转换成 [`any` 类型](http://www.typescriptlang.org/docs/handbook/basic-types.html#any)。
<code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-1" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-1" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
In this example, when the Angular compiler turns your template into TypeScript code, In this example, when the Angular compiler turns your template into TypeScript code,
@ -3405,7 +3273,6 @@ the component.
`$any` 转换函数可以和 `this` 联合使用,以便访问组件中未声明过的成员。 `$any` 转换函数可以和 `this` 联合使用,以便访问组件中未声明过的成员。
<code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-2" title="src/app/app.component.html" linenums="false"> <code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-2" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
The `$any` cast function can be used anywhere in a binding expression where a method call is valid. The `$any` cast function can be used anywhere in a binding expression where a method call is valid.
@ -3419,5 +3286,4 @@ The `$any` cast function can be used anywhere in a binding expression where a me
You've completed this survey of template syntax. You've completed this survey of template syntax.
Now it's time to put that knowledge to work on your own components and directives. Now it's time to put that knowledge to work on your own components and directives.
你完成了模板语法的概述。现在,该把如何写组件和指令的知识投入到实际工作当中了。 你完成了模板语法的概述。现在,该把如何写组件和指令的知识投入到实际工作当中了。

View File

@ -39,9 +39,7 @@ Just run this one CLI command:
运行下列 CLI 命令即可: 运行下列 CLI 命令即可:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng test ng test
</code-example> </code-example>
The `ng test` command builds the app in _watch mode_, The `ng test` command builds the app in _watch mode_,
@ -54,14 +52,12 @@ The console output looks a bit like this:
它的控制台输出一般是这样的: 它的控制台输出一般是这样的:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
10% building modules 1/1 modules 0 active 10% building modules 1/1 modules 0 active
...INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/ ...INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
...INFO [launcher]: Launching browser Chrome ... ...INFO [launcher]: Launching browser Chrome ...
...INFO [launcher]: Starting browser Chrome ...INFO [launcher]: Starting browser Chrome
...INFO [Chrome ...]: Connected on socket ... ...INFO [Chrome ...]: Connected on socket ...
Chrome ...: Executed 3 of 3 SUCCESS (0.135 secs / 0.205 secs) Chrome ...: Executed 3 of 3 SUCCESS (0.135 secs / 0.205 secs)
</code-example> </code-example>
The last line of the log is the most important. The last line of the log is the most important.
@ -286,7 +282,6 @@ array of the services that you'll test or mock.
path="testing/src/app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts"
region="value-service-before-each" region="value-service-before-each"
title="app/demo/demo.testbed.spec.ts (provide ValueService in beforeEach"> title="app/demo/demo.testbed.spec.ts (provide ValueService in beforeEach">
</code-example> </code-example>
Then inject it inside a test by calling `TestBed.get()` with the service class as the argument. Then inject it inside a test by calling `TestBed.get()` with the service class as the argument.
@ -296,7 +291,6 @@ Then inject it inside a test by calling `TestBed.get()` with the service class a
<code-example <code-example
path="testing/src/app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts"
region="value-service-inject-it"> region="value-service-inject-it">
</code-example> </code-example>
Or inside the `beforeEach()` if you prefer to inject the service as part of your setup. Or inside the `beforeEach()` if you prefer to inject the service as part of your setup.
@ -306,7 +300,6 @@ Or inside the `beforeEach()` if you prefer to inject the service as part of your
<code-example <code-example
path="testing/src/app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts"
region="value-service-inject-before-each"> region="value-service-inject-before-each">
</code-example> </code-example>
When testing a service with a dependency, provide the mock in the `providers` array. When testing a service with a dependency, provide the mock in the `providers` array.
@ -320,7 +313,6 @@ In the following example, the mock is a spy object.
<code-example <code-example
path="testing/src/app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts"
region="master-service-before-each" linenums="false"> region="master-service-before-each" linenums="false">
</code-example> </code-example>
The test consumes that spy in the same way it did earlier. The test consumes that spy in the same way it did earlier.
@ -330,7 +322,6 @@ The test consumes that spy in the same way it did earlier.
<code-example <code-example
path="testing/src/app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts"
region="master-service-it"> region="master-service-it">
</code-example> </code-example>
{@a no-before-each} {@a no-before-each}
@ -361,7 +352,6 @@ Begin by putting re-usable, preparatory code in a _setup_ function instead of `b
path="testing/src/app/demo/demo.spec.ts" path="testing/src/app/demo/demo.spec.ts"
region="no-before-each-setup" region="no-before-each-setup"
title="app/demo/demo.spec.ts (setup)" linenums="false"> title="app/demo/demo.spec.ts (setup)" linenums="false">
</code-example> </code-example>
The `setup()` function returns an object literal The `setup()` function returns an object literal
@ -380,7 +370,6 @@ with steps that manipulate the test subject and assert expectations.
<code-example <code-example
path="testing/src/app/demo/demo.spec.ts" path="testing/src/app/demo/demo.spec.ts"
region="no-before-each-test" linenums="false"> region="no-before-each-test" linenums="false">
</code-example> </code-example>
Notice how the test uses Notice how the test uses
@ -393,7 +382,6 @@ to extract the setup variables that it needs.
<code-example <code-example
path="testing/src/app/demo/demo.spec.ts" path="testing/src/app/demo/demo.spec.ts"
region="no-before-each-setup-call"> region="no-before-each-setup-call">
</code-example> </code-example>
Many developers feel this approach is cleaner and more explicit than the Many developers feel this approach is cleaner and more explicit than the
@ -427,7 +415,6 @@ test any service with a dependency.
path="testing/src/app/model/hero.service.spec.ts" path="testing/src/app/model/hero.service.spec.ts"
region="test-with-spies" region="test-with-spies"
title="app/model/hero.service.spec.ts (tests with spies)"> title="app/model/hero.service.spec.ts (tests with spies)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -521,7 +508,6 @@ Consider this `LightswitchComponent` which toggles a light on and off
path="testing/src/app/demo/demo.ts" path="testing/src/app/demo/demo.ts"
region="LightswitchComp" region="LightswitchComp"
title="app/demo/demo.ts (LightswitchComp)" linenums="false"> title="app/demo/demo.ts (LightswitchComp)" linenums="false">
</code-example> </code-example>
You might decide only to test that the `clicked()` method You might decide only to test that the `clicked()` method
@ -542,7 +528,6 @@ Do the same with the component class.
path="testing/src/app/demo/demo.spec.ts" path="testing/src/app/demo/demo.spec.ts"
region="Lightswitch" region="Lightswitch"
title="app/demo/demo.spec.ts (Lightswitch tests)" linenums="false"> title="app/demo/demo.spec.ts (Lightswitch tests)" linenums="false">
</code-example> </code-example>
Here is the `DashboardHeroComponent` from the _Tour of Heroes_ tutorial. Here is the `DashboardHeroComponent` from the _Tour of Heroes_ tutorial.
@ -553,7 +538,6 @@ Here is the `DashboardHeroComponent` from the _Tour of Heroes_ tutorial.
path="testing/src/app/dashboard/dashboard-hero.component.ts" path="testing/src/app/dashboard/dashboard-hero.component.ts"
region="class" region="class"
title="app/dashboard/dashboard-hero.component.ts (component)" linenums="false"> title="app/dashboard/dashboard-hero.component.ts (component)" linenums="false">
</code-example> </code-example>
It appears within the template of a parent component, It appears within the template of a parent component,
@ -571,7 +555,6 @@ or its parent component.
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="class-only" region="class-only"
title="app/dashboard/dashboard-hero.component.spec.ts (class tests)" linenums="false"> title="app/dashboard/dashboard-hero.component.spec.ts (class tests)" linenums="false">
</code-example> </code-example>
When a component has dependencies, you may wish to use the `TestBed` to both When a component has dependencies, you may wish to use the `TestBed` to both
@ -587,7 +570,6 @@ The following `WelcomeComponent` depends on the `UserService` to know the name o
path="testing/src/app/welcome/welcome.component.ts" path="testing/src/app/welcome/welcome.component.ts"
region="class" region="class"
title="app/welcome/welcome.component.ts" linenums="false"> title="app/welcome/welcome.component.ts" linenums="false">
</code-example> </code-example>
You might start by creating a mock of the `UserService` that meets the minimum needs of this component. You might start by creating a mock of the `UserService` that meets the minimum needs of this component.
@ -598,7 +580,6 @@ You might start by creating a mock of the `UserService` that meets the minimum n
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="mock-user-service" region="mock-user-service"
title="app/welcome/welcome.component.spec.ts (MockUserService)" linenums="false"> title="app/welcome/welcome.component.spec.ts (MockUserService)" linenums="false">
</code-example> </code-example>
Then provide and inject _both the_ **component** _and the service_ in the `TestBed` configuration. Then provide and inject _both the_ **component** _and the service_ in the `TestBed` configuration.
@ -609,7 +590,6 @@ Then provide and inject _both the_ **component** _and the service_ in the `TestB
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="class-only-before-each" region="class-only-before-each"
title="app/welcome/welcome.component.spec.ts (class-only setup)" linenums="false"> title="app/welcome/welcome.component.spec.ts (class-only setup)" linenums="false">
</code-example> </code-example>
Then exercise the component class, remembering to call the [lifecycle hook methods](guide/lifecycle-hooks) as Angular does when running the app. Then exercise the component class, remembering to call the [lifecycle hook methods](guide/lifecycle-hooks) as Angular does when running the app.
@ -620,7 +600,6 @@ Then exercise the component class, remembering to call the [lifecycle hook metho
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="class-only-tests" region="class-only-tests"
title="app/welcome/welcome.component.spec.ts (class-only tests)" linenums="false"> title="app/welcome/welcome.component.spec.ts (class-only tests)" linenums="false">
</code-example> </code-example>
### Component DOM testing ### Component DOM testing
@ -702,9 +681,7 @@ For example, the following CLI command generates a `BannerComponent` in the `app
比如,下列 CLI 命令会在 `app/banner` 文件夹中创建带有内联模板和内联样式的 `BannerComponent` 比如,下列 CLI 命令会在 `app/banner` 文件夹中创建带有内联模板和内联样式的 `BannerComponent`
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component banner --inline-template --inline-style --module app ng generate component banner --inline-template --inline-style --module app
</code-example> </code-example>
It also generates an initial test file for the component, `banner-external.component.spec.ts`, that looks like this: It also generates an initial test file for the component, `banner-external.component.spec.ts`, that looks like this:
@ -715,7 +692,6 @@ It also generates an initial test file for the component, `banner-external.compo
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v1" region="v1"
title="app/banner/banner-external.component.spec.ts (initial)" linenums="false"> title="app/banner/banner-external.component.spec.ts (initial)" linenums="false">
</code-example> </code-example>
#### Reduce the setup #### Reduce the setup
@ -741,7 +717,6 @@ For now, you can radically reduce this test file to a more manageable size:
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v2" region="v2"
title="app/banner/banner-initial.component.spec.ts (minimal)" linenums="false"> title="app/banner/banner-initial.component.spec.ts (minimal)" linenums="false">
</code-example> </code-example>
In this example, the metadata object passed to `TestBed.configureTestingModule` In this example, the metadata object passed to `TestBed.configureTestingModule`
@ -752,7 +727,6 @@ simply declares `BannerComponent`, the component to test.
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="configureTestingModule"> region="configureTestingModule">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -784,7 +758,6 @@ After configuring `TestBed`, you call its `createComponent()` method.
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="createComponent"> region="createComponent">
</code-example> </code-example>
`TestBed.createComponent()` creates an instance of the `BannerComponent`, `TestBed.createComponent()` creates an instance of the `BannerComponent`,
@ -829,7 +802,6 @@ Access the component instance through the fixture and confirm it exists with a J
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="componentInstance"> region="componentInstance">
</code-example> </code-example>
#### _beforeEach()_ #### _beforeEach()_
@ -845,7 +817,6 @@ you refactor to pull the setup into a Jasmine `beforeEach()` and some supporting
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v3" region="v3"
linenums="false"> linenums="false">
</code-example> </code-example>
Now add a test that gets the component's element from `fixture.nativeElement` and Now add a test that gets the component's element from `fixture.nativeElement` and
@ -856,7 +827,6 @@ looks for the expected text.
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v4-test-2"> region="v4-test-2">
</code-example> </code-example>
{@a native-element} {@a native-element}
@ -896,7 +866,6 @@ Here's another test that calls `HTMLElement.querySelector` to get the paragraph
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v4-test-3"> region="v4-test-3">
</code-example> </code-example>
{@a debug-element} {@a debug-element}
@ -910,7 +879,6 @@ Angular 的*夹具*可以通过 `fixture.nativeElement` 直接提供组件的元
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="nativeElement"> region="nativeElement">
</code-example> </code-example>
This is actually a convenience method, implemented as `fixture.debugElement.nativeElement`. This is actually a convenience method, implemented as `fixture.debugElement.nativeElement`.
@ -920,7 +888,6 @@ This is actually a convenience method, implemented as `fixture.debugElement.nati
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="debugElement-nativeElement"> region="debugElement-nativeElement">
</code-example> </code-example>
There's a good reason for this circuitous path to the element. There's a good reason for this circuitous path to the element.
@ -956,7 +923,6 @@ Here's the previous test, re-implemented with `fixture.debugElement.nativeElemen
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v4-test-4"> region="v4-test-4">
</code-example> </code-example>
The `DebugElement` has other methods and properties that The `DebugElement` has other methods and properties that
@ -971,7 +937,6 @@ You import the `DebugElement` symbol from the Angular core library.
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="import-debug-element"> region="import-debug-element">
</code-example> </code-example>
{@a by-css} {@a by-css}
@ -1003,7 +968,6 @@ library for the runtime platform. Here's the `By` import for the browser platfor
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="import-by"> region="import-by">
</code-example> </code-example>
The following example re-implements the previous test with The following example re-implements the previous test with
@ -1014,7 +978,6 @@ The following example re-implements the previous test with
<code-example <code-example
path="testing/src/app/banner/banner-initial.component.spec.ts" path="testing/src/app/banner/banner-initial.component.spec.ts"
region="v4-test-5"> region="v4-test-5">
</code-example> </code-example>
Some noteworthy observations: Some noteworthy observations:
@ -1073,7 +1036,6 @@ the component's `title` property like this.
path="testing/src/app/banner/banner.component.ts" path="testing/src/app/banner/banner.component.ts"
region="component" region="component"
title="app/banner/banner.component.ts" linenums="false"> title="app/banner/banner.component.ts" linenums="false">
</code-example> </code-example>
Simple as this is, you decide to add a test to confirm that component Simple as this is, you decide to add a test to confirm that component
@ -1099,7 +1061,6 @@ and assign it to the `h1` variable.
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="setup" region="setup"
title="app/banner/banner.component.spec.ts (setup)" linenums="false"> title="app/banner/banner.component.spec.ts (setup)" linenums="false">
</code-example> </code-example>
{@a detect-changes} {@a detect-changes}
@ -1117,7 +1078,6 @@ Your instinct is to write a test that immediately inspects the `<h1>` like this:
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="expect-h1-default-v1"> region="expect-h1-default-v1">
</code-example> </code-example>
_That test fails_ with the message: _That test fails_ with the message:
@ -1148,7 +1108,6 @@ a fact confirmed in the revised test:
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" region="test-w-o-detect-changes" linenums="false"> path="testing/src/app/banner/banner.component.spec.ts" region="test-w-o-detect-changes" linenums="false">
</code-example> </code-example>
#### _detectChanges()_ #### _detectChanges()_
@ -1162,7 +1121,6 @@ Only then does the `<h1>` have the expected title.
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="expect-h1-default"> region="expect-h1-default">
</code-example> </code-example>
Delayed change detection is intentional and useful. Delayed change detection is intentional and useful.
@ -1179,7 +1137,6 @@ Here's another test that changes the component's `title` property _before_ calli
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="after-change"> region="after-change">
</code-example> </code-example>
{@a auto-detect-changes} {@a auto-detect-changes}
@ -1293,7 +1250,6 @@ as the following variant of `BannerComponent` does.
path="testing/src/app/banner/banner-external.component.ts" path="testing/src/app/banner/banner-external.component.ts"
region="metadata" region="metadata"
title="app/banner/banner-external.component.ts (metadata)" linenums="false"> title="app/banner/banner-external.component.ts (metadata)" linenums="false">
</code-example> </code-example>
This syntax tells the Angular compiler to read the external files during component compilation. This syntax tells the Angular compiler to read the external files during component compilation.
@ -1313,11 +1269,9 @@ For example, if you run the `BannerComponent` tests in a web coding environment
比如,如果你在像 [plunker](http://plnkr.co/) 这样的 Web 编程环境下运行 `BannerComponent` 的测试,就会看到如下信息: 比如,如果你在像 [plunker](http://plnkr.co/) 这样的 Web 编程环境下运行 `BannerComponent` 的测试,就会看到如下信息:
<code-example language="sh" class="code-shell" hideCopy> <code-example language="sh" class="code-shell" hideCopy>
Error: This test module uses the component BannerComponent Error: This test module uses the component BannerComponent
which is using a "templateUrl" or "styleUrls", but they were never compiled. which is using a "templateUrl" or "styleUrls", but they were never compiled.
Please call "TestBed.compileComponents" before your test. Please call "TestBed.compileComponents" before your test.
</code-example> </code-example>
You get this test failure message when the runtime environment You get this test failure message when the runtime environment
@ -1392,7 +1346,6 @@ and its tests:
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="user-service-stub" region="user-service-stub"
title="app/welcome/welcome.component.spec.ts" linenums="false"> title="app/welcome/welcome.component.spec.ts" linenums="false">
</code-example> </code-example>
{@a get-injected-service} {@a get-injected-service}
@ -1423,7 +1376,6 @@ The component injector is a property of the fixture's `DebugElement`.
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="injected-service" region="injected-service"
title="WelcomeComponent's injector"> title="WelcomeComponent's injector">
</code-example> </code-example>
{@a testbed-get} {@a testbed-get}
@ -1447,7 +1399,6 @@ so it is safe to call `TestBed.get()` as follows:
path="testing/src/app/welcome/welcome.component.spec.ts" path="testing/src/app/welcome/welcome.component.spec.ts"
region="inject-from-testbed" region="inject-from-testbed"
title="TestBed injector"> title="TestBed injector">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1537,7 +1488,6 @@ The `TwainComponent` displays Mark Twain quotes.
path="testing/src/app/twain/twain.component.ts" path="testing/src/app/twain/twain.component.ts"
region="template" region="template"
title="app/twain/twain.component.ts (template)" linenums="false"> title="app/twain/twain.component.ts (template)" linenums="false">
</code-example> </code-example>
Note that value of the component's `quote` property passes through an `AsyncPipe`. Note that value of the component's `quote` property passes through an `AsyncPipe`.
@ -1555,7 +1505,6 @@ the `quote` property returns an `Observable`.
path="testing/src/app/twain/twain.component.ts" path="testing/src/app/twain/twain.component.ts"
region="get-quote" region="get-quote"
title="app/twain/twain.component.ts (getQuote)" linenums="false"> title="app/twain/twain.component.ts (getQuote)" linenums="false">
</code-example> </code-example>
The `TwainComponent` gets quotes from an injected `TwainService`. The `TwainComponent` gets quotes from an injected `TwainService`.
@ -1593,7 +1542,6 @@ They should emulate such calls. The setup in this `app/twain/twain.component.spe
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="setup" region="setup"
title="app/twain/twain.component.spec.ts (setup)" linenums="false"> title="app/twain/twain.component.spec.ts (setup)" linenums="false">
</code-example> </code-example>
{@a service-spy} {@a service-spy}
@ -1605,7 +1553,6 @@ Focus on the spy.
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="spy"> region="spy">
</code-example> </code-example>
The spy is designed such that any call to `getQuote` receives an Observable with a test quote. The spy is designed such that any call to `getQuote` receives an Observable with a test quote.
@ -1633,7 +1580,6 @@ you can often turn asynchronous processes into synchronous tests.
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="sync-test"> region="sync-test">
</code-example> </code-example>
Because the spy result returns synchronously, the `getQuote()` method updates Because the spy result returns synchronously, the `getQuote()` method updates
@ -1665,7 +1611,6 @@ The following test confirms the expected behavior when the service returns an `E
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="error-test"> region="error-test">
</code-example> </code-example>
Note that the `it()` function receives an argument of the following form. Note that the `it()` function receives an argument of the following form.
@ -1733,7 +1678,6 @@ from the `getQuote()` spy like this.
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="async-setup"> region="async-setup">
</code-example> </code-example>
#### Async observable helpers #### Async observable helpers
@ -1751,7 +1695,6 @@ Or you can copy this one from the sample code.
path="testing/src/testing/async-observable-helpers.ts" path="testing/src/testing/async-observable-helpers.ts"
region="async-data" region="async-data"
title="testing/async-observable-helpers.ts"> title="testing/async-observable-helpers.ts">
</code-example> </code-example>
This helper's observable emits the `data` value in the next turn of the JavaScript engine. This helper's observable emits the `data` value in the next turn of the JavaScript engine.
@ -1781,7 +1724,6 @@ There's a similar helper for producing an async error.
<code-example <code-example
path="testing/src/testing/async-observable-helpers.ts" path="testing/src/testing/async-observable-helpers.ts"
region="async-error"> region="async-error">
</code-example> </code-example>
#### More async tests #### More async tests
@ -1801,7 +1743,6 @@ in the real world.
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="fake-async-test"> region="fake-async-test">
</code-example> </code-example>
Notice that the quote element displays the placeholder value (`'...'`) after `ngOnInit()`. Notice that the quote element displays the placeholder value (`'...'`) after `ngOnInit()`.
@ -1855,7 +1796,6 @@ Here's the previous `fakeAsync()` test, re-written with the `async()` utility.
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="async-test"> region="async-test">
</code-example> </code-example>
The `async()` utility hides some asynchronous boilerplate by arranging for the tester's code The `async()` utility hides some asynchronous boilerplate by arranging for the tester's code
@ -1928,7 +1868,6 @@ The first one subscribes to the `Observable` exposed to the template by the comp
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="quote-done-test" linenums="false"> region="quote-done-test" linenums="false">
</code-example> </code-example>
The RxJS `last()` operator emits the observable's last value before completing, which will be the test quote. The RxJS `last()` operator emits the observable's last value before completing, which will be the test quote.
@ -1951,7 +1890,6 @@ can give you that information and make assertions about the state of the view.
<code-example <code-example
path="testing/src/app/twain/twain.component.spec.ts" path="testing/src/app/twain/twain.component.spec.ts"
region="spy-done-test" linenums="false"> region="spy-done-test" linenums="false">
</code-example> </code-example>
<hr> <hr>
@ -2003,7 +1941,6 @@ Then import the symbols you need.
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="import-marbles" region="import-marbles"
title="app/twain/twain.component.marbles.spec.ts (import marbles)" linenums="false"> title="app/twain/twain.component.marbles.spec.ts (import marbles)" linenums="false">
</code-example> </code-example>
Here's the complete test for getting a quote: Here's the complete test for getting a quote:
@ -2013,7 +1950,6 @@ Here's the complete test for getting a quote:
<code-example <code-example
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="get-quote-test" linenums="false"> region="get-quote-test" linenums="false">
</code-example> </code-example>
Notice that the Jasmine test is synchronous. There's no `fakeAsync()`. Notice that the Jasmine test is synchronous. There's no `fakeAsync()`.
@ -2036,7 +1972,6 @@ In the second argument you map the value marker (`x`) to the emitted value (`tes
<code-example <code-example
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="test-quote-marbles" linenums="false"> region="test-quote-marbles" linenums="false">
</code-example> </code-example>
The marble library constructs the corresponding observable, which the The marble library constructs the corresponding observable, which the
@ -2052,7 +1987,6 @@ you tell the `TestScheduler` to _flush_ its queue of prepared tasks like this.
<code-example <code-example
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="test-scheduler-flush" linenums="false"> region="test-scheduler-flush" linenums="false">
</code-example> </code-example>
This step serves a purpose analogous to `tick()` and `whenStable()` in the This step serves a purpose analogous to `tick()` and `whenStable()` in the
@ -2073,7 +2007,6 @@ Here's the marble testing version of the `getQuote()` error test.
<code-example <code-example
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="error-test" linenums="false"> region="error-test" linenums="false">
</code-example> </code-example>
It's still an async test, calling `fakeAsync()` and `tick()`, because the component itself It's still an async test, calling `fakeAsync()` and `tick()`, because the component itself
@ -2088,7 +2021,6 @@ Look at the marble observable definition.
<code-example <code-example
path="testing/src/app/twain/twain.component.marbles.spec.ts" path="testing/src/app/twain/twain.component.marbles.spec.ts"
region="error-marbles" linenums="false"> region="error-marbles" linenums="false">
</code-example> </code-example>
This is a _cold_ observable that waits three frames and then emits an error, This is a _cold_ observable that waits three frames and then emits an error,
@ -2172,7 +2104,6 @@ The `DashboardHeroComponent` is embedded in the `DashboardComponent` template li
path="testing/src/app/dashboard/dashboard.component.html" path="testing/src/app/dashboard/dashboard.component.html"
region="dashboard-hero" region="dashboard-hero"
title="app/dashboard/dashboard.component.html (excerpt)" linenums="false"> title="app/dashboard/dashboard.component.html (excerpt)" linenums="false">
</code-example> </code-example>
The `DashboardHeroComponent` appears in an `*ngFor` repeater, which sets each component's `hero` input property The `DashboardHeroComponent` appears in an `*ngFor` repeater, which sets each component's `hero` input property
@ -2190,7 +2121,6 @@ Here's the component's full definition:
path="testing/src/app/dashboard/dashboard-hero.component.ts" path="testing/src/app/dashboard/dashboard-hero.component.ts"
region="component" region="component"
title="app/dashboard/dashboard-hero.component.ts (component)" linenums="false"> title="app/dashboard/dashboard-hero.component.ts (component)" linenums="false">
</code-example> </code-example>
While testing a component this simple has little intrinsic value, it's worth knowing how. While testing a component this simple has little intrinsic value, it's worth knowing how.
@ -2219,7 +2149,6 @@ A quick look at the `DashboardComponent` constructor discourages the first appro
path="testing/src/app/dashboard/dashboard.component.ts" path="testing/src/app/dashboard/dashboard.component.ts"
region="ctor" region="ctor"
title="app/dashboard/dashboard.component.ts (constructor)" linenums="false"> title="app/dashboard/dashboard.component.ts (constructor)" linenums="false">
</code-example> </code-example>
The `DashboardComponent` depends on the Angular router and the `HeroService`. The `DashboardComponent` depends on the Angular router and the `HeroService`.
@ -2258,7 +2187,6 @@ Here's the meat of the spec file setup.
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="setup" region="setup"
title="app/dashboard/dashboard-hero.component.spec.ts (setup)" linenums="false"> title="app/dashboard/dashboard-hero.component.spec.ts (setup)" linenums="false">
</code-example> </code-example>
Note how the setup code assigns a test hero (`expectedHero`) to the component's `hero` property, Note how the setup code assigns a test hero (`expectedHero`) to the component's `hero` property,
@ -2274,7 +2202,6 @@ The following test verifies that the hero name is propagated to the template via
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="name-test"> region="name-test">
</code-example> </code-example>
Because the [template](#dashboard-hero-component) passes the hero name through the Angular `UpperCasePipe`, Because the [template](#dashboard-hero-component) passes the hero name through the Angular `UpperCasePipe`,
@ -2306,7 +2233,6 @@ the host component (`DashboardComponent` presumably) can hear:
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="click-test"> region="click-test">
</code-example> </code-example>
The component's `selected` property returns an `EventEmitter`, The component's `selected` property returns an `EventEmitter`,
@ -2353,7 +2279,6 @@ The test triggered a "click" event with a `null` event object.
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" region="trigger-event-handler"> path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" region="trigger-event-handler">
</code-example> </code-example>
The test assumes (correctly in this case) that the runtime The test assumes (correctly in this case) that the runtime
@ -2386,7 +2311,6 @@ which is perfectly fine for _this component_.
<code-example <code-example
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="click-test-2"> region="click-test-2">
</code-example> </code-example>
{@a click-helper} {@a click-helper}
@ -2408,7 +2332,6 @@ in a helper such as the `click()` function below:
path="testing/src/testing/index.ts" path="testing/src/testing/index.ts"
region="click-event" region="click-event"
title="testing/index.ts (click helper)" linenums="false"> title="testing/index.ts (click helper)" linenums="false">
</code-example> </code-example>
The first parameter is the _element-to-click_. If you wish, you can pass a The first parameter is the _element-to-click_. If you wish, you can pass a
@ -2441,7 +2364,6 @@ Here's the previous test, rewritten using the click helper.
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="click-test-3" region="click-test-3"
title="app/dashboard/dashboard-hero.component.spec.ts (test with click helper)"> title="app/dashboard/dashboard-hero.component.spec.ts (test with click helper)">
</code-example> </code-example>
<hr> <hr>
@ -2479,7 +2401,6 @@ that can be made satisfactorily with a _test host_ like this one:
region="test-host" region="test-host"
title="app/dashboard/dashboard-hero.component.spec.ts (test host)" title="app/dashboard/dashboard-hero.component.spec.ts (test host)"
linenums="false"> linenums="false">
</code-example> </code-example>
This test host binds to `DashboardHeroComponent` as the `DashboardComponent` would This test host binds to `DashboardHeroComponent` as the `DashboardComponent` would
@ -2542,7 +2463,6 @@ The tests themselves are almost identical to the stand-alone version:
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="test-host-tests" region="test-host-tests"
title="app/dashboard/dashboard-hero.component.spec.ts (test-host)" linenums="false"> title="app/dashboard/dashboard-hero.component.spec.ts (test-host)" linenums="false">
</code-example> </code-example>
Only the selected event test differs. It confirms that the selected `DashboardHeroComponent` hero Only the selected event test differs. It confirms that the selected `DashboardHeroComponent` hero
@ -2576,7 +2496,6 @@ which it injects together with the `HeroService`.
path="testing/src/app/dashboard/dashboard.component.ts" path="testing/src/app/dashboard/dashboard.component.ts"
region="ctor" region="ctor"
title="app/dashboard/dashboard.component.ts (constructor)" linenums="false"> title="app/dashboard/dashboard.component.ts (constructor)" linenums="false">
</code-example> </code-example>
Mocking the `HeroService` with a spy is a [familiar story](#component-with-async-service). Mocking the `HeroService` with a spy is a [familiar story](#component-with-async-service).
@ -2593,7 +2512,6 @@ Fortunately, not in this case because the `DashboardComponent` isn't doing much
path="testing/src/app/dashboard/dashboard.component.ts" path="testing/src/app/dashboard/dashboard.component.ts"
region="goto-detail" region="goto-detail"
title="app/dashboard/dashboard.component.ts (goToDetail)"> title="app/dashboard/dashboard.component.ts (goToDetail)">
</code-example> </code-example>
This is often the case with _routing components_. This is often the case with _routing components_.
@ -2612,7 +2530,6 @@ as providing a `HeroService` spy.
path="testing/src/app/dashboard/dashboard.component.spec.ts" path="testing/src/app/dashboard/dashboard.component.spec.ts"
region="router-spy" region="router-spy"
title="app/dashboard/dashboard.component.spec.ts (spies)" linenums="false"> title="app/dashboard/dashboard.component.spec.ts (spies)" linenums="false">
</code-example> </code-example>
The following test clicks the displayed hero and confirms that The following test clicks the displayed hero and confirms that
@ -2624,7 +2541,6 @@ The following test clicks the displayed hero and confirms that
path="testing/src/app/dashboard/dashboard.component.spec.ts" path="testing/src/app/dashboard/dashboard.component.spec.ts"
region="navigate-test" region="navigate-test"
title="app/dashboard/dashboard.component.spec.ts (navigate test)" linenums="false"> title="app/dashboard/dashboard.component.spec.ts (navigate test)" linenums="false">
</code-example> </code-example>
{@a routed-component-w-param} {@a routed-component-w-param}
@ -2728,7 +2644,6 @@ The following `ActivatedRouteStub` class serves as a test double for `ActivatedR
path="testing/src/testing/activated-route-stub.ts" path="testing/src/testing/activated-route-stub.ts"
region="activated-route-stub" region="activated-route-stub"
title="testing/activated-route-stub.ts (ActivatedRouteStub)" linenums="false"> title="testing/activated-route-stub.ts (ActivatedRouteStub)" linenums="false">
</code-example> </code-example>
Consider placing such helpers in a `testing` folder sibling to the `app` folder. Consider placing such helpers in a `testing` folder sibling to the `app` folder.
@ -2798,7 +2713,6 @@ New heroes have `id=0` and a blank `name`. This test confirms that the component
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="route-no-id" region="route-no-id"
title="app/hero/hero-detail.component.spec.ts (no id)" linenums="false"> title="app/hero/hero-detail.component.spec.ts (no id)" linenums="false">
</code-example> </code-example>
<hr> <hr>
@ -2824,7 +2738,6 @@ The `AppComponent`, for example, displays a navigation bar with anchors and thei
<code-example <code-example
path="testing/src/app/app.component.html" path="testing/src/app/app.component.html"
title="app/app.component.html" linenums="false"> title="app/app.component.html" linenums="false">
</code-example> </code-example>
While the `AppComponent` _class_ is empty, While the `AppComponent` _class_ is empty,
@ -2885,7 +2798,6 @@ and directive that play little or no role in the tests.
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="component-stubs" region="component-stubs"
title="app/app.component.spec.ts (stub declaration)" linenums="false"> title="app/app.component.spec.ts (stub declaration)" linenums="false">
</code-example> </code-example>
The stub selectors match the selectors for the corresponding real components. The stub selectors match the selectors for the corresponding real components.
@ -2902,7 +2814,6 @@ components, directives, and pipes that need to be real.
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="testbed-stubs" region="testbed-stubs"
title="app/app.component.spec.ts (TestBed stubs)" linenums="false"> title="app/app.component.spec.ts (TestBed stubs)" linenums="false">
</code-example> </code-example>
The `AppComponent` is the test subject, so of course you declare the real version. The `AppComponent` is the test subject, so of course you declare the real version.
@ -2930,7 +2841,6 @@ In the second approach, add `NO_ERRORS_SCHEMA` to the `TestBed.schemas` metadata
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="no-errors-schema" region="no-errors-schema"
title="app/app.component.spec.ts (NO_ERRORS_SCHEMA)" linenums="false"> title="app/app.component.spec.ts (NO_ERRORS_SCHEMA)" linenums="false">
</code-example> </code-example>
The `NO_ERRORS_SCHEMA` tells the Angular compiler to ignore unrecognized elements and attributes. The `NO_ERRORS_SCHEMA` tells the Angular compiler to ignore unrecognized elements and attributes.
@ -2992,7 +2902,6 @@ as seen in this example.
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="mixed-setup" region="mixed-setup"
title="app/app.component.spec.ts (mixed setup)" linenums="false"> title="app/app.component.spec.ts (mixed setup)" linenums="false">
</code-example> </code-example>
The Angular compiler creates the `BannerComponentStub` for the `<app-banner>` element The Angular compiler creates the `BannerComponentStub` for the `<app-banner>` element
@ -3026,7 +2935,6 @@ seen in the `AppComponent` template.
path="testing/src/testing/router-link-directive-stub.ts" path="testing/src/testing/router-link-directive-stub.ts"
region="router-link" region="router-link"
title="testing/router-link-directive-stub.ts (RouterLinkDirectiveStub)" linenums="false"> title="testing/router-link-directive-stub.ts (RouterLinkDirectiveStub)" linenums="false">
</code-example> </code-example>
The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property. The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property.
@ -3071,7 +2979,6 @@ A little more setup triggers the initial data binding and gets references to the
path="testing/src/app/app.component.spec.ts" path="testing/src/app/app.component.spec.ts"
region="test-setup" region="test-setup"
title="app/app.component.spec.ts (test setup)" linenums="false"> title="app/app.component.spec.ts (test setup)" linenums="false">
</code-example> </code-example>
Three points of special interest: Three points of special interest:
@ -3099,7 +3006,6 @@ The `AppComponent` links to validate are as follows:
path="testing/src/app/app.component.html" path="testing/src/app/app.component.html"
region="links" region="links"
title="app/app.component.html (navigation links)" linenums="false"> title="app/app.component.html (navigation links)" linenums="false">
</code-example> </code-example>
{@a app-component-tests} {@a app-component-tests}
@ -3194,7 +3100,6 @@ But there's plenty of template complexity even in this simple form.
<code-example <code-example
path="testing/src/app/hero/hero-detail.component.html" title="app/hero/hero-detail.component.html" linenums="false"> path="testing/src/app/hero/hero-detail.component.html" title="app/hero/hero-detail.component.html" linenums="false">
</code-example> </code-example>
Tests that exercise the component need ... Tests that exercise the component need ...
@ -3238,7 +3143,6 @@ Here is such a `Page` class for the `hero-detail.component.spec.ts`
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="page" region="page"
title="app/hero/hero-detail.component.spec.ts (Page)" linenums="false"> title="app/hero/hero-detail.component.spec.ts (Page)" linenums="false">
</code-example> </code-example>
Now the important hooks for component manipulation and inspection are neatly organized and accessible from an instance of `Page`. Now the important hooks for component manipulation and inspection are neatly organized and accessible from an instance of `Page`.
@ -3253,7 +3157,6 @@ A `createComponent` method creates a `page` object and fills in the blanks once
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="create-component" region="create-component"
title="app/hero/hero-detail.component.spec.ts (createComponent)" linenums="false"> title="app/hero/hero-detail.component.spec.ts (createComponent)" linenums="false">
</code-example> </code-example>
The [_HeroDetailComponent_ tests](#tests-w-test-double) in an earlier section demonstrate how `createComponent` and `page` The [_HeroDetailComponent_ tests](#tests-w-test-double) in an earlier section demonstrate how `createComponent` and `page`
@ -3271,7 +3174,6 @@ Here are a few more `HeroDetailComponent` tests to reinforce the point.
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="selected-tests" region="selected-tests"
title="app/hero/hero-detail.component.spec.ts (selected tests)" linenums="false"> title="app/hero/hero-detail.component.spec.ts (selected tests)" linenums="false">
</code-example> </code-example>
<hr> <hr>
@ -3296,11 +3198,9 @@ If you run tests in a **non-CLI environment**, the tests may fail with a message
如果你在**非 CLI 环境**中运行测试,这些测试可能会报错,错误信息如下: 如果你在**非 CLI 环境**中运行测试,这些测试可能会报错,错误信息如下:
<code-example language="sh" class="code-shell" hideCopy> <code-example language="sh" class="code-shell" hideCopy>
Error: This test module uses the component BannerComponent Error: This test module uses the component BannerComponent
which is using a "templateUrl" or "styleUrls", but they were never compiled. which is using a "templateUrl" or "styleUrls", but they were never compiled.
Please call "TestBed.compileComponents" before your test. Please call "TestBed.compileComponents" before your test.
</code-example> </code-example>
The root of the problem is at least one of the components involved in the test The root of the problem is at least one of the components involved in the test
@ -3312,7 +3212,6 @@ the following version of the `BannerComponent` does.
<code-example <code-example
path="testing/src/app/banner/banner-external.component.ts" path="testing/src/app/banner/banner-external.component.ts"
title="app/banner/banner-external.component.ts (external template & css)" linenums="false"> title="app/banner/banner-external.component.ts (external template & css)" linenums="false">
</code-example> </code-example>
The test fails when the `TestBed` tries to create the component. The test fails when the `TestBed` tries to create the component.
@ -3324,7 +3223,6 @@ The test fails when the `TestBed` tries to create the component.
region="configure-and-create" region="configure-and-create"
title="app/banner/banner.component.spec.ts (setup that fails)" title="app/banner/banner.component.spec.ts (setup that fails)"
avoid linenums="false"> avoid linenums="false">
</code-example> </code-example>
Recall that the app hasn't been compiled. Recall that the app hasn't been compiled.
@ -3367,9 +3265,7 @@ you'll see this error message
如果你忘了把测试函数标为异步的(比如忘了像稍后的代码中那样使用 `async()`),就会看到下列错误。 如果你忘了把测试函数标为异步的(比如忘了像稍后的代码中那样使用 `async()`),就会看到下列错误。
<code-example language="sh" class="code-shell" hideCopy> <code-example language="sh" class="code-shell" hideCopy>
Error: ViewDestroyedError: Attempt to use a destroyed view Error: ViewDestroyedError: Attempt to use a destroyed view
</code-example> </code-example>
</div> </div>
@ -3393,7 +3289,6 @@ To follow this pattern, import the `async()` helper with the other testing symbo
<code-example <code-example
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="import-async"> region="import-async">
</code-example> </code-example>
#### The async _beforeEach_ #### The async _beforeEach_
@ -3408,7 +3303,6 @@ Write the first async `beforeEach` like this.
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="async-before-each" region="async-before-each"
title="app/banner/banner-external.component.spec.ts (async beforeEach)" linenums="false"> title="app/banner/banner-external.component.spec.ts (async beforeEach)" linenums="false">
</code-example> </code-example>
The `async()` helper function takes a parameterless function with the body of the setup. The `async()` helper function takes a parameterless function with the body of the setup.
@ -3467,7 +3361,6 @@ which include creating the component and querying for elements to inspect.
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="sync-before-each" region="sync-before-each"
title="app/banner/banner-external.component.spec.ts (synchronous beforeEach)" linenums="false"> title="app/banner/banner-external.component.spec.ts (synchronous beforeEach)" linenums="false">
</code-example> </code-example>
You can count on the test runner to wait for the first asynchronous `beforeEach` to finish before calling the second. You can count on the test runner to wait for the first asynchronous `beforeEach` to finish before calling the second.
@ -3493,7 +3386,6 @@ into a `then(...)` callback.
path="testing/src/app/banner/banner-external.component.spec.ts" path="testing/src/app/banner/banner-external.component.spec.ts"
region="one-before-each" region="one-before-each"
title="app/banner/banner-external.component.spec.ts (one beforeEach)" linenums="false"> title="app/banner/banner-external.component.spec.ts (one beforeEach)" linenums="false">
</code-example> </code-example>
#### _compileComponents()_ is harmless #### _compileComponents()_ is harmless
@ -3529,7 +3421,6 @@ Earlier component tests configured the testing module with a few `declarations`
path="testing/src/app/dashboard/dashboard-hero.component.spec.ts" path="testing/src/app/dashboard/dashboard-hero.component.spec.ts"
region="config-testbed" region="config-testbed"
title="app/dashboard/dashboard-hero.component.spec.ts (configure TestBed)"> title="app/dashboard/dashboard-hero.component.spec.ts (configure TestBed)">
</code-example> </code-example>
The `DashboardComponent` is simple. It needs no help. The `DashboardComponent` is simple. It needs no help.
@ -3576,7 +3467,6 @@ One approach is to configure the testing module from the individual pieces as in
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="setup-forms-module" region="setup-forms-module"
title="app/hero/hero-detail.component.spec.ts (FormsModule setup)" linenums="false"> title="app/hero/hero-detail.component.spec.ts (FormsModule setup)" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -3611,7 +3501,6 @@ The test configuration can use the `SharedModule` too as seen in this alternativ
path="testing/src/app/hero/hero-detail.component.spec.ts" path="testing/src/app/hero/hero-detail.component.spec.ts"
region="setup-shared-module" region="setup-shared-module"
title="app/hero/hero-detail.component.spec.ts (SharedModule setup)" linenums="false"> title="app/hero/hero-detail.component.spec.ts (SharedModule setup)" linenums="false">
</code-example> </code-example>
It's a bit tighter and smaller, with fewer import statements (not shown). It's a bit tighter and smaller, with fewer import statements (not shown).
@ -3743,13 +3632,11 @@ The [overide metadata object](#metadata-override-object) is a generic defined as
它接受两个参数:要改写的组件类(`HeroDetailComponent`),以及用于改写的元数据对象: 它接受两个参数:要改写的组件类(`HeroDetailComponent`),以及用于改写的元数据对象:
<code-example format="." language="javascript"> <code-example format="." language="javascript">
type MetadataOverride<T> = { type MetadataOverride<T> = {
add?: T; add?: T;
remove?: T; remove?: T;
set?: T; set?: T;
}; };
</code-example> </code-example>
A metadata override object can either add-and-remove elements in metadata properties or completely reset those properties. A metadata override object can either add-and-remove elements in metadata properties or completely reset those properties.
@ -3763,13 +3650,11 @@ The type parameter, `T`, is the kind of metadata you'd pass to the `@Component`
这个类型参数,`T`,是你会传递给 `@Component` 装饰器的元数据的类型。 这个类型参数,`T`,是你会传递给 `@Component` 装饰器的元数据的类型。
<code-example format="." language="javascript"> <code-example format="." language="javascript">
selector?: string; selector?: string;
template?: string; template?: string;
templateUrl?: string; templateUrl?: string;
providers?: any[]; providers?: any[];
... ...
</code-example> </code-example>
{@a spy-stub} {@a spy-stub}
@ -4057,7 +3942,6 @@ Here's a summary of the stand-alone functions, in order of likely utility:
下面是一些独立函数的总结,以使用频率排序: 下面是一些独立函数的总结,以使用频率排序:
<table> <table>
<tr> <tr>
<th> <th>
@ -4272,7 +4156,6 @@ Here's a summary of the stand-alone functions, in order of likely utility:
</td> </td>
</tr> </tr>
</table> </table>
<hr> <hr>
@ -4297,14 +4180,12 @@ is a subset of the `@NgModule` metadata properties.
传递给 `configureTestingModule` 的模块定义是 `@NgModule` 元数据属性的子集。 传递给 `configureTestingModule` 的模块定义是 `@NgModule` 元数据属性的子集。
<code-example format="." language="javascript"> <code-example format="." language="javascript">
type TestModuleMetadata = { type TestModuleMetadata = {
providers?: any[]; providers?: any[];
declarations?: any[]; declarations?: any[];
imports?: any[]; imports?: any[];
schemas?: Array&lt;SchemaMetadata | any[]&gt;; schemas?: Array&lt;SchemaMetadata | any[]&gt;;
}; };
</code-example> </code-example>
{@a metadata-override-object} {@a metadata-override-object}
@ -4316,13 +4197,11 @@ appropriate to the method, that is, the parameter of an `@NgModule`,
每一个重载方法接受一个 `MetadataOverride<T>`,这里 `T` 是适合这个方法的元数据类型,也就是 `@NgModule`、`@Component`、`@Directive` 或者 `@Pipe` 的参数。 每一个重载方法接受一个 `MetadataOverride<T>`,这里 `T` 是适合这个方法的元数据类型,也就是 `@NgModule`、`@Component`、`@Directive` 或者 `@Pipe` 的参数。
<code-example format="." language="javascript"> <code-example format="." language="javascript">
type MetadataOverride<T> = { type MetadataOverride<T> = {
add?: T; add?: T;
remove?: T; remove?: T;
set?: T; set?: T;
}; };
</code-example> </code-example>
{@a testbed-methods} {@a testbed-methods}
@ -4347,7 +4226,6 @@ Here are the most important static methods, in order of likely utility.
这里列出了最重要的静态方法,以使用频率排序: 这里列出了最重要的静态方法,以使用频率排序:
<table> <table>
<tr> <tr>
<th> <th>
@ -4614,7 +4492,6 @@ Here are the most important static methods, in order of likely utility.
</td> </td>
</tr> </tr>
</table> </table>
A few of the `TestBed` instance methods are not covered by static `TestBed` _class_ methods. A few of the `TestBed` instance methods are not covered by static `TestBed` _class_ methods.
@ -4650,7 +4527,6 @@ Here are the most important properties for testers, in order of likely utility.
下面是对测试最重要的属性,以使用频率排序: 下面是对测试最重要的属性,以使用频率排序:
<table> <table>
<tr> <tr>
<th> <th>
@ -4754,7 +4630,6 @@ Here are the most important properties for testers, in order of likely utility.
</td> </td>
</tr> </tr>
</table> </table>
{@a component-fixture-methods} {@a component-fixture-methods}
@ -4774,7 +4649,6 @@ Here are the most useful methods for testers.
下面是对测试最有用的方法。 下面是对测试最有用的方法。
<table> <table>
<tr> <tr>
<th> <th>
@ -4939,7 +4813,6 @@ Here are the most useful methods for testers.
</td> </td>
</tr> </tr>
</table> </table>
{@a debug-element-details} {@a debug-element-details}
@ -4960,7 +4833,6 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
下面是 `DebugElement` 最有用的成员,以使用频率排序。 下面是 `DebugElement` 最有用的成员,以使用频率排序。
<table> <table>
<tr> <tr>
<th> <th>
@ -5267,7 +5139,6 @@ Here are the most useful `DebugElement` members for testers, in approximate orde
</td> </td>
</tr> </tr>
</table> </table>
{@a query-predicate} {@a query-predicate}

View File

@ -102,7 +102,6 @@ You can suppress them with the following additional flag:
你可以使用另一个标志来禁止它们。 你可以使用另一个标志来禁止它们。
<code-example format="."> <code-example format=".">
"suppressImplicitAnyIndexErrors":true "suppressImplicitAnyIndexErrors":true
</code-example> </code-example>
@ -166,7 +165,6 @@ list of declaration files to be included:
因为《快速上手》的目标为 `es5`,所以你可以重写声明文件列表来包含: 因为《快速上手》的目标为 `es5`,所以你可以重写声明文件列表来包含:
<code-example format="."> <code-example format=".">
"lib": ["es2015", "dom"] "lib": ["es2015", "dom"]
</code-example> </code-example>

View File

@ -261,7 +261,6 @@ When you're done, the folder structure will look like this:
当做完这些后,文件夹的结构是这样的: 当做完这些后,文件夹的结构是这样的:
<code-example format="." language="none" linenums="false"> <code-example format="." language="none" linenums="false">
src/ src/
index.html <t><i>app web page</i></t><t>应用的宿主页</t> index.html <t><i>app web page</i></t><t>应用的宿主页</t>
main.ts <t><i>bootstrapper for client app</i></t><t>客户端应用的引导程序</t> main.ts <t><i>bootstrapper for client app</i></t><t>客户端应用的引导程序</t>
@ -276,7 +275,6 @@ server.ts <t><i>* express web server</i></t><t>* Express 的
tsconfig.json <t><i>TypeScript client configuration</i></t><t>TypeScript 的客户端配置</t> tsconfig.json <t><i>TypeScript client configuration</i></t><t>TypeScript 的客户端配置</t>
package.json <t><i>npm configuration</i></t><t>npm 配置</t> package.json <t><i>npm configuration</i></t><t>npm 配置</t>
webpack.server.config.js <t><i>* Webpack server configuration</i></t><t>* Webpack 的服务端配置</t> webpack.server.config.js <t><i>* Webpack server configuration</i></t><t>* Webpack 的服务端配置</t>
</code-example> </code-example>
The files marked with `*` are new and not in the original tutorial sample. The files marked with `*` are new and not in the original tutorial sample.
@ -326,9 +324,7 @@ Install them with the following commands:
使用下列命令安装它们: 使用下列命令安装它们:
<code-example format="." language="bash"> <code-example format="." language="bash">
npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader @nguniversal/express-engine npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader @nguniversal/express-engine
</code-example> </code-example>
{@a transition} {@a transition}
@ -364,7 +360,6 @@ Replace that import with this one:
把该导入改成这样: 把该导入改成这样:
<code-example path="universal/src/app/app.module.ts" region="browsermodule" title="src/app/app.module.ts (withServerTransition)"> <code-example path="universal/src/app/app.module.ts" region="browsermodule" title="src/app/app.module.ts (withServerTransition)">
</code-example> </code-example>
Angular adds the `appId` value (which can be _any_ string) to the style-names of the server-rendered pages, Angular adds the `appId` value (which can be _any_ string) to the style-names of the server-rendered pages,
@ -377,7 +372,6 @@ You can get runtime information about the current platform and the `appId` by in
你可以通过依赖注入取得关于当前平台和 `appId` 的运行时信息。 你可以通过依赖注入取得关于当前平台和 `appId` 的运行时信息。
<code-example path="universal/src/app/app.module.ts" region="platform-detection" title="src/app/app.module.ts (platform detection)"> <code-example path="universal/src/app/app.module.ts" region="platform-detection" title="src/app/app.module.ts (platform detection)">
</code-example> </code-example>
{@a http-urls} {@a http-urls}
@ -413,7 +407,6 @@ Start by changing the `HeroService` constructor to take a second `origin` parame
先为 `HeroService` 的构造函数添加第二个 `origin` 参数,它是可选的,并通过 `APP_BASE_HREF` 令牌进行注入。 先为 `HeroService` 的构造函数添加第二个 `origin` 参数,它是可选的,并通过 `APP_BASE_HREF` 令牌进行注入。
<code-example path="universal/src/app/hero.service.ts" region="ctor" title="src/app/hero.service.ts (constructor with optional origin)"> <code-example path="universal/src/app/hero.service.ts" region="ctor" title="src/app/hero.service.ts (constructor with optional origin)">
</code-example> </code-example>
Note how the constructor prepends the origin (if it exists) to the `heroesUrl`. Note how the constructor prepends the origin (if it exists) to the `heroesUrl`.
@ -460,7 +453,6 @@ Create an `app.server.module.ts` file in the `src/app/` directory with the follo
`src/app/` 目录下创建 `app.server.module.ts` 文件,代码如下: `src/app/` 目录下创建 `app.server.module.ts` 文件,代码如下:
<code-example path="universal/src/app/app.server.module.ts" title="src/app/app.server.module.ts"> <code-example path="universal/src/app/app.server.module.ts" title="src/app/app.server.module.ts">
</code-example> </code-example>
Notice that it imports first the client app's `AppModule`, the Angular Universal's `ServerModule` and the `ModuleMapLoaderModule`. Notice that it imports first the client app's `AppModule`, the Angular Universal's `ServerModule` and the `ModuleMapLoaderModule`.
@ -512,7 +504,6 @@ Create a `server.ts` file in the root directory and add the following code:
在根目录下创建 `server.ts` 文件,并添加下列代码: 在根目录下创建 `server.ts` 文件,并添加下列代码:
<code-example path="universal/server.ts" title="server.ts"> <code-example path="universal/server.ts" title="server.ts">
</code-example> </code-example>
<div class="alert is-critical"> <div class="alert is-critical">
@ -537,7 +528,6 @@ The important bit in this file is the `ngExpressEngine` function:
这个文件中最重要的部分是 `ngExpressEngine` 函数: 这个文件中最重要的部分是 `ngExpressEngine` 函数:
<code-example path="universal/server.ts" title="server.ts" region="ngExpressEngine"> <code-example path="universal/server.ts" title="server.ts" region="ngExpressEngine">
</code-example> </code-example>
The `ngExpressEngine` is a wrapper around the universal's `renderModuleFactory` function that turns a client's requests into server-rendered HTML pages. The `ngExpressEngine` is a wrapper around the universal's `renderModuleFactory` function that turns a client's requests into server-rendered HTML pages.
@ -641,7 +631,6 @@ You configure the Express server pipeline with calls to `app.get()` like this on
你通过通过调用 `app.get()` 来配置 Express 服务器的管道,就像下面这个数据请求一样: 你通过通过调用 `app.get()` 来配置 Express 服务器的管道,就像下面这个数据请求一样:
<code-example path="universal/server.ts" title="server.ts (data URL)" region="data-request" linenums="false"> <code-example path="universal/server.ts" title="server.ts (data URL)" region="data-request" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -688,7 +677,6 @@ The following code filters for request URLs with no extensions and treats them a
下列代码会过滤出不带扩展名的 URL并把它们当做导航请求进行处理。 下列代码会过滤出不带扩展名的 URL并把它们当做导航请求进行处理。
<code-example path="universal/server.ts" title="server.ts (navigation)" region="navigation-request" linenums="false"> <code-example path="universal/server.ts" title="server.ts (navigation)" region="navigation-request" linenums="false">
</code-example> </code-example>
#### Serve static files safely #### Serve static files safely
@ -710,7 +698,6 @@ The following express code routes all remaining requests to `/dist`; it returns
下列 Express 代码会把剩下的所有请求都路由到 `/dist` 目录下,如果文件未找到,就会返回 `404 - NOT FOUND` 下列 Express 代码会把剩下的所有请求都路由到 `/dist` 目录下,如果文件未找到,就会返回 `404 - NOT FOUND`
<code-example path="universal/server.ts" title="server.ts (static files)" region="static" linenums="false"> <code-example path="universal/server.ts" title="server.ts (static files)" region="static" linenums="false">
</code-example> </code-example>
{@a universal-configuration} {@a universal-configuration}
@ -734,7 +721,6 @@ Create a `tsconfig.server.json` file in the project root directory to configure
在项目的根目录下创建一个 `tsconfig.server.json` 文件来配置 TypeScript 和这个 Universal 应用的 AOT 编译选项。 在项目的根目录下创建一个 `tsconfig.server.json` 文件来配置 TypeScript 和这个 Universal 应用的 AOT 编译选项。
<code-example path="universal/src/tsconfig.server.json" title="src/tsconfig.server.json"> <code-example path="universal/src/tsconfig.server.json" title="src/tsconfig.server.json">
</code-example> </code-example>
This config extends from the root's `tsconfig.json` file. Certain settings are noteworthy for their differences. This config extends from the root's `tsconfig.json` file. Certain settings are noteworthy for their differences.
@ -743,7 +729,7 @@ This config extends from the root's `tsconfig.json` file. Certain settings are n
* The `module` property must be **commonjs** which can be required into our server application. * The `module` property must be **commonjs** which can be required into our server application.
`module` 属性必须是 **commonjs**,这样它才能被 `require()` 进你的服务端应用。 `module` 属性必须是 **commonjs**,这样它才能被 `require()` 进你的服务端应用。
* The `angularCompilerOptions` section guides the AOT compiler: * The `angularCompilerOptions` section guides the AOT compiler:
@ -767,7 +753,6 @@ Create a `webpack.server.config.js` file in the project root directory with the
在项目的根目录下创建一个 `webpack.server.config.js` 文件,代码如下: 在项目的根目录下创建一个 `webpack.server.config.js` 文件,代码如下:
<code-example path="universal/webpack.server.config.js" title="webpack.server.config.js"> <code-example path="universal/webpack.server.config.js" title="webpack.server.config.js">
</code-example> </code-example>
**Webpack configuration** is a rich topic beyond the scope of this guide. **Webpack configuration** is a rich topic beyond the scope of this guide.
@ -787,7 +772,6 @@ First add the _build_ and _serve_ commands to the `scripts` section of the `pack
首先把 `build``serve` 命令添加到 `package.json``scripts` 区: 首先把 `build``serve` 命令添加到 `package.json``scripts` 区:
<code-example format="." language="ts"> <code-example format="." language="ts">
"scripts": { "scripts": {
... ...
"build:universal": "npm run build:client-and-server-bundles && npm run webpack:server", "build:universal": "npm run build:client-and-server-bundles && npm run webpack:server",
@ -796,7 +780,6 @@ First add the _build_ and _serve_ commands to the `scripts` section of the `pack
"webpack:server": "webpack --config webpack.server.config.js --progress --colors" "webpack:server": "webpack --config webpack.server.config.js --progress --colors"
... ...
} }
</code-example> </code-example>
{@a build} {@a build}
@ -810,9 +793,7 @@ From the command prompt, type
在命令行提示中输入 在命令行提示中输入
<code-example format="." language="bash"> <code-example format="." language="bash">
npm run build:universal npm run build:universal
</code-example> </code-example>
The Angular CLI compiles and bundles the universal app into two different folders, `browser` and `server`. The Angular CLI compiles and bundles the universal app into two different folders, `browser` and `server`.
@ -832,9 +813,7 @@ After building the application, start the server.
构建完应用之后,启动服务器。 构建完应用之后,启动服务器。
<code-example format="." language="bash"> <code-example format="." language="bash">
npm run serve:universal npm run serve:universal
</code-example> </code-example>
The console window should say The console window should say
@ -842,9 +821,7 @@ The console window should say
在控制台窗口中应该看到 在控制台窗口中应该看到
<code-example format="." language="bash"> <code-example format="." language="bash">
Node server listening on http://localhost:4000 Node server listening on http://localhost:4000
</code-example> </code-example>
## Universal in action ## Universal in action

View File

@ -282,7 +282,6 @@ architecture may look something like this:
AngularJS 中一个完全向 Angular 架构对齐过的组件型指令是这样的: AngularJS 中一个完全向 Angular 架构对齐过的组件型指令是这样的:
<code-example path="upgrade-module/src/app/hero-detail.directive.ts" title="hero-detail.directive.ts"> <code-example path="upgrade-module/src/app/hero-detail.directive.ts" title="hero-detail.directive.ts">
</code-example> </code-example>
AngularJS 1.5 introduces the [component API](https://docs.angularjs.org/api/ng/type/angular.Module#component) AngularJS 1.5 introduces the [component API](https://docs.angularjs.org/api/ng/type/angular.Module#component)
@ -310,7 +309,6 @@ using the component API:
如果使用这个组件 API 进行快捷定义,那么上面看到的组件型指令就变成了这样: 如果使用这个组件 API 进行快捷定义,那么上面看到的组件型指令就变成了这样:
<code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" title="hero-detail.component.ts">
</code-example> </code-example>
Controller lifecycle hook methods `$onInit()`, `$onDestroy()`, and `$onChanges()` Controller lifecycle hook methods `$onInit()`, `$onDestroy()`, and `$onChanges()`
@ -373,7 +371,6 @@ frameworks in how it actually works.
无论是在 AngularJS 中还是在 Angular 中,依赖注入都位于前沿和中心的位置,但在两个框架的工作原理上,却存在着一些关键的不同之处。 无论是在 AngularJS 中还是在 Angular 中,依赖注入都位于前沿和中心的位置,但在两个框架的工作原理上,却存在着一些关键的不同之处。
<table> <table>
<tr> <tr>
<th> <th>
@ -389,7 +386,6 @@ frameworks in how it actually works.
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -411,7 +407,6 @@ frameworks in how it actually works.
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -433,7 +428,6 @@ frameworks in how it actually works.
</td> </td>
</tr> </tr>
</table> </table>
Even accounting for these differences you can still have dependency injection Even accounting for these differences you can still have dependency injection
@ -529,9 +523,7 @@ where you use an Angular component from AngularJS like this:
考虑一个场景,你从 AngularJS 中使用一个 Angular 组件,就像这样: 考虑一个场景,你从 AngularJS 中使用一个 Angular 组件,就像这样:
<code-example language="html" escape="html"> <code-example language="html" escape="html">
&lt;a-component&gt;&lt;/a-component&gt; &lt;a-component&gt;&lt;/a-component&gt;
</code-example> </code-example>
The DOM element `<a-component>` will remain to be an AngularJS managed The DOM element `<a-component>` will remain to be an AngularJS managed
@ -671,7 +663,6 @@ be used to bootstrap the AngularJS application.
在 AngularJS 应用中有一个 AngularJS 的根模块,它用于引导 AngularJS 应用。 在 AngularJS 应用中有一个 AngularJS 的根模块,它用于引导 AngularJS 应用。
<code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="ng1module" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="ng1module" title="app.module.ts">
</code-example> </code-example>
Pure AngularJS applications can be automatically bootstrapped by using an `ng-app` Pure AngularJS applications can be automatically bootstrapped by using an `ng-app`
@ -687,7 +678,6 @@ Say you have an `ng-app` driven bootstrap such as this one:
比如你现在有这样一个通过 `ng-app` 进行引导的应用: 比如你现在有这样一个通过 `ng-app` 进行引导的应用:
<code-example path="upgrade-module/src/index-ng-app.html"> <code-example path="upgrade-module/src/index-ng-app.html">
</code-example> </code-example>
You can remove the `ng-app` and `ng-strict-di` directives from the HTML You can remove the `ng-app` and `ng-strict-di` directives from the HTML
@ -697,7 +687,6 @@ will result in the same thing:
你可以从 HTML 中移除 `ng-app``ng-strict-di` 指令,改为从 JavaScript 中调用 `angular.bootstrap`,它能达到同样效果: 你可以从 HTML 中移除 `ng-app``ng-strict-di` 指令,改为从 JavaScript 中调用 `angular.bootstrap`,它能达到同样效果:
<code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="bootstrap" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-bootstrap/app.module.ts" region="bootstrap" title="app.module.ts">
</code-example> </code-example>
To begin converting your AngularJS application to a hybrid, you need to load the Angular framework. To begin converting your AngularJS application to a hybrid, you need to load the Angular framework.
@ -713,7 +702,6 @@ and add a mapping for the `@angular/upgrade/static` package:
也可以通过 `npm install @angular/upgrade --save` 命令来安装 `@angular/upgrade` 包,并给它添加一个到 `@angular/upgrade/static` 包的映射。 也可以通过 `npm install @angular/upgrade --save` 命令来安装 `@angular/upgrade` 包,并给它添加一个到 `@angular/upgrade/static` 包的映射。
<code-example path="upgrade-module/src/systemjs.config.1.js" region="upgrade-static-umd" title="systemjs.config.js (map)"> <code-example path="upgrade-module/src/systemjs.config.1.js" region="upgrade-static-umd" title="systemjs.config.js (map)">
</code-example> </code-example>
Next, create an `app.module.ts` file and add the following `NgModule` class: Next, create an `app.module.ts` file and add the following `NgModule` class:
@ -721,7 +709,6 @@ Next, create an `app.module.ts` file and add the following `NgModule` class:
接下来,创建一个 `app.module.ts` 文件,并添加下列 `NgModule` 类: 接下来,创建一个 `app.module.ts` 文件,并添加下列 `NgModule` 类:
<code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="ngmodule" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="ngmodule" title="app.module.ts">
</code-example> </code-example>
This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app must have. This bare minimum `NgModule` imports `BrowserModule`, the module every Angular browser-based app must have.
@ -752,7 +739,6 @@ Now you can bootstrap `AppModule` using the `platformBrowserDynamic.bootstrapMod
现在,你就可以使用 `platformBrowserDynamic.bootstrapModule` 方法来启动 `AppModule` 了。 现在,你就可以使用 `platformBrowserDynamic.bootstrapModule` 方法来启动 `AppModule` 了。
<code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="bootstrap" title="app.module.ts'"> <code-example path="upgrade-module/src/app/ajs-a-hybrid-bootstrap/app.module.ts" region="bootstrap" title="app.module.ts'">
</code-example> </code-example>
Congratulations! You're running a hybrid application! The Congratulations! You're running a hybrid application! The
@ -779,7 +765,6 @@ Say you have a simple Angular component that shows information about a hero:
假设你有一个简单的用来显示英雄信息的 Angular 组件: 假设你有一个简单的用来显示英雄信息的 Angular 组件:
<code-example path="upgrade-module/src/app/downgrade-static/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/downgrade-static/hero-detail.component.ts" title="hero-detail.component.ts">
</code-example> </code-example>
If you want to use this component from AngularJS, you need to *downgrade* it If you want to use this component from AngularJS, you need to *downgrade* it
@ -790,7 +775,6 @@ using the `downgradeComponent()` method. The result is an AngularJS
其结果是一个 AngularJS 的*指令*,你可以把它注册到 AngularJS 的模块中: 其结果是一个 AngularJS 的*指令*,你可以把它注册到 AngularJS 的模块中:
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" title="app.module.ts"> <code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="downgradecomponent" title="app.module.ts">
</code-example> </code-example>
Because `HeroDetailComponent` is an Angular component, you must also add it to the Because `HeroDetailComponent` is an Angular component, you must also add it to the
@ -806,7 +790,6 @@ NgModule.
将它加入到 Angular 模块的 `entryComponents` 列表中。 将它加入到 Angular 模块的 `entryComponents` 列表中。
<code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="ngmodule" title="app.module.ts"> <code-example path="upgrade-module/src/app/downgrade-static/app.module.ts" region="ngmodule" title="app.module.ts">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -823,7 +806,6 @@ use like any other directive in AngularJS templates.
最终的结果是一个叫做 `heroDetail` 的 AngularJS 指令,你可以像用其它指令一样把它用在 AngularJS 模板中。 最终的结果是一个叫做 `heroDetail` 的 AngularJS 指令,你可以像用其它指令一样把它用在 AngularJS 模板中。
<code-example path="upgrade-module/src/index-downgrade-static.html" region="usecomponent"> <code-example path="upgrade-module/src/index-downgrade-static.html" region="usecomponent">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -847,7 +829,6 @@ like this:
Angular 的英雄详情组件带有像这样的输入属性与输出属性: Angular 的英雄详情组件带有像这样的输入属性与输出属性:
<code-example path="upgrade-module/src/app/downgrade-io/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/downgrade-io/hero-detail.component.ts" title="hero-detail.component.ts">
</code-example> </code-example>
These inputs and outputs can be supplied from the AngularJS template, and the These inputs and outputs can be supplied from the AngularJS template, and the
@ -856,7 +837,6 @@ These inputs and outputs can be supplied from the AngularJS template, and the
这些输入属性和输出属性的值来自于 AngularJS 的模板,而 `downgradeComponent()` 方法负责桥接它们: 这些输入属性和输出属性的值来自于 AngularJS 的模板,而 `downgradeComponent()` 方法负责桥接它们:
<code-example path="upgrade-module/src/index-downgrade-io.html" region="usecomponent"> <code-example path="upgrade-module/src/index-downgrade-io.html" region="usecomponent">
</code-example> </code-example>
Note that even though you are in an AngularJS template, **you're using Angular Note that even though you are in an AngularJS template, **you're using Angular
@ -880,9 +860,7 @@ of multiple words. In Angular, you would bind these attributes using camelCase:
它适用于由多个单词组成的输入或输出属性。在 Angular 中,你要使用小驼峰命名法绑定这些属性: 它适用于由多个单词组成的输入或输出属性。在 Angular 中,你要使用小驼峰命名法绑定这些属性:
<code-example format=""> <code-example format="">
[myHero]="hero" [myHero]="hero"
</code-example> </code-example>
But when using them from AngularJS templates, you must use kebab-case: But when using them from AngularJS templates, you must use kebab-case:
@ -890,9 +868,7 @@ But when using them from AngularJS templates, you must use kebab-case:
但是从 AngularJS 的模板中使用它们时,你得使用中线命名法: 但是从 AngularJS 的模板中使用它们时,你得使用中线命名法:
<code-example format=""> <code-example format="">
[my-hero]="hero" [my-hero]="hero"
</code-example> </code-example>
</div> </div>
@ -911,7 +887,6 @@ For example, you can easily make multiple copies of the component using `ng-repe
例如,你可以用 `ng-repeat` 简单的制作该组件的多份拷贝: 例如,你可以用 `ng-repeat` 简单的制作该组件的多份拷贝:
<code-example path="upgrade-module/src/index-downgrade-io.html" region="userepeatedcomponent"> <code-example path="upgrade-module/src/index-downgrade-io.html" region="userepeatedcomponent">
</code-example> </code-example>
### Using AngularJS Component Directives from Angular Code ### Using AngularJS Component Directives from Angular Code
@ -949,7 +924,6 @@ and a controller:
可升级组件的简单例子是只有一个模板和一个控制器的指令: 可升级组件的简单例子是只有一个模板和一个控制器的指令:
<code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail" title="hero-detail.component.ts">
</code-example> </code-example>
You can *upgrade* this component to Angular using the `UpgradeComponent` class. You can *upgrade* this component to Angular using the `UpgradeComponent` class.
@ -963,11 +937,9 @@ All that is left is to add it to `AppModule`'s `declarations` array.
剩下是工作就是把它加入到 `AppModule``declarations` 数组。 剩下是工作就是把它加入到 `AppModule``declarations` 数组。
<code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail-upgrade" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-static/hero-detail.component.ts" region="hero-detail-upgrade" title="hero-detail.component.ts">
</code-example> </code-example>
<code-example path="upgrade-module/src/app/upgrade-static/app.module.ts" region="hero-detail-upgrade" title="app.module.ts"> <code-example path="upgrade-module/src/app/upgrade-static/app.module.ts" region="hero-detail-upgrade" title="app.module.ts">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -992,7 +964,6 @@ observing the following rules:
当你从 Angular 模板中使用该组件时,就要使用**Angular 模板语法**来提供这些输入属性和输出属性,但要遵循下列规则: 当你从 Angular 模板中使用该组件时,就要使用**Angular 模板语法**来提供这些输入属性和输出属性,但要遵循下列规则:
<table> <table>
<tr> <tr>
<th> <th>
@ -1016,7 +987,6 @@ observing the following rules:
</th> </th>
</tr> </tr>
<tr> <tr>
<th> <th>
@ -1040,7 +1010,6 @@ observing the following rules:
</td> </td>
</tr> </tr>
<tr> <tr>
<th> <th>
@ -1064,7 +1033,6 @@ observing the following rules:
</td> </td>
</tr> </tr>
<tr> <tr>
<th> <th>
@ -1088,7 +1056,6 @@ observing the following rules:
</td> </td>
</tr> </tr>
<tr> <tr>
<th> <th>
@ -1117,7 +1084,6 @@ observing the following rules:
</td> </td>
</tr> </tr>
</table> </table>
For example, imagine a hero detail AngularJS component directive For example, imagine a hero detail AngularJS component directive
@ -1126,7 +1092,6 @@ with one input and one output:
举个例子,假设 AngularJS 中有一个表示“英雄详情”的组件型指令,它带有一个输入属性和一个输出属性: 举个例子,假设 AngularJS 中有一个表示“英雄详情”的组件型指令,它带有一个输入属性和一个输出属性:
<code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io" title="hero-detail.component.ts">
</code-example> </code-example>
You can upgrade this component to Angular, annotate inputs and outputs in the upgrade directive, You can upgrade this component to Angular, annotate inputs and outputs in the upgrade directive,
@ -1135,11 +1100,9 @@ and then provide the input and output using Angular template syntax:
你可以把这个组件升级到 Angular然后使用 Angular 的模板语法提供这个输入属性和输出属性: 你可以把这个组件升级到 Angular然后使用 Angular 的模板语法提供这个输入属性和输出属性:
<code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io-upgrade" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/hero-detail.component.ts" region="hero-detail-io-upgrade" title="hero-detail.component.ts">
</code-example> </code-example>
<code-example path="upgrade-module/src/app/upgrade-io/container.component.ts" title="container.component.ts"> <code-example path="upgrade-module/src/app/upgrade-io/container.component.ts" title="container.component.ts">
</code-example> </code-example>
### Projecting AngularJS Content into Angular Components ### Projecting AngularJS Content into Angular Components
@ -1164,7 +1127,6 @@ tag within them. Here's an example of such a component:
Angular 的组件通过使用 `<ng-content>` 标签来支持内容投影。下面是这类组件的一个例子: Angular 的组件通过使用 `<ng-content>` 标签来支持内容投影。下面是这类组件的一个例子:
<code-example path="upgrade-module/src/app/ajs-to-a-projection/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-projection/hero-detail.component.ts" title="hero-detail.component.ts">
</code-example> </code-example>
When using the component from AngularJS, you can supply contents for it. Just When using the component from AngularJS, you can supply contents for it. Just
@ -1175,7 +1137,6 @@ of the `<ng-content>` tag in Angular:
它们也在 Angular 中被投影到了 `<ng-content>` 标签所在的位置: 它们也在 Angular 中被投影到了 `<ng-content>` 标签所在的位置:
<code-example path="upgrade-module/src/index-ajs-to-a-projection.html" region="usecomponent"> <code-example path="upgrade-module/src/index-ajs-to-a-projection.html" region="usecomponent">
</code-example> </code-example>
<div class="alert is-helpful"> <div class="alert is-helpful">
@ -1207,7 +1168,6 @@ point:
如果一个 AngularJS 组件型指令支持透传,它就会在自己的模板中使用 `ng-transclude` 指令标记出透传到的位置: 如果一个 AngularJS 组件型指令支持透传,它就会在自己的模板中使用 `ng-transclude` 指令标记出透传到的位置:
<code-example path="upgrade-module/src/app/a-to-ajs-transclusion/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-transclusion/hero-detail.component.ts" title="hero-detail.component.ts">
</code-example> </code-example>
If you upgrade this component and use it from Angular, you can populate If you upgrade this component and use it from Angular, you can populate
@ -1216,7 +1176,6 @@ the component tag with contents that will then get transcluded:
如果你升级这个组件,并把它用在 Angular 中,你就能把准备透传的内容放进这个组件的标签中。 如果你升级这个组件,并把它用在 Angular 中,你就能把准备透传的内容放进这个组件的标签中。
<code-example path="upgrade-module/src/app/a-to-ajs-transclusion/container.component.ts" title="container.component.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-transclusion/container.component.ts" title="container.component.ts">
</code-example> </code-example>
### Making AngularJS Dependencies Injectable to Angular ### Making AngularJS Dependencies Injectable to Angular
@ -1239,7 +1198,6 @@ code. For example, you might have a service called `HeroesService` in AngularJS:
比如,你可能在 AngularJS 中有一个名叫 `HeroesService` 的服务: 比如,你可能在 AngularJS 中有一个名叫 `HeroesService` 的服务:
<code-example path="upgrade-module/src/app/ajs-to-a-providers/heroes.service.ts" title="heroes.service.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-providers/heroes.service.ts" title="heroes.service.ts">
</code-example> </code-example>
You can upgrade the service using a Angular [factory provider](guide/dependency-injection#factory-providers) You can upgrade the service using a Angular [factory provider](guide/dependency-injection#factory-providers)
@ -1260,11 +1218,9 @@ compilation can pick it up.
同时,建议导出 `heroesServiceFactory` 函数,以便 AOT 编译器可以拿到它们。 同时,建议导出 `heroesServiceFactory` 函数,以便 AOT 编译器可以拿到它们。
<code-example path="upgrade-module/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts" title="ajs-upgraded-providers.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts" title="ajs-upgraded-providers.ts">
</code-example> </code-example>
<code-example path="upgrade-module/src/app/ajs-to-a-providers/app.module.ts" region="register" title="app.module.ts"> <code-example path="upgrade-module/src/app/ajs-to-a-providers/app.module.ts" region="register" title="app.module.ts">
</code-example> </code-example>
You can then inject it in Angular using its class as a type annotation: You can then inject it in Angular using its class as a type annotation:
@ -1306,7 +1262,6 @@ For example, you might have an Angular service called `Heroes`:
例如,你可能有一个 Angular 的 `Heroes` 服务: 例如,你可能有一个 Angular 的 `Heroes` 服务:
<code-example path="upgrade-module/src/app/a-to-ajs-providers/heroes.ts" title="heroes.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/heroes.ts" title="heroes.ts">
</code-example> </code-example>
Again, as with Angular components, register the provider with the `NgModule` by adding it to the module's `providers` list. Again, as with Angular components, register the provider with the `NgModule` by adding it to the module's `providers` list.
@ -1314,7 +1269,6 @@ Again, as with Angular components, register the provider with the `NgModule` by
仿照 Angular 组件,把该提供商加入 `NgModule``providers` 列表中,以注册它。 仿照 Angular 组件,把该提供商加入 `NgModule``providers` 列表中,以注册它。
<code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="ngmodule" title="app.module.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="ngmodule" title="app.module.ts">
</code-example> </code-example>
Now wrap the Angular `Heroes` in an *AngularJS factory function* using `downgradeInjectable()` Now wrap the Angular `Heroes` in an *AngularJS factory function* using `downgradeInjectable()`
@ -1325,7 +1279,6 @@ The name of the AngularJS dependency is up to you:
依赖在 AngularJS 中的名字你可以自己定: 依赖在 AngularJS 中的名字你可以自己定:
<code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="register" title="app.module.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/app.module.ts" region="register" title="app.module.ts">
</code-example> </code-example>
After this, the service is injectable anywhere in AngularJS code: After this, the service is injectable anywhere in AngularJS code:
@ -1333,7 +1286,6 @@ After this, the service is injectable anywhere in AngularJS code:
此后,该服务就能被注入到 AngularJS 代码中的任何地方了: 此后,该服务就能被注入到 AngularJS 代码中的任何地方了:
<code-example path="upgrade-module/src/app/a-to-ajs-providers/hero-detail.component.ts" title="hero-detail.component.ts"> <code-example path="upgrade-module/src/app/a-to-ajs-providers/hero-detail.component.ts" title="hero-detail.component.ts">
</code-example> </code-example>
## Using Ahead-of-time compilation with hybrid apps ## Using Ahead-of-time compilation with hybrid apps
@ -1362,7 +1314,6 @@ bootstrap the hybrid app:
你还要使用所生成的 `AppModuleFactory` 而不是原来的 `AppModule` 来引导一个混合式应用: 你还要使用所生成的 `AppModuleFactory` 而不是原来的 `AppModule` 来引导一个混合式应用:
<code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" title="app/main-aot.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" title="app/main-aot.ts">
</code-example> </code-example>
And that's all you need do to get the full benefit of AOT for Angular apps! And that's all you need do to get the full benefit of AOT for Angular apps!
@ -1712,9 +1663,7 @@ Begin by installing TypeScript to the project.
先把 TypeScript 包安装到项目中。 先把 TypeScript 包安装到项目中。
<code-example format=""> <code-example format="">
npm i typescript --save-dev npm i typescript --save-dev
</code-example> </code-example>
Install type definitions for the existing libraries that Install type definitions for the existing libraries that
@ -1724,9 +1673,7 @@ Jasmine unit test framework.
还要为那些没有自带类型信息的库(比如 AngularJS 和 Jasmine安装类型定义文件。 还要为那些没有自带类型信息的库(比如 AngularJS 和 Jasmine安装类型定义文件。
<code-example format=""> <code-example format="">
npm install @types/jasmine @types/angular @types/angular-animate @types/angular-cookies @types/angular-mocks @types/angular-resource @types/angular-route @types/angular-sanitize --save-dev npm install @types/jasmine @types/angular @types/angular-animate @types/angular-cookies @types/angular-mocks @types/angular-resource @types/angular-route @types/angular-sanitize --save-dev
</code-example> </code-example>
You should also configure the TypeScript compiler with a `tsconfig.json` in the project directory You should also configure the TypeScript compiler with a `tsconfig.json` in the project directory
@ -1744,12 +1691,10 @@ JavaScript (based on the `tsconfig.json` configuration file):
最后,你应该把下列 npm 脚本添加到 `package.json` 中,用于把 TypeScript 文件编译成 JavaScript (根据 `tsconfig.json` 的配置): 最后,你应该把下列 npm 脚本添加到 `package.json` 中,用于把 TypeScript 文件编译成 JavaScript (根据 `tsconfig.json` 的配置):
<code-example format=""> <code-example format="">
"script": { "script": {
"tsc": "tsc", "tsc": "tsc",
"tsc:w": "tsc -w", "tsc:w": "tsc -w",
... ...
</code-example> </code-example>
Now launch the TypeScript compiler from the command line in watch mode: Now launch the TypeScript compiler from the command line in watch mode:
@ -1757,9 +1702,7 @@ Now launch the TypeScript compiler from the command line in watch mode:
现在,从命令行中用监视模式启动 TypeScript 编译器: 现在,从命令行中用监视模式启动 TypeScript 编译器:
<code-example format=""> <code-example format="">
npm run tsc:w npm run tsc:w
</code-example> </code-example>
Keep this process running in the background, watching and recompiling as you make changes. Keep this process running in the background, watching and recompiling as you make changes.
@ -1813,7 +1756,6 @@ what the filter is supposed to do.
这可以更清楚的表明此过滤器打算做什么 这可以更清楚的表明此过滤器打算做什么
<code-example path="upgrade-phonecat-1-typescript/app/core/checkmark/checkmark.filter.ts" title="app/core/checkmark/checkmark.filter.ts"> <code-example path="upgrade-phonecat-1-typescript/app/core/checkmark/checkmark.filter.ts" title="app/core/checkmark/checkmark.filter.ts">
</code-example> </code-example>
In the `Phone` service, you can explicitly annotate the `$resource` service dependency In the `Phone` service, you can explicitly annotate the `$resource` service dependency
@ -1822,7 +1764,6 @@ as an `angular.resource.IResourceService` - a type defined by the AngularJS typi
`Phone` 服务中,你可以明确的把 `$resource` 服务声明为 `angular.resource.IResourceService`,一个 AngularJS 类型定义提供的类型。 `Phone` 服务中,你可以明确的把 `$resource` 服务声明为 `angular.resource.IResourceService`,一个 AngularJS 类型定义提供的类型。
<code-example path="upgrade-phonecat-1-typescript/app/core/phone/phone.service.ts" title="app/core/phone/phone.service.ts"> <code-example path="upgrade-phonecat-1-typescript/app/core/phone/phone.service.ts" title="app/core/phone/phone.service.ts">
</code-example> </code-example>
You can apply the same trick to the application's route configuration file in `app.config.ts`, You can apply the same trick to the application's route configuration file in `app.config.ts`,
@ -1833,7 +1774,6 @@ can verify you're calling their APIs with the correct kinds of arguments.
一旦为它们提供了类型信息TypeScript 就能检查你是否在用类型的正确参数来调用它们了。 一旦为它们提供了类型信息TypeScript 就能检查你是否在用类型的正确参数来调用它们了。
<code-example path="upgrade-phonecat-1-typescript/app/app.config.ts" title="app/app.config.ts"> <code-example path="upgrade-phonecat-1-typescript/app/app.config.ts" title="app/app.config.ts">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -1878,7 +1818,6 @@ Here's what the new class for the phone list component controller looks like:
新的“电话列表(phone list)”组件控制器类是这样的: 新的“电话列表(phone list)”组件控制器类是这样的:
<code-example path="upgrade-phonecat-1-typescript/app/phone-list/phone-list.component.ts" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-1-typescript/app/phone-list/phone-list.component.ts" title="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
What was previously done in the controller function is now done in the class What was previously done in the controller function is now done in the class
@ -1906,7 +1845,6 @@ that the user is looking at and another for the URL of the currently displayed i
在电话详情控制器中,你有两个成员:一个是用户正在查看的电话,另一个是正在显示的图像: 在电话详情控制器中,你有两个成员:一个是用户正在查看的电话,另一个是正在显示的图像:
<code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
This makes the controller code look a lot more like Angular already. You're This makes the controller code look a lot more like Angular already. You're
@ -1969,9 +1907,7 @@ Once these are done, run:
这些完成之后,就运行: 这些完成之后,就运行:
<code-example format=""> <code-example format="">
npm install npm install
</code-example> </code-example>
Soon you can load Angular dependencies into the application via `index.html`, Soon you can load Angular dependencies into the application via `index.html`,
@ -1989,9 +1925,7 @@ instead of `app`:
`app/index.html` 移入项目的根目录,然后把 `package.json` 中的开发服务器根目录也指向项目的根目录,而不再是 `app` 目录: `app/index.html` 移入项目的根目录,然后把 `package.json` 中的开发服务器根目录也指向项目的根目录,而不再是 `app` 目录:
<code-example format=""> <code-example format="">
"start": "http-server ./ -a localhost -p 8000 -c-1", "start": "http-server ./ -a localhost -p 8000 -c-1",
</code-example> </code-example>
Now you're able to serve everything from the project root to the web browser. But you do *not* Now you're able to serve everything from the project root to the web browser. But you do *not*
@ -2002,7 +1936,6 @@ cause relative URLs to be resolved back to the `/app` directory:
现在,你就能把项目根目录下的每一样东西发给浏览器了。但你*不想*为了适应开发环境中的设置,被迫修改应用代码中用到的所有图片和数据的路径。因此,你要往 `index.html` 中添加一个 `<base>` 标签,它将导致各种相对路径被解析回 `/app` 目录: 现在,你就能把项目根目录下的每一样东西发给浏览器了。但你*不想*为了适应开发环境中的设置,被迫修改应用代码中用到的所有图片和数据的路径。因此,你要往 `index.html` 中添加一个 `<base>` 标签,它将导致各种相对路径被解析回 `/app` 目录:
<code-example path="upgrade-phonecat-2-hybrid/index.html" region="base" title="index.html"> <code-example path="upgrade-phonecat-2-hybrid/index.html" region="base" title="index.html">
</code-example> </code-example>
Now you can load Angular via SystemJS. You'll add the Angular polyfills and the Now you can load Angular via SystemJS. You'll add the Angular polyfills and the
@ -2013,7 +1946,6 @@ to load the actual application:
和 SystemJS 的配置加到 `<head>` 区的末尾,然后,你能就用 `System.import` 来加载实际的应用了: 和 SystemJS 的配置加到 `<head>` 区的末尾,然后,你能就用 `System.import` 来加载实际的应用了:
<code-example path="upgrade-phonecat-2-hybrid/index.html" region="angular" title="index.html"> <code-example path="upgrade-phonecat-2-hybrid/index.html" region="angular" title="index.html">
</code-example> </code-example>
You also need to make a couple of adjustments You also need to make a couple of adjustments
@ -2032,7 +1964,6 @@ and add a mapping for the `@angular/upgrade/static` package.
再通过 `npm install @angular/upgrade --save` 安装 `upgrade` 包,并为 `@angular/upgrade/static` 包添加一个映射。 再通过 `npm install @angular/upgrade --save` 安装 `upgrade` 包,并为 `@angular/upgrade/static` 包添加一个映射。
<code-example path="upgrade-phonecat-2-hybrid/systemjs.config.1.js" region="paths" title="systemjs.config.js"> <code-example path="upgrade-phonecat-2-hybrid/systemjs.config.1.js" region="paths" title="systemjs.config.js">
</code-example> </code-example>
### Creating the _AppModule_ ### Creating the _AppModule_
@ -2050,7 +1981,6 @@ The file contents remain:
文件的内容保留: 文件的内容保留:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ajs.ts" title="app.module.ajs.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ajs.ts" title="app.module.ajs.ts">
</code-example> </code-example>
Now create a new `app.module.ts` with the minimum `NgModule` class: Now create a new `app.module.ts` with the minimum `NgModule` class:
@ -2058,7 +1988,6 @@ Now create a new `app.module.ts` with the minimum `NgModule` class:
然后创建一个新的 `app.module.ts` 文件,其中是一个最小化的 `NgModule` 类: 然后创建一个新的 `app.module.ts` 文件,其中是一个最小化的 `NgModule` 类:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="bare" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="bare" title="app.module.ts">
</code-example> </code-example>
### Bootstrapping a hybrid PhoneCat ### Bootstrapping a hybrid PhoneCat
@ -2086,7 +2015,6 @@ Then import `UpgradeModule` in the `AppModule`, and override its `ngDoBootstrap`
首先,从 `index.html` 中移除 `ng-app`。然后在 `AppModule` 中导入 `UpgradeModule`,并改写它的 `ngDoBootstrap` 方法: 首先,从 `index.html` 中移除 `ng-app`。然后在 `AppModule` 中导入 `UpgradeModule`,并改写它的 `ngDoBootstrap` 方法:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="upgrademodule" title="app/app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="upgrademodule" title="app/app.module.ts">
</code-example> </code-example>
Note that you are bootstrapping the AngularJS module from inside `ngDoBootstrap`. Note that you are bootstrapping the AngularJS module from inside `ngDoBootstrap`.
@ -2104,7 +2032,6 @@ so it is already being loaded by the browser.
最后,在 `src/main.ts` 中引导这个 `AppModule`。该文件在 `systemjs.config.js` 中被配置为了应用的入口,所以它已经被加载进了浏览器中。 最后,在 `src/main.ts` 中引导这个 `AppModule`。该文件在 `systemjs.config.js` 中被配置为了应用的入口,所以它已经被加载进了浏览器中。
<code-example path="upgrade-phonecat-2-hybrid/app/main.ts" region="bootstrap" title="app/main.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/main.ts" region="bootstrap" title="app/main.ts">
</code-example> </code-example>
Now you're running both AngularJS and Angular at the same time. That's pretty Now you're running both AngularJS and Angular at the same time. That's pretty
@ -2183,7 +2110,6 @@ Re-open the `app.module.ts` file, import and add `HttpModule` to the `imports` a
再次打开 `app.module.ts` 文件,导入并把 `HttpModule` 添加到 `AppModule``imports` 数组中: 再次打开 `app.module.ts` 文件,导入并把 `HttpModule` 添加到 `AppModule``imports` 数组中:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="httpmodule" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="httpmodule" title="app.module.ts">
</code-example> </code-example>
Now you're ready to upgrade the Phone service itself. Replace the ngResource-based Now you're ready to upgrade the Phone service itself. Replace the ngResource-based
@ -2192,7 +2118,6 @@ service in `phone.service.ts` with a TypeScript class decorated as `@Injectable`
现在,你已经准备好了升级 `Phones` 服务本身。你将为 `phone.service.ts` 文件中基于 ngResource 的服务加上 `@Injectable` 装饰器: 现在,你已经准备好了升级 `Phones` 服务本身。你将为 `phone.service.ts` 文件中基于 ngResource 的服务加上 `@Injectable` 装饰器:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="classdef" title="app/core/phone/phone.service.ts (skeleton)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="classdef" title="app/core/phone/phone.service.ts (skeleton)" linenums="false">
</code-example> </code-example>
The `@Injectable` decorator will attach some dependency injection metadata The `@Injectable` decorator will attach some dependency injection metadata
@ -2214,7 +2139,6 @@ and the other loads the details of a specified phone:
然后该服务在两个实例方法中被使用到,一个加载所有电话的列表,另一个加载一台指定电话的详情: 然后该服务在两个实例方法中被使用到,一个加载所有电话的列表,另一个加载一台指定电话的详情:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="fullclass" title="app/core/phone/phone.service.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="fullclass" title="app/core/phone/phone.service.ts">
</code-example> </code-example>
The methods now return Observables of type `PhoneData` and `PhoneData[]`. This is The methods now return Observables of type `PhoneData` and `PhoneData[]`. This is
@ -2224,7 +2148,6 @@ a type you don't have yet. Add a simple interface for it:
这是一个你从未用过的类型,因此你得为它新增一个简单的接口: 这是一个你从未用过的类型,因此你得为它新增一个简单的接口:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="phonedata-interface" title="app/core/phone/phone.service.ts (interface)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="phonedata-interface" title="app/core/phone/phone.service.ts (interface)" linenums="false">
</code-example> </code-example>
`@angular/upgrade/static` has a `downgradeInjectable` method for the purpose of making `@angular/upgrade/static` has a `downgradeInjectable` method for the purpose of making
@ -2234,7 +2157,6 @@ Angular services available to AngularJS code. Use it to plug in the `Phone` serv
使用它来插入 `Phone` 服务: 使用它来插入 `Phone` 服务:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="downgrade-injectable" title="app/core/phone/phone.service.ts (downgrade)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="downgrade-injectable" title="app/core/phone/phone.service.ts (downgrade)" linenums="false">
</code-example> </code-example>
Here's the full, final code for the service: Here's the full, final code for the service:
@ -2242,7 +2164,6 @@ Here's the full, final code for the service:
最终,该类的全部代码如下: 最终,该类的全部代码如下:
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" title="app/core/phone/phone.service.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" title="app/core/phone/phone.service.ts">
</code-example> </code-example>
Notice that you're importing the `map` operator of the RxJS `Observable` separately. Notice that you're importing the `map` operator of the RxJS `Observable` separately.
@ -2258,7 +2179,6 @@ Because it's an Angular service, you register it with the `NgModule` providers:
因为它是 Angular 服务,你通过 `NgModule``providers` 数组来注册它: 因为它是 Angular 服务,你通过 `NgModule``providers` 数组来注册它:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phone" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phone" title="app.module.ts">
</code-example> </code-example>
Now that you are loading `phone.service.ts` through an import that is resolved Now that you are loading `phone.service.ts` through an import that is resolved
@ -2277,11 +2197,9 @@ it's really an instance of the `Phone` class and you annotate its type according
但它实际上是一个 `Phones` 类的实例,并且你可以据此注解它的类型: 但它实际上是一个 `Phones` 类的实例,并且你可以据此注解它的类型:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ajs.ts" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ajs.ts" title="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ajs.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ajs.ts" title="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
Now there are two AngularJS components using an Angular service! Now there are two AngularJS components using an Angular service!
@ -2325,7 +2243,6 @@ You can then also remove the static `$inject` property from the class:
的组件了。然后,你还要从类中移除静态 `$inject` 属性。 的组件了。然后,你还要从类中移除静态 `$inject` 属性。
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="initialclass" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="initialclass" title="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
The `selector` attribute is a CSS selector that defines where on the page the component The `selector` attribute is a CSS selector that defines where on the page the component
@ -2343,7 +2260,6 @@ with Angular's two-way `[(ngModel)]` binding syntax:
现在,将组件的模版也转换为 Angular 语法。在搜索控件中,把 AngularJS 的 `$ctrl` 表达式替换成 Angular 的双向绑定语法 `[(ngModel)]` 现在,将组件的模版也转换为 Angular 语法。在搜索控件中,把 AngularJS 的 `$ctrl` 表达式替换成 Angular 的双向绑定语法 `[(ngModel)]`
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="controls" title="app/phone-list/phone-list.template.html (search controls)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="controls" title="app/phone-list/phone-list.template.html (search controls)" linenums="false">
</code-example> </code-example>
Replace the list's `ng-repeat` with an `*ngFor` as Replace the list's `ng-repeat` with an `*ngFor` as
@ -2355,7 +2271,6 @@ Replace the image tag's `ng-src` with a binding to the native `src` property.
再把 `img` 标签的 `ng-src` 替换为一个标准的 `src` 属性(property)绑定。 再把 `img` 标签的 `ng-src` 替换为一个标准的 `src` 属性(property)绑定。
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="list" title="app/phone-list/phone-list.template.html (phones)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.template.html" region="list" title="app/phone-list/phone-list.template.html (phones)" linenums="false">
</code-example> </code-example>
#### No Angular _filter_ or _orderBy_ filters #### No Angular _filter_ or _orderBy_ filters
@ -2374,7 +2289,6 @@ which implements the filtering and ordering logic inside the component itself.
你把 `filter``orderBy` 过滤器改成绑定到控制器中的 `getPhones()` 方法,通过该方法,组件本身实现了过滤和排序逻辑。 你把 `filter``orderBy` 过滤器改成绑定到控制器中的 `getPhones()` 方法,通过该方法,组件本身实现了过滤和排序逻辑。
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="getphones" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="getphones" title="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
Now you need to downgrade the Angular component so you can use it in AngularJS. Now you need to downgrade the Angular component so you can use it in AngularJS.
@ -2391,7 +2305,6 @@ that the return value of the `downgradeComponent` method is a directive factory.
的返回值是一个指令工厂。 的返回值是一个指令工厂。
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="downgrade-component" title="app/phone-list/phone-list.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.ts" region="downgrade-component" title="app/phone-list/phone-list.component.ts">
</code-example> </code-example>
The new `PhoneListComponent` uses the Angular `ngModel` directive, located in the `FormsModule`. The new `PhoneListComponent` uses the Angular `ngModel` directive, located in the `FormsModule`.
@ -2403,7 +2316,6 @@ finally add it to `entryComponents` since you downgraded it:
最后,把降级的结果添加到 `entryComponents`中: 最后,把降级的结果添加到 `entryComponents`中:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonelist" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonelist" title="app.module.ts">
</code-example> </code-example>
Remove the &lt;script&gt; tag for the phone list component from `index.html`. Remove the &lt;script&gt; tag for the phone list component from `index.html`.
@ -2415,7 +2327,6 @@ Now set the remaining `phone-detail.component.ts` as follows:
现在,剩下的 `phone-detail.component.ts` 文件变成了这样: 现在,剩下的 `phone-detail.component.ts` 文件变成了这样:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
This is similar to the phone list component. This is similar to the phone list component.
@ -2443,11 +2354,9 @@ Do that in a new file called `ajs-upgraded-providers.ts` and import it in `app.m
新建一个名叫 `ajs-upgraded-providers.ts` 的文件,并且在 `app.module.ts` 中导入它: 新建一个名叫 `ajs-upgraded-providers.ts` 的文件,并且在 `app.module.ts` 中导入它:
<code-example path="upgrade-phonecat-2-hybrid/app/ajs-upgraded-providers.ts" title="app/ajs-upgraded-providers.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/ajs-upgraded-providers.ts" title="app/ajs-upgraded-providers.ts">
</code-example> </code-example>
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="routeparams" title="app/app.module.ts ($routeParams)" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="routeparams" title="app/app.module.ts ($routeParams)" linenums="false">
</code-example> </code-example>
Convert the phone detail component template into Angular syntax as follows: Convert the phone detail component template into Angular syntax as follows:
@ -2455,7 +2364,6 @@ Convert the phone detail component template into Angular syntax as follows:
把该组件的模板转变成 Angular 的语法,代码如下: 把该组件的模板转变成 Angular 的语法,代码如下:
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.template.html" title="app/phone-detail/phone-detail.template.html"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.template.html" title="app/phone-detail/phone-detail.template.html">
</code-example> </code-example>
There are several notable changes here: There are several notable changes here:
@ -2507,7 +2415,6 @@ Add `PhoneDetailComponent` component to the `NgModule` _declarations_ and _entry
`PhoneDetailComponent` 组件添加到 `NgModule`*declarations**entryComponents* 中: `PhoneDetailComponent` 组件添加到 `NgModule`*declarations**entryComponents* 中:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonedetail" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="phonedetail" title="app.module.ts">
</code-example> </code-example>
You should now also remove the phone detail component &lt;script&gt; tag from `index.html`. You should now also remove the phone detail component &lt;script&gt; tag from `index.html`.
@ -2536,7 +2443,6 @@ Rename the file to `checkmark.pipe.ts` to conform with Angular conventions:
把该文件改名成 `checkmark.pipe.ts`,以符合 Angular 中的命名约定: 把该文件改名成 `checkmark.pipe.ts`,以符合 Angular 中的命名约定:
<code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.ts" title="app/core/checkmark/checkmark.pipe.ts" linenums="false"> <code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.ts" title="app/core/checkmark/checkmark.pipe.ts" linenums="false">
</code-example> </code-example>
Now import and declare the newly created pipe and Now import and declare the newly created pipe and
@ -2545,7 +2451,6 @@ remove the filter &lt;script&gt; tag from `index.html`:
现在,导入并声明这个新创建的管道,同时从 `index.html` 文件中移除该过滤器的`<script>` 标签: 现在,导入并声明这个新创建的管道,同时从 `index.html` 文件中移除该过滤器的`<script>` 标签:
<code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="checkmarkpipe" title="app.module.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/app.module.ts" region="checkmarkpipe" title="app.module.ts">
</code-example> </code-example>
### AOT compile the hybrid app ### AOT compile the hybrid app
@ -2563,7 +2468,6 @@ by the AOT compiler:
然后修改 `main-aot.ts` 的引导代码,通过所生成的 `AppComponentFactory` 来引导 AngularJS 应用: 然后修改 `main-aot.ts` 的引导代码,通过所生成的 `AppComponentFactory` 来引导 AngularJS 应用:
<code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" title="app/main-aot.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/main-aot.ts" title="app/main-aot.ts">
</code-example> </code-example>
You need to load all the AngularJS files you already use in `index.html` in `aot/index.html` You need to load all the AngularJS files you already use in `index.html` in `aot/index.html`
@ -2572,7 +2476,6 @@ as well:
你还要把在 `index.html` 中已经用到的所有 AngularJS 文件加载到 `aot/index.html` 中: 你还要把在 `index.html` 中已经用到的所有 AngularJS 文件加载到 `aot/index.html` 中:
<code-example path="upgrade-phonecat-2-hybrid/aot/index.html" title="aot/index.html"> <code-example path="upgrade-phonecat-2-hybrid/aot/index.html" title="aot/index.html">
</code-example> </code-example>
These files need to be copied together with the polyfills. The files the application These files need to be copied together with the polyfills. The files the application
@ -2586,7 +2489,6 @@ Install `fs-extra` via `npm install fs-extra --save-dev` for better file copying
通过 `npm install fs-extra --save-dev` 安装 `fs-extra` 可以更好的复制文件,并且把 `copy-dist-files.js` 文件改成这样: 通过 `npm install fs-extra --save-dev` 安装 `fs-extra` 可以更好的复制文件,并且把 `copy-dist-files.js` 文件改成这样:
<code-example path="upgrade-phonecat-2-hybrid/copy-dist-files.js" title="copy-dist-files.js"> <code-example path="upgrade-phonecat-2-hybrid/copy-dist-files.js" title="copy-dist-files.js">
</code-example> </code-example>
And that's all you need to use AOT while upgrading your app! And that's all you need to use AOT while upgrading your app!
@ -2624,7 +2526,6 @@ Create a new `app.component.ts` file with the following `AppComponent` class:
创建新的 `app.component.ts` 文件,放入像这样的 `AppComponent` 类: 创建新的 `app.component.ts` 文件,放入像这样的 `AppComponent` 类:
<code-example path="upgrade-phonecat-3-final/app/app.component.ts" title="app/app.component.ts"> <code-example path="upgrade-phonecat-3-final/app/app.component.ts" title="app/app.component.ts">
</code-example> </code-example>
It has a simple template that only includes the `<router-outlet>. It has a simple template that only includes the `<router-outlet>.
@ -2645,7 +2546,6 @@ It replaces the old AngularJS `ng-view` directive:
用它来代替 AngularJS 中的 `ng-view` 指令: 用它来代替 AngularJS 中的 `ng-view` 指令:
<code-example path="upgrade-phonecat-3-final/index.html" region="appcomponent" title="index.html (body)" linenums="false"> <code-example path="upgrade-phonecat-3-final/index.html" region="appcomponent" title="index.html (body)" linenums="false">
</code-example> </code-example>
#### Create the _Routing Module_ #### Create the _Routing Module_
@ -2664,7 +2564,6 @@ Angular 路由器配置的详情最好去查阅下[路由与导航](guide/router
它建议你创建一个专们用于路由器配置的 `NgModule`(名叫*路由模块*)。 它建议你创建一个专们用于路由器配置的 `NgModule`(名叫*路由模块*)。
<code-example path="upgrade-phonecat-3-final/app/app-routing.module.ts" title="app/app-routing.module.ts"> <code-example path="upgrade-phonecat-3-final/app/app-routing.module.ts" title="app/app-routing.module.ts">
</code-example> </code-example>
This module defines a `routes` object with two routes to the two phone components This module defines a `routes` object with two routes to the two phone components
@ -2693,7 +2592,6 @@ and the `UpgradeModule` import.
你还要从 `app.module.ts` 中移除调用 `ngDoBootstrap()` 来引导 AngularJS 模块的代码,以及对 `UpgradeModule` 的导入代码。 你还要从 `app.module.ts` 中移除调用 `ngDoBootstrap()` 来引导 AngularJS 模块的代码,以及对 `UpgradeModule` 的导入代码。
<code-example path="upgrade-phonecat-3-final/app/app.module.ts" title="app/app.module.ts"> <code-example path="upgrade-phonecat-3-final/app/app.module.ts" title="app/app.module.ts">
</code-example> </code-example>
And since you are routing to `PhoneListComponent` and `PhoneDetailComponent` directly rather than And since you are routing to `PhoneListComponent` and `PhoneDetailComponent` directly rather than
@ -2714,7 +2612,6 @@ and let that directive construct the appropriate URL to the `PhoneDetailComponen
你可以通过把每个电话的 `id` 绑定到 `routerLink` 指令来生成它们了,该指令的构造函数会为 `PhoneDetailComponent` 生成正确的 URL 你可以通过把每个电话的 `id` 绑定到 `routerLink` 指令来生成它们了,该指令的构造函数会为 `PhoneDetailComponent` 生成正确的 URL
<code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.template.html" region="list" title="app/phone-list/phone-list.template.html (list with links)" linenums="false"> <code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.template.html" region="list" title="app/phone-list/phone-list.template.html (list with links)" linenums="false">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -2738,7 +2635,6 @@ Angular 路由器会传入不同的路由参数。
`ActivatedRoute.snapshot.params` 中提取出 `phoneId`,并像以前一样获取手机的数据: `ActivatedRoute.snapshot.params` 中提取出 `phoneId`,并像以前一样获取手机的数据:
<code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts"> <code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.ts" title="app/phone-detail/phone-detail.component.ts">
</code-example> </code-example>
You are now running a pure Angular application! You are now running a pure Angular application!
@ -2766,7 +2662,6 @@ Switch the bootstrap method of the application from the `UpgradeModule` to the A
把应用的引导(`bootstrap`)方法从 `UpgradeAdapter` 的改为 Angular 的。 把应用的引导(`bootstrap`)方法从 `UpgradeAdapter` 的改为 Angular 的。
<code-example path="upgrade-phonecat-3-final/app/main.ts" title="main.ts"> <code-example path="upgrade-phonecat-3-final/app/main.ts" title="main.ts">
</code-example> </code-example>
If you haven't already, remove all references to the `UpgradeModule` from `app.module.ts`, If you haven't already, remove all references to the `UpgradeModule` from `app.module.ts`,
@ -2785,7 +2680,6 @@ in `entryComponents`.
因为你不再需要降级任何组件了,也不再需要把它们列在 `entryComponents` 中。 因为你不再需要降级任何组件了,也不再需要把它们列在 `entryComponents` 中。
<code-example path="upgrade-phonecat-3-final/app/app.module.ts" title="app.module.ts"> <code-example path="upgrade-phonecat-3-final/app/app.module.ts" title="app.module.ts">
</code-example> </code-example>
You may also completely remove the following files. They are AngularJS You may also completely remove the following files. They are AngularJS
@ -2813,10 +2707,8 @@ The `@angular/upgrade` package and its mapping in `systemjs.config.js` can also
`systemjs.config.js` 中的 `@angular/upgrade` 包及其映射也可以移除了。 `systemjs.config.js` 中的 `@angular/upgrade` 包及其映射也可以移除了。
<code-example format=""> <code-example format="">
npm uninstall @angular/upgrade --save npm uninstall @angular/upgrade --save
npm uninstall @types/angular @types/angular-animate @types/angular-cookies @types/angular-mocks @types/angular-resource @types/angular-route @types/angular-sanitize --save-dev npm uninstall @types/angular @types/angular-animate @types/angular-cookies @types/angular-mocks @types/angular-resource @types/angular-route @types/angular-sanitize --save-dev
</code-example> </code-example>
Finally, from `index.html`, remove all references to AngularJS scripts and jQuery. Finally, from `index.html`, remove all references to AngularJS scripts and jQuery.
@ -2826,7 +2718,6 @@ When you're done, this is what it should look like:
当这些全部做完时,`index.html` 应该是这样的: 当这些全部做完时,`index.html` 应该是这样的:
<code-example path="upgrade-phonecat-3-final/index.html" region="full" title="index.html"> <code-example path="upgrade-phonecat-3-final/index.html" region="full" title="index.html">
</code-example> </code-example>
That is the last you'll see of AngularJS! It has served us well but now That is the last you'll see of AngularJS! It has served us well but now
@ -2875,9 +2766,7 @@ Update the `protractor-conf.js` to sync with hybrid apps:
再对 `protractor-conf.js` 做下列修改,与混合应用同步: 再对 `protractor-conf.js` 做下列修改,与混合应用同步:
<code-example format=""> <code-example format="">
ng12Hybrid: true ng12Hybrid: true
</code-example> </code-example>
When you start to upgrade components and their templates to Angular, you'll make more changes When you start to upgrade components and their templates to Angular, you'll make more changes
@ -2888,7 +2777,6 @@ For PhoneCat you need to make the following changes in order to make things work
这是因为 E2E 测试有一些匹配器是 AngularJS 中特有的。对于 PhoneCat 来说,为了让它能在 Angular 下工作,你得做下列修改: 这是因为 E2E 测试有一些匹配器是 AngularJS 中特有的。对于 PhoneCat 来说,为了让它能在 Angular 下工作,你得做下列修改:
<table> <table>
<tr> <tr>
<th> <th>
@ -2916,7 +2804,6 @@ For PhoneCat you need to make the following changes in order to make things work
</th> </th>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -2940,7 +2827,6 @@ For PhoneCat you need to make the following changes in order to make things work
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -2964,7 +2850,6 @@ For PhoneCat you need to make the following changes in order to make things work
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -2988,7 +2873,6 @@ For PhoneCat you need to make the following changes in order to make things work
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -3012,7 +2896,6 @@ For PhoneCat you need to make the following changes in order to make things work
</td> </td>
</tr> </tr>
<tr> <tr>
<td> <td>
@ -3036,7 +2919,6 @@ For PhoneCat you need to make the following changes in order to make things work
</td> </td>
</tr> </tr>
</table> </table>
When the bootstrap method is switched from that of `UpgradeModule` to When the bootstrap method is switched from that of `UpgradeModule` to
@ -3054,9 +2936,7 @@ Replace the `ng12Hybrid` previously added with the following in `protractor-conf
替换之前在 `protractor-conf.js` 中加入 `ng12Hybrid`,象这样: 替换之前在 `protractor-conf.js` 中加入 `ng12Hybrid`,象这样:
<code-example format=""> <code-example format="">
useAllAngular2AppRoots: true, useAllAngular2AppRoots: true,
</code-example> </code-example>
Also, there are a couple of Protractor API calls in the PhoneCat test code that Also, there are a couple of Protractor API calls in the PhoneCat test code that
@ -3069,7 +2949,6 @@ the redirection spec:
你就得把这些调用用一个 WebDriver 的通用 URL API 代替。第一个 API 是“重定向(redirect)”规约: 你就得把这些调用用一个 WebDriver 的通用 URL API 代替。第一个 API 是“重定向(redirect)”规约:
<code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="redirect" title="e2e-tests/scenarios.ts"> <code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="redirect" title="e2e-tests/scenarios.ts">
</code-example> </code-example>
And the second is the phone links spec: And the second is the phone links spec:
@ -3077,7 +2956,6 @@ And the second is the phone links spec:
然后是“电话链接(phone links)”规约: 然后是“电话链接(phone links)”规约:
<code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="links" title="e2e-tests/scenarios.ts"> <code-example path="upgrade-phonecat-3-final/e2e-spec.ts" region="links" title="e2e-tests/scenarios.ts">
</code-example> </code-example>
### Unit Tests ### Unit Tests
@ -3103,7 +2981,6 @@ definitions of the AngularJS services you're consuming:
AngularJS 服务提供了类型定义。 AngularJS 服务提供了类型定义。
<code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.spec.ts" title="app/phone-detail/phone-detail.component.spec.ts"> <code-example path="upgrade-phonecat-1-typescript/app/phone-detail/phone-detail.component.spec.ts" title="app/phone-detail/phone-detail.component.spec.ts">
</code-example> </code-example>
Once you start the upgrade process and bring in SystemJS, configuration changes Once you start the upgrade process and bring in SystemJS, configuration changes
@ -3114,7 +2991,6 @@ which can be done with the following kind of shim file:
你需要让 SystemJS 加载所有的 Angular 新代码, 你需要让 SystemJS 加载所有的 Angular 新代码,
<code-example path="upgrade-phonecat-2-hybrid/karma-test-shim.1.js" title="karma-test-shim.js"> <code-example path="upgrade-phonecat-2-hybrid/karma-test-shim.1.js" title="karma-test-shim.js">
</code-example> </code-example>
The shim first loads the SystemJS configuration, then Angular's test support libraries, The shim first loads the SystemJS configuration, then Angular's test support libraries,
@ -3128,7 +3004,6 @@ as the base directory, instead of `app`.
然后需要修改 Karma 配置,来让它使用本应用的根目录作为基础目录(base directory),而不是 `app` 然后需要修改 Karma 配置,来让它使用本应用的根目录作为基础目录(base directory),而不是 `app`
<code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="basepath" title="karma.conf.js"> <code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="basepath" title="karma.conf.js">
</code-example> </code-example>
Once done, you can load SystemJS and other dependencies, and also switch the configuration Once done, you can load SystemJS and other dependencies, and also switch the configuration
@ -3139,7 +3014,6 @@ the shim and SystemJS load them.
你要让这个 shim 文件和 SystemJS 去加载它们。 你要让这个 shim 文件和 SystemJS 去加载它们。
<code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="files" title="karma.conf.js"> <code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="files" title="karma.conf.js">
</code-example> </code-example>
Since the HTML templates of Angular components will be loaded as well, you must help Since the HTML templates of Angular components will be loaded as well, you must help
@ -3148,7 +3022,6 @@ Karma out a bit so that it can route them to the right paths:
由于 Angular 组件中的 HTML 模板也同样要被加载,所以你得帮 Karma 一把,帮它在正确的路径下找到这些模板: 由于 Angular 组件中的 HTML 模板也同样要被加载,所以你得帮 Karma 一把,帮它在正确的路径下找到这些模板:
<code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="html" title="karma.conf.js"> <code-example path="upgrade-phonecat-2-hybrid/karma.conf.ajs.js" region="html" title="karma.conf.js">
</code-example> </code-example>
The unit test files themselves also need to be switched to Angular when their production The unit test files themselves also need to be switched to Angular when their production
@ -3158,7 +3031,6 @@ as the pipe has no dependencies:
如果产品代码被切换到了 Angular单元测试文件本身也需要切换过来。对勾(checkmark)管道的规约可能是最简单的,因为它没有任何依赖: 如果产品代码被切换到了 Angular单元测试文件本身也需要切换过来。对勾(checkmark)管道的规约可能是最简单的,因为它没有任何依赖:
<code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.spec.ts" title="app/core/checkmark/checkmark.pipe.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/checkmark/checkmark.pipe.spec.ts" title="app/core/checkmark/checkmark.pipe.spec.ts">
</code-example> </code-example>
The unit test for the phone service is a bit more involved. You need to switch from the mocked-out The unit test for the phone service is a bit more involved. You need to switch from the mocked-out
@ -3167,7 +3039,6 @@ AngularJS `$httpBackend` to a mocked-out Angular Http backend.
`Phone` 服务的测试会牵扯到一点别的。你需要把模拟版的 AngularJS `$httpBackend` 服务切换到模拟板的 Angular Http 后端。 `Phone` 服务的测试会牵扯到一点别的。你需要把模拟版的 AngularJS `$httpBackend` 服务切换到模拟板的 Angular Http 后端。
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.spec.ts" title="app/core/phone/phone.service.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.spec.ts" title="app/core/phone/phone.service.spec.ts">
</code-example> </code-example>
For the component specs, you can mock out the `Phone` service itself, and have it provide For the component specs, you can mock out the `Phone` service itself, and have it provide
@ -3176,11 +3047,9 @@ canned phone data. You use Angular's component unit testing APIs for both compon
对于组件的规约,你可以模拟出 `Phone` 服务本身,并且让它提供电话的数据。你可以对这些组件使用 Angular 的组件单元测试 API。 对于组件的规约,你可以模拟出 `Phone` 服务本身,并且让它提供电话的数据。你可以对这些组件使用 Angular 的组件单元测试 API。
<code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.spec.ts" title="app/phone-detail/phone-detail.component.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-detail/phone-detail.component.spec.ts" title="app/phone-detail/phone-detail.component.spec.ts">
</code-example> </code-example>
<code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.spec.ts" title="app/phone-list/phone-list.component.spec.ts"> <code-example path="upgrade-phonecat-2-hybrid/app/phone-list/phone-list.component.spec.ts" title="app/phone-list/phone-list.component.spec.ts">
</code-example> </code-example>
Finally, revisit both of the component tests when you switch to the Angular Finally, revisit both of the component tests when you switch to the Angular
@ -3191,7 +3060,6 @@ instead of using the AngularJS `$routeParams`.
`RouteParams` 的 mock 对象,而不再用 AngularJS 中的 `$routeParams` `RouteParams` 的 mock 对象,而不再用 AngularJS 中的 `$routeParams`
<code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.spec.ts" region="activatedroute" title="app/phone-detail/phone-detail.component.spec.ts"> <code-example path="upgrade-phonecat-3-final/app/phone-detail/phone-detail.component.spec.ts" region="activatedroute" title="app/phone-detail/phone-detail.component.spec.ts">
</code-example> </code-example>
And for the phone list component, a few adjustments to the router make And for the phone list component, a few adjustments to the router make
@ -3200,5 +3068,4 @@ the `RouteLink` directives work.
对于电话列表组件,还要再做少量的调整,以便路由器能让 `RouteLink` 指令正常工作。 对于电话列表组件,还要再做少量的调整,以便路由器能让 `RouteLink` 指令正常工作。
<code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.component.spec.ts" region="routestuff" title="app/phone-list/phone-list.component.spec.ts"> <code-example path="upgrade-phonecat-3-final/app/phone-list/phone-list.component.spec.ts" region="routestuff" title="app/phone-list/phone-list.component.spec.ts">
</code-example> </code-example>

View File

@ -125,9 +125,7 @@ Here's what the UI displays:
用户界面将显示: 用户界面将显示:
<code-example> <code-example>
a | ab | abc | ab | a | | a | ab | abc | ab | a | |
</code-example> </code-example>
<figure> <figure>
@ -142,7 +140,6 @@ for `event.target.value` in which case the same user input would produce:
或者,你可以用 `event.key` 替代 `event.target.value`,积累各个按键本身,这样同样的用户输入可以产生: 或者,你可以用 `event.key` 替代 `event.target.value`,积累各个按键本身,这样同样的用户输入可以产生:
<code-example> <code-example>
a | b | c | backspace | backspace | backspace | a | b | c | backspace | backspace | backspace |
</code-example> </code-example>
@ -428,7 +425,6 @@ values between data entry fields and model properties.
The next page, `Forms`, explains how to write The next page, `Forms`, explains how to write
two-way bindings with `NgModel`. two-way bindings with `NgModel`.
这些技术对小规模演示很实用,但是在处理大量用户输入时,很容易变得累赘和笨拙。 这些技术对小规模演示很实用,但是在处理大量用户输入时,很容易变得累赘和笨拙。
要在数据录入字段和模型属性之间传递数据,双向数据绑定是更加优雅和简洁的方式。 要在数据录入字段和模型属性之间传递数据,双向数据绑定是更加优雅和简洁的方式。
下一章 ` 表单 ` 解释了如何用 `NgModel` 来进行双向绑定。 下一章 ` 表单 ` 解释了如何用 `NgModel` 来进行双向绑定。

View File

@ -222,7 +222,7 @@ Include the files in the Visual Studio project as follows:
<h2 id='restore'>Step 4: Restore the required packages</h2> <h2 id='restore'>Step 4: Restore the required packages</h2>
<h2 id='restore'> 第四步: 恢复需要的包 </h2> <h2 id='restore'>第四步: 恢复需要的包 </h2>
Restore the packages required for an Angular application as follows: Restore the packages required for an Angular application as follows:
@ -348,7 +348,6 @@ rewrite rules near the bottom of the `web.config`:
通过把下列重写规则添加到 `web.config` 的底部,就可以告诉 Visual Studio 如何处理到应用页面的请求。 通过把下列重写规则添加到 `web.config` 的底部,就可以告诉 Visual Studio 如何处理到应用页面的请求。
<code-example format='.'> <code-example format='.'>
&lt;system.webServer&gt; &lt;system.webServer&gt;
&lt;rewrite&gt; &lt;rewrite&gt;
&lt;rules&gt; &lt;rules&gt;
@ -397,7 +396,6 @@ The default browser opens and displays the QuickStart sample application.
默认浏览器打开并显示《快速上手》例子应用。 默认浏览器打开并显示《快速上手》例子应用。
Try editing any of the project files. Save and refresh the browser to Try editing any of the project files. Save and refresh the browser to
see the changes. see the changes.
尝试编辑任何项目文件,*保存*并刷新浏览器来查看效果。 尝试编辑任何项目文件,*保存*并刷新浏览器来查看效果。

View File

@ -175,7 +175,6 @@ Then it **outputs** these files to the `app.js` _bundle file_ designated in conf
然后它把这些文件**输出**到当前配置所指定的*包文件*`app.js` 中: 然后它把这些文件**输出**到当前配置所指定的*包文件*`app.js` 中:
<code-example name="webpack.config.js (single output)" language="javascript"> <code-example name="webpack.config.js (single output)" language="javascript">
output: { output: {
filename: 'app.js' filename: 'app.js'
} }
@ -204,7 +203,6 @@ Change the configuration so that it has two entry points, `main.ts` and `vendor.
所以要修改配置,以获得两个入口点:`main.ts` 和 `vendor.ts` 所以要修改配置,以获得两个入口点:`main.ts` 和 `vendor.ts`
<code-example language="javascript"> <code-example language="javascript">
entry: { entry: {
app: 'src/app.ts', app: 'src/app.ts',
vendor: 'src/vendor.ts' vendor: 'src/vendor.ts'
@ -257,7 +255,6 @@ Webpack 可以打包任何类型的文件JavaScript、TypeScript、CSS、SASS
再为 TypeScript 和 CSS 文件配置如下加载器。 再为 TypeScript 和 CSS 文件配置如下加载器。
<code-example language="javascript"> <code-example language="javascript">
rules: [ rules: [
{ {
test: /\.ts$/, test: /\.ts$/,
@ -277,7 +274,6 @@ it applies the `test` RegEx patterns.
当 Webpack 遇到如下所示的 `import` 语句时,它就会调用正则表达式的 `test` 方法。 当 Webpack 遇到如下所示的 `import` 语句时,它就会调用正则表达式的 `test` 方法。
<code-example language="typescript"> <code-example language="typescript">
import { AppComponent } from './app.component.ts'; import { AppComponent } from './app.component.ts';
import 'uiframework/dist/uiframework.css'; import 'uiframework/dist/uiframework.css';
@ -316,7 +312,6 @@ Webpack 有一条构建流水线,它被划分成多个经过精心定义的阶
可以把插件(比如 `uglify` 代码最小化插件)挂到流水线上: 可以把插件(比如 `uglify` 代码最小化插件)挂到流水线上:
<code-example language="javascript"> <code-example language="javascript">
plugins: [ plugins: [
new webpack.optimize.UglifyJsPlugin() new webpack.optimize.UglifyJsPlugin()
] ]
@ -342,7 +337,6 @@ Create a new project folder.
创建一个新的项目文件夹。 创建一个新的项目文件夹。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
mkdir angular-webpack mkdir angular-webpack
cd angular-webpack cd angular-webpack
@ -396,7 +390,6 @@ Open a terminal window and install the npm packages.
打开命令行窗口并安装这些 *npm* 打开命令行窗口并安装这些 *npm*
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm install npm install
</code-example> </code-example>
@ -530,7 +523,6 @@ You could write `import` statements with explicit extensions like this example:
如果你的应用程序只须 `import` 几十个 JavaScript 或 TypeScript 文件,而不是几百个,你可以在 `import` 语句里完整写上扩展名,如: 如果你的应用程序只须 `import` 几十个 JavaScript 或 TypeScript 文件,而不是几百个,你可以在 `import` 语句里完整写上扩展名,如:
<code-example language="typescript"> <code-example language="typescript">
import { AppComponent } from './app.component.ts'; import { AppComponent } from './app.component.ts';
</code-example> </code-example>
@ -737,7 +729,6 @@ Grab the app code at the end of this guide and try:
抓取本指南底部的应用代码,并试一试: 抓取本指南底部的应用代码,并试一试:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm start npm start
</code-example> </code-example>
@ -746,11 +737,11 @@ Grab the app code at the end of this guide and try:
### Production configuration ### Production configuration
### 产环境配置 ### 产环境配置
Configuration of a *production* build resembles *development* configuration with a few key changes. Configuration of a *production* build resembles *development* configuration with a few key changes.
*产环境*下的配置和*开发环境*下的配置很相似……除了一些关键的改动。 *产环境*下的配置和*开发环境*下的配置很相似……除了一些关键的改动。
<code-example path="webpack/config/webpack.prod.js" title="config/webpack.prod.js" linenums="false"> <code-example path="webpack/config/webpack.prod.js" title="config/webpack.prod.js" linenums="false">
@ -764,7 +755,7 @@ You won't deploy the artifacts needed only in development.
Put the production output bundle files in the `dist` folder. Put the production output bundle files in the `dist` folder.
把产环境的输出包放在 `dist` 目录下。 产环境的输出包放在 `dist` 目录下。
Webpack generates file names with cache-busting hash. Webpack generates file names with cache-busting hash.
Thanks to the `HtmlWebpackPlugin`, you don't have to update the `index.html` file when the hash changes. Thanks to the `HtmlWebpackPlugin`, you don't have to update the `index.html` file when the hash changes.
@ -809,7 +800,6 @@ Grab the app code at the end of this guide and try:
抓取本指南底部的应用代码,并试一试: 抓取本指南底部的应用代码,并试一试:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm run build npm run build
</code-example> </code-example>
@ -826,7 +816,7 @@ You probably don't need to load and process the application-wide styles files fo
you'll use the `null` loader for those CSS files. you'll use the `null` loader for those CSS files.
你并不需要使用很多配置项来运行单元测试。 你并不需要使用很多配置项来运行单元测试。
也不需要在开发环境和产环境下引入的那些加载器和插件。 也不需要在开发环境和产环境下引入的那些加载器和插件。
如果有可能拖慢执行速度,甚至都不需要在单元测试中加载和处理应用全局样式文件,所以你用一个 `null` 加载器来处理所有 CSS。 如果有可能拖慢执行速度,甚至都不需要在单元测试中加载和处理应用全局样式文件,所以你用一个 `null` 加载器来处理所有 CSS。
You could merge the test configuration into the `webpack.common` configuration and override the parts you don't want or need. You could merge the test configuration into the `webpack.common` configuration and override the parts you don't want or need.
@ -877,7 +867,6 @@ Grab the app code at the end of this guide and try:
抓取本指南底部的应用代码,并试一试: 抓取本指南底部的应用代码,并试一试:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm test npm test
</code-example> </code-example>
@ -1002,7 +991,7 @@ if the `CommonsChunkPlugin` hadn't detected the overlap and removed them from `a
You've learned just enough Webpack to configurate development, test and production builds You've learned just enough Webpack to configurate development, test and production builds
for a small Angular application. for a small Angular application.
你学到了刚好够用来在开发、测试、产环境下构建一个小型 Angular 应用的 Webpack 配置知识。 你学到了刚好够用来在开发、测试、产环境下构建一个小型 Angular 应用的 Webpack 配置知识。
_You could always do more_. Search the web for expert advice and expand your Webpack knowledge. _You could always do more_. Search the web for expert advice and expand your Webpack knowledge.
@ -1010,5 +999,4 @@ _You could always do more_. Search the web for expert advice and expand your Web
[Back to top](guide/webpack#top) [Back to top](guide/webpack#top)
[回到顶部](guide/webpack#top) [回到顶部](guide/webpack#top)

View File

@ -421,7 +421,7 @@
}, },
{ {
"url": "guide/service-worker-devops", "url": "guide/service-worker-devops",
"title": "环境下的 Service Worker", "title": "产环境下的 Service Worker",
"tooltip": "使用 Service Worker 运行应用、管理应用更新、调试以及杀掉正在运行的应用。" "tooltip": "使用 Service Worker 运行应用、管理应用更新、调试以及杀掉正在运行的应用。"
}, },
{ {

View File

@ -11,9 +11,7 @@
如果还没有安装 [Angular CLI](https://github.com/angular/angular-cli),请执行: 如果还没有安装 [Angular CLI](https://github.com/angular/angular-cli),请执行:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm install -g @angular/cli npm install -g @angular/cli
</code-example> </code-example>
## Create a new application ## Create a new application
@ -25,9 +23,7 @@ Create a new project named `angular-tour-of-heroes` with this CLI command.
使用 CLI 命令创建一个名叫 `angular-tour-of-heroes` 的新项目。 使用 CLI 命令创建一个名叫 `angular-tour-of-heroes` 的新项目。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng new angular-tour-of-heroes ng new angular-tour-of-heroes
</code-example> </code-example>
The Angular CLI generated a new project with a default application and supporting files. The Angular CLI generated a new project with a default application and supporting files.
@ -43,10 +39,8 @@ Go to the project directory and launch the application.
进入项目目录,并启动这个应用。 进入项目目录,并启动这个应用。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
cd angular-tour-of-heroes cd angular-tour-of-heroes
ng serve --open ng serve --open
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -111,7 +105,6 @@ Open the component class file (`app.component.ts`) and change the value of the `
打开组件的类文件 (`app.component.ts`),并把 `title` 属性的值修改为 'Tour of Heroes' (英雄指南)。 打开组件的类文件 (`app.component.ts`),并把 `title` 属性的值修改为 'Tour of Heroes' (英雄指南)。
<code-example path="toh-pt0/src/app/app.component.ts" region="set-title" title="app.component.ts (class title property)" linenums="false"> <code-example path="toh-pt0/src/app/app.component.ts" region="set-title" title="app.component.ts (class title property)" linenums="false">
</code-example> </code-example>
Open the component template file (`app.component.html`) and Open the component template file (`app.component.html`) and
@ -122,7 +115,6 @@ Replace it with the following line of HTML.
<code-example path="toh-pt0/src/app/app.component.html" <code-example path="toh-pt0/src/app/app.component.html"
title="app.component.html (template)" linenums="false"> title="app.component.html (template)" linenums="false">
</code-example> </code-example>
The double curly braces are Angular's *interpolation binding* syntax. The double curly braces are Angular's *interpolation binding* syntax.
@ -155,7 +147,6 @@ Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app.
下面是这个*英雄指南*范例应用中 `styles.css` 文件的片段。 下面是这个*英雄指南*范例应用中 `styles.css` 文件的片段。
<code-example path="toh-pt0/src/styles.1.css" title="src/styles.css (excerpt)"> <code-example path="toh-pt0/src/styles.1.css" title="src/styles.css (excerpt)">
</code-example> </code-example>
## Final code review ## Final code review
@ -183,7 +174,6 @@ Here are the code files discussed on this page.
title="src/styles.css (excerpt)" title="src/styles.css (excerpt)"
path="toh-pt0/src/styles.1.css"> path="toh-pt0/src/styles.1.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
## Summary ## Summary
@ -198,6 +188,6 @@ Here are the code files discussed on this page.
你学会了使用 Angular 组件来显示数据。 你学会了使用 Angular 组件来显示数据。
* You used the double curly braces of interpolation to display the app title. * You used the double curly braces of interpolation to display the app title.
你使用双花括号插值表达式显示了应用标题。 你使用双花括号插值表达式显示了应用标题。

View File

@ -18,9 +18,7 @@ Using the Angular CLI, generate a new component named `heroes`.
使用 Angular CLI 创建一个名为 `heroes` 的新组件。 使用 Angular CLI 创建一个名为 `heroes` 的新组件。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component heroes ng generate component heroes
</code-example> </code-example>
The CLI creates a new folder, `src/app/heroes/` and generates The CLI creates a new folder, `src/app/heroes/` and generates
@ -35,7 +33,6 @@ The `HeroesComponent` class file is as follows:
<code-example <code-example
path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1" path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1"
title="app/heroes/heroes.component.ts (initial version)" linenums="false"> title="app/heroes/heroes.component.ts (initial version)" linenums="false">
</code-example> </code-example>
You always import the `Component` symbol from the Angular core library You always import the `Component` symbol from the Angular core library
@ -89,7 +86,6 @@ Add a `hero` property to the `HeroesComponent` for a hero named "Windstorm."
`HeroesComponent` 中添加一个 `hero` 属性,用来表示一个名叫 “Windstorm” 的英雄。 `HeroesComponent` 中添加一个 `hero` 属性,用来表示一个名叫 “Windstorm” 的英雄。
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="add-hero" title="heroes.component.ts (hero property)" linenums="false"> <code-example path="toh-pt1/src/app/heroes/heroes.component.ts" region="add-hero" title="heroes.component.ts (hero property)" linenums="false">
</code-example> </code-example>
### Show the hero ### Show the hero
@ -103,7 +99,6 @@ replace it with a data binding to the new `hero` property.
打开模板文件 `heroes.component.html`。删除 Angular CLI 自动生成的默认内容,改为到 `hero` 属性的数据绑定。 打开模板文件 `heroes.component.html`。删除 Angular CLI 自动生成的默认内容,改为到 `hero` 属性的数据绑定。
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" title="heroes.component.html" region="show-hero-1" linenums="false"> <code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" title="heroes.component.html" region="show-hero-1" linenums="false">
</code-example> </code-example>
## Show the _HeroesComponent_ view ## Show the _HeroesComponent_ view
@ -121,7 +116,6 @@ So add an `<app-heroes>` element to the `AppComponent` template file, just below
所以,只要把 `<app-heroes>` 元素添加到 `AppComponent` 的模板文件中就可以了,就放在标题下方。 所以,只要把 `<app-heroes>` 元素添加到 `AppComponent` 的模板文件中就可以了,就放在标题下方。
<code-example path="toh-pt1/src/app/app.component.html" title="src/app/app.component.html" linenums="false"> <code-example path="toh-pt1/src/app/app.component.html" title="src/app/app.component.html" linenums="false">
</code-example> </code-example>
Assuming that the CLI `ng serve` command is still running, Assuming that the CLI `ng serve` command is still running,
@ -143,7 +137,6 @@ Give it `id` and `name` properties.
`src/app` 文件夹中为 `Hero` 类创建一个文件,并添加 `id``name` 属性。 `src/app` 文件夹中为 `Hero` 类创建一个文件,并添加 `id``name` 属性。
<code-example path="toh-pt1/src/app/hero.ts" title="src/app/hero.ts" linenums="false"> <code-example path="toh-pt1/src/app/hero.ts" title="src/app/hero.ts" linenums="false">
</code-example> </code-example>
Return to the `HeroesComponent` class and import the `Hero` class. Return to the `HeroesComponent` class and import the `Hero` class.
@ -162,7 +155,6 @@ The revised `HeroesComponent` class file should look like this:
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" linenums="false" <code-example path="toh-pt1/src/app/heroes/heroes.component.ts" linenums="false"
title= "src/app/heroes/heroes.component.ts"> title= "src/app/heroes/heroes.component.ts">
</code-example> </code-example>
The page no longer displays properly because you changed the hero from a string to an object. The page no longer displays properly because you changed the hero from a string to an object.
@ -182,7 +174,6 @@ and show both `id` and `name` in a details layout like this:
path="toh-pt1/src/app/heroes/heroes.component.1.html" path="toh-pt1/src/app/heroes/heroes.component.1.html"
region="show-hero-2" region="show-hero-2"
title="heroes.component.html (HeroesComponent's template)" linenums="false"> title="heroes.component.html (HeroesComponent's template)" linenums="false">
</code-example> </code-example>
The browser refreshes and display's the hero's information. The browser refreshes and display's the hero's information.
@ -200,7 +191,6 @@ Modify the `hero.name` binding like this.
<code-example <code-example
path="toh-pt1/src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html"
region="pipe"> region="pipe">
</code-example> </code-example>
The browser refreshes and now the hero's name is displayed in capital letters. The browser refreshes and now the hero's name is displayed in capital letters.
@ -273,10 +263,8 @@ for a message like
打开浏览器的开发工具,就会在控制台中看到如下信息: 打开浏览器的开发工具,就会在控制台中看到如下信息:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
Template parse errors: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'. Can't bind to 'ngModel' since it isn't a known property of 'input'.
</code-example> </code-example>
Although `ngModel` is a valid Angular directive, it isn't available by default. Although `ngModel` is a valid Angular directive, it isn't available by default.
@ -322,7 +310,6 @@ Open `AppModule` (`app.module.ts`) and import the `FormsModule` symbol from the
<code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts (FormsModule symbol import)" <code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts (FormsModule symbol import)"
region="formsmodule-js-import"> region="formsmodule-js-import">
</code-example> </code-example>
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs. Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
@ -331,7 +318,6 @@ Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which cont
<code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts ( @NgModule imports)" <code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts ( @NgModule imports)"
region="ng-imports"> region="ng-imports">
</code-example> </code-example>
When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox. When the browser refreshes, the app should work again. You can edit the hero's name and see the changes reflected immediately in the `<h2>` above the textbox.
@ -360,7 +346,6 @@ Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
打开 `src/app/app.module.ts` 你就会发现 `HeroesComponent` 已经在顶部导入过了。 打开 `src/app/app.module.ts` 你就会发现 `HeroesComponent` 已经在顶部导入过了。
<code-example path="toh-pt1/src/app/app.module.ts" region="heroes-import" > <code-example path="toh-pt1/src/app/app.module.ts" region="heroes-import" >
</code-example> </code-example>
The `HeroesComponent` is declared in the `@NgModule.declarations` array. The `HeroesComponent` is declared in the `@NgModule.declarations` array.
@ -368,7 +353,6 @@ The `HeroesComponent` is declared in the `@NgModule.declarations` array.
`HeroesComponent` 也已经声明在了 `@NgModule.declarations` 数组中。 `HeroesComponent` 也已经声明在了 `@NgModule.declarations` 数组中。
<code-example path="toh-pt1/src/app/app.module.ts" region="declarations"> <code-example path="toh-pt1/src/app/app.module.ts" region="declarations">
</code-example> </code-example>
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`. Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.
@ -438,4 +422,4 @@ Your app should look like this <live-example></live-example>. Here are the code
* You learned the importance of declaring components in the `AppModule` * You learned the importance of declaring components in the `AppModule`
and appreciated that the CLI declared it for you. and appreciated that the CLI declared it for you.
你知道了把组件声明到 `AppModule` 是很重要的,并认识到 CLI 会自动帮你声明它。 你知道了把组件声明到 `AppModule` 是很重要的,并认识到 CLI 会自动帮你声明它。

View File

@ -32,7 +32,6 @@ The file should look like this.
<code-example path="toh-pt2/src/app/mock-heroes.ts" linenums="false" <code-example path="toh-pt2/src/app/mock-heroes.ts" linenums="false"
title="src/app/mock-heroes.ts"> title="src/app/mock-heroes.ts">
</code-example> </code-example>
## Displaying heroes ## Displaying heroes
@ -48,7 +47,6 @@ Open the `HeroesComponent` class file and import the mock `HEROES`.
打开 `HeroesComponent` 类文件,并导入模拟的 `HEROES` 打开 `HeroesComponent` 类文件,并导入模拟的 `HEROES`
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" title="src/app/heroes/heroes.component.ts (import HEROES)"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="import-heroes" title="src/app/heroes/heroes.component.ts (import HEROES)">
</code-example> </code-example>
Add a `heroes` property to the class that exposes these heroes for binding. Add a `heroes` property to the class that exposes these heroes for binding.
@ -56,7 +54,6 @@ Add a `heroes` property to the class that exposes these heroes for binding.
往类中添加一个 `heroes` 属性,这样可以暴露出这些英雄,以供绑定。 往类中添加一个 `heroes` 属性,这样可以暴露出这些英雄,以供绑定。
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="heroes"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="heroes">
</code-example> </code-example>
### List heroes with _*ngFor_ ### List heroes with _*ngFor_
@ -88,7 +85,6 @@ Make it look like this:
做完之后应该是这样的: 做完之后应该是这样的:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" title="heroes.component.html (heroes template)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="list" title="heroes.component.html (heroes template)" linenums="false">
</code-example> </code-example>
Now change the `<li>` to this: Now change the `<li>` to this:
@ -96,7 +92,6 @@ Now change the `<li>` to this:
现在,把 `<li>` 修改成这样: 现在,把 `<li>` 修改成这样:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="li"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="li">
</code-example> </code-example>
The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive. The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive.
@ -176,7 +171,6 @@ and pointed to it in `@Component.styleUrls` like this.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="metadata" <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="metadata"
title="src/app/heroes/heroes.component.ts (@Component)"> title="src/app/heroes/heroes.component.ts (@Component)">
</code-example> </code-example>
Open the `heroes.component.css` file and paste in the private CSS styles for the `HeroesComponent`. Open the `heroes.component.css` file and paste in the private CSS styles for the `HeroesComponent`.
@ -218,7 +212,6 @@ Add a click event binding to the `<li>` like this:
再往 `<li>` 元素上插入一句点击事件的绑定代码: 再往 `<li>` 元素上插入一句点击事件的绑定代码:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="selectedHero-click" title="heroes.component.html (template excerpt)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="selectedHero-click" title="heroes.component.html (template excerpt)" linenums="false">
</code-example> </code-example>
This is an example of Angular's [event binding](guide/template-syntax#event-binding) syntax. This is an example of Angular's [event binding](guide/template-syntax#event-binding) syntax.
@ -254,7 +247,6 @@ to the component's `selectedHero`.
添加如下 `onSelect()` 方法,它会把模板中被点击的英雄赋值给组件的 `selectedHero` 属性。 添加如下 `onSelect()` 方法,它会把模板中被点击的英雄赋值给组件的 `selectedHero` 属性。
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" title="src/app/heroes/heroes.component.ts (onSelect)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="on-select" title="src/app/heroes/heroes.component.ts (onSelect)" linenums="false">
</code-example> </code-example>
### Update the details template ### Update the details template
@ -268,7 +260,6 @@ Rename `hero` to `selectedHero`.
`hero` 改名为 `selectedHero` `hero` 改名为 `selectedHero`
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" title="heroes.component.html (selected hero details)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="selectedHero-details" title="heroes.component.html (selected hero details)" linenums="false">
</code-example> </code-example>
### Hide empty details with _*ngIf_ ### Hide empty details with _*ngIf_
@ -284,9 +275,7 @@ Open the browser developer tools and look in the console for an error message li
打开浏览器的开发者工具,它的控制台中显示出如下错误信息: 打开浏览器的开发者工具,它的控制台中显示出如下错误信息:
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined
</code-example> </code-example>
Now click one of the list items. Now click one of the list items.
@ -332,7 +321,6 @@ Don't forget the asterisk (*) in front of `ngIf`. It's a critical part of the sy
</div> </div>
<code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="ng-if" title="src/app/heroes/heroes.component.html (*ngIf)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.html" region="ng-if" title="src/app/heroes/heroes.component.html (*ngIf)" linenums="false">
</code-example> </code-example>
After the browser refreshes, the list of names reappears. After the browser refreshes, the list of names reappears.
@ -391,7 +379,6 @@ Add the following `[class.selected]` binding to the `<li>` in the `HeroesCompon
`HeroesComponent` 模板中的 `<li>` 元素上添加 `[class.selected]` 绑定,代码如下: `HeroesComponent` 模板中的 `<li>` 元素上添加 `[class.selected]` 绑定,代码如下:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="class-selected" title="heroes.component.html (toggle the 'selected' CSS class)" linenums="false"> <code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="class-selected" title="heroes.component.html (toggle the 'selected' CSS class)" linenums="false">
</code-example> </code-example>
When the current row hero is the same as the `selectedHero`, Angular adds the `selected` CSS class. When the two heroes are different, Angular removes the class. When the current row hero is the same as the `selectedHero`, Angular adds the `selected` CSS class. When the two heroes are different, Angular removes the class.
@ -421,7 +408,6 @@ Here are the code files discussed on this page, including the `HeroesComponent`
下面是本页面中所提及的代码文件,包括 `HeroesComponent` 的样式。 下面是本页面中所提及的代码文件,包括 `HeroesComponent` 的样式。
<code-tabs> <code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="toh-pt2/src/app/heroes/heroes.component.ts"> <code-pane title="src/app/heroes/heroes.component.ts" path="toh-pt2/src/app/heroes/heroes.component.ts">
</code-pane> </code-pane>
@ -430,7 +416,6 @@ Here are the code files discussed on this page, including the `HeroesComponent`
<code-pane title="src/app/heroes/heroes.component.css" path="toh-pt2/src/app/heroes/heroes.component.css"> <code-pane title="src/app/heroes/heroes.component.css" path="toh-pt2/src/app/heroes/heroes.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
## Summary ## Summary
@ -455,4 +440,4 @@ Here are the code files discussed on this page, including the `HeroesComponent`
* You can toggle a CSS style class with a `class` binding. * You can toggle a CSS style class with a `class` binding.
你可以用 `class` 绑定来切换 CSS 的样式类。 你可以用 `class` 绑定来切换 CSS 的样式类。

View File

@ -12,12 +12,12 @@ You'll want to split up large components into smaller sub-components, each focus
把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。 把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。
你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。 你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。
In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailComponent`. In this page, you'll take the first step in that direction by moving the hero details into a separate, reusable `HeroDetailsComponent`.
本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 `HeroDetailComponent` 本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 `HeroDetailComponent`
The `HeroesComponent` will only present the list of heroes. The `HeroesComponent` will only present the list of heroes.
The `HeroDetailComponent` will present details of a selected hero. The `HeroDetailsComponent` will present details of a selected hero.
`HeroesComponent` 将仅仅用来表示英雄列表。 `HeroesComponent` 将仅仅用来表示英雄列表。
`HeroDetailComponent` 将用来表示所选英雄的详情。 `HeroDetailComponent` 将用来表示所选英雄的详情。
@ -31,9 +31,7 @@ Use the Angular CLI to generate a new component named `hero-detail`.
使用 Angular CLI 生成一个名叫 `hero-detail` 的新组件。 使用 Angular CLI 生成一个名叫 `hero-detail` 的新组件。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component hero-detail ng generate component hero-detail
</code-example> </code-example>
The command scaffolds the `HeroDetailComponent` files and declares the component in `AppModule`. The command scaffolds the `HeroDetailComponent` files and declares the component in `AppModule`.
@ -78,7 +76,6 @@ Open the `HeroDetailComponent` class file and import the `Hero` symbol.
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts"
region="import-hero" title="src/app/hero-detail/hero-detail.component.ts (import Hero)"> region="import-hero" title="src/app/hero-detail/hero-detail.component.ts (import Hero)">
</code-example> </code-example>
The `hero` property The `hero` property
@ -89,7 +86,6 @@ because the _external_ `HeroesComponent` [will bind to it](#heroes-component-tem
`hero` 属性[必须是一个带有 `@Input()` 装饰器的输入属性](guide/template-syntax#inputs-outputs "Input and Output properties"),因为*外部的* `HeroesComponent` 组件[将会绑定到它](#heroes-component-template)。就像这样: `hero` 属性[必须是一个带有 `@Input()` 装饰器的输入属性](guide/template-syntax#inputs-outputs "Input and Output properties"),因为*外部的* `HeroesComponent` 组件[将会绑定到它](#heroes-component-template)。就像这样:
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding"> <code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding">
</code-example> </code-example>
Amend the `@angular/core` import statement to include the `Input` symbol. Amend the `@angular/core` import statement to include the `Input` symbol.
@ -97,7 +93,6 @@ Amend the `@angular/core` import statement to include the `Input` symbol.
修改 `@angular/core` 的导入语句,导入 `Input` 符号。 修改 `@angular/core` 的导入语句,导入 `Input` 符号。
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="import-input" title="src/app/hero-detail/hero-detail.component.ts (import Input)" linenums="false"> <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="import-input" title="src/app/hero-detail/hero-detail.component.ts (import Input)" linenums="false">
</code-example> </code-example>
Add a `hero` property, preceded by the `@Input()` decorator. Add a `hero` property, preceded by the `@Input()` decorator.
@ -105,7 +100,6 @@ Add a `hero` property, preceded by the `@Input()` decorator.
添加一个带有 `@Input()` 装饰器的 `hero` 属性。 添加一个带有 `@Input()` 装饰器的 `hero` 属性。
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false"> <code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false">
</code-example> </code-example>
That's the only change you should make to the `HeroDetailComponent` class. That's the only change you should make to the `HeroDetailComponent` class.
@ -181,7 +175,6 @@ The revised `HeroesComponent` template should look like this:
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" <code-example path="toh-pt3/src/app/heroes/heroes.component.html"
title="heroes.component.html" linenums="false"> title="heroes.component.html" linenums="false">
</code-example> </code-example>
The browser refreshes and the app starts working again as it did before. The browser refreshes and the app starts working again as it did before.
@ -257,5 +250,4 @@ Here are the code files discussed on this page and your app should look like thi
to make the `hero` property available for binding to make the `hero` property available for binding
by the external `HeroesComponent`. by the external `HeroesComponent`.
你用 [`@Input` 装饰器](guide/template-syntax#inputs-outputs)来让 `hero` 属性可以在外部的 `HeroesComponent` 中绑定。 你用 [`@Input` 装饰器](guide/template-syntax#inputs-outputs)来让 `hero` 属性可以在外部的 `HeroesComponent` 中绑定。

View File

@ -52,9 +52,7 @@ Using the Angular CLI, create a service called `hero`.
使用 Angular CLI 创建一个名叫 `hero` 的服务。 使用 Angular CLI 创建一个名叫 `hero` 的服务。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate service hero ng generate service hero
</code-example> </code-example>
The command generates skeleton `HeroService` class in `src/app/hero.service.ts` The command generates skeleton `HeroService` class in `src/app/hero.service.ts`
@ -65,7 +63,6 @@ The `HeroService` class should look like the below.
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new" <code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
title="src/app/hero.service.ts (new service)" linenums="false"> title="src/app/hero.service.ts (new service)" linenums="false">
</code-example> </code-example>
### _@Injectable()_ services ### _@Injectable()_ services
@ -118,7 +115,6 @@ Import the `Hero` and `HEROES`.
导入 `Hero``HEROES` 导入 `Hero``HEROES`
<code-example path="toh-pt4/src/app/hero.service.ts" region="import-heroes"> <code-example path="toh-pt4/src/app/hero.service.ts" region="import-heroes">
</code-example> </code-example>
Add a `getHeroes` method to return the _mock heroes_. Add a `getHeroes` method to return the _mock heroes_.
@ -126,7 +122,6 @@ Add a `getHeroes` method to return the _mock heroes_.
添加一个 `getHeroes` 方法,让它返回*模拟的英雄列表*。 添加一个 `getHeroes` 方法,让它返回*模拟的英雄列表*。
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="getHeroes"> <code-example path="toh-pt4/src/app/hero.service.1.ts" region="getHeroes">
</code-example> </code-example>
{@a provide} {@a provide}
@ -158,9 +153,7 @@ by appending `--module=app`.
这是一个常用的选择,因此你可以通过 `--module=app` 选项让 CLI 自动把它提供给 `AppModule` 这是一个常用的选择,因此你可以通过 `--module=app` 选项让 CLI 自动把它提供给 `AppModule`
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate service hero --module=app ng generate service hero --module=app
</code-example> </code-example>
Since you did not, you'll have to provide it yourself. Since you did not, you'll have to provide it yourself.
@ -172,7 +165,6 @@ Open the `AppModule` class, import the `HeroService`, and add it to the `@NgModu
打开 `AppModule` 类,导入 `HeroService`,并把它加入 `@NgModule.providers` 数组中。 打开 `AppModule` 类,导入 `HeroService`,并把它加入 `@NgModule.providers` 数组中。
<code-example path="toh-pt4/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-heroservice"> <code-example path="toh-pt4/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-heroservice">
</code-example> </code-example>
The `providers` array tells Angular to create a single, shared instance of `HeroService` The `providers` array tells Angular to create a single, shared instance of `HeroService`
@ -215,7 +207,6 @@ Import the `HeroService` instead.
转而导入 `HeroService` 转而导入 `HeroService`
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" title="src/app/heroes/heroes.component.ts (import HeroService)" region="hero-service-import">
</code-example> </code-example>
Replace the definition of the `heroes` property with a simple declaration. Replace the definition of the `heroes` property with a simple declaration.
@ -223,7 +214,6 @@ Replace the definition of the `heroes` property with a simple declaration.
`heroes` 属性的定义改为一句简单的声明。 `heroes` 属性的定义改为一句简单的声明。
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
</code-example> </code-example>
{@a inject} {@a inject}
@ -237,7 +227,6 @@ Add a private `heroService` parameter of type `HeroService` to the constructor.
往构造函数中添加一个私有的 `heroService`,其类型为 `HeroService` 往构造函数中添加一个私有的 `heroService`,其类型为 `HeroService`
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ctor"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ctor">
</code-example> </code-example>
The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site. The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site.
@ -258,7 +247,6 @@ Create a function to retrieve the heroes from the service.
创建一个函数,以从服务中获取这些英雄数据。 创建一个函数,以从服务中获取这些英雄数据。
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes"> <code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
</code-example> </code-example>
{@a oninit} {@a oninit}
@ -285,7 +273,6 @@ let Angular call `ngOnInit` at an appropriate time _after_ constructing a `Heroe
你应该改为在 [*ngOnInit 生命周期钩子*](guide/lifecycle-hooks)中调用 `getHeroes()`,并且等 Angular 构造出 `HeroesComponent` 的实例之后,找个恰当的时机调用 `ngOnInit` 你应该改为在 [*ngOnInit 生命周期钩子*](guide/lifecycle-hooks)中调用 `getHeroes()`,并且等 Angular 构造出 `HeroesComponent` 的实例之后,找个恰当的时机调用 `ngOnInit`
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ng-on-init"> <code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ng-on-init">
</code-example> </code-example>
### See it run ### See it run
@ -311,7 +298,6 @@ as if heroes could be fetched synchronously.
`HeroesComponent` 也同样假设能同步取到 `getHeroes()` 的结果。 `HeroesComponent` 也同样假设能同步取到 `getHeroes()` 的结果。
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="get-heroes"> <code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="get-heroes">
</code-example> </code-example>
This will not work in a real app. This will not work in a real app.
@ -365,7 +351,6 @@ Open the `HeroService` file and import the `Observable` and `of` symbols from Rx
<code-example path="toh-pt4/src/app/hero.service.ts" <code-example path="toh-pt4/src/app/hero.service.ts"
title="src/app/hero.service.ts (Observable imports)" region="import-observable"> title="src/app/hero.service.ts (Observable imports)" region="import-observable">
</code-example> </code-example>
Replace the `getHeroes` method with this one. Replace the `getHeroes` method with this one.
@ -478,9 +463,7 @@ Use the CLI to create the `MessagesComponent`.
使用 CLI 创建 `MessagesComponent` 使用 CLI 创建 `MessagesComponent`
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component messages ng generate component messages
</code-example> </code-example>
The CLI creates the component files in the `src/app/messages` folder and declare `MessagesComponent` in `AppModule`. The CLI creates the component files in the `src/app/messages` folder and declare `MessagesComponent` in `AppModule`.
@ -494,7 +477,6 @@ Modify the `AppComponent` template to display the generated `MessagesComponent`
<code-example <code-example
title = "/src/app/app.component.html" title = "/src/app/app.component.html"
path="toh-pt4/src/app/app.component.html"> path="toh-pt4/src/app/app.component.html">
</code-example> </code-example>
You should see the default paragraph from `MessagesComponent` at the bottom of the page. You should see the default paragraph from `MessagesComponent` at the bottom of the page.
@ -512,9 +494,7 @@ The `--module=app` option tells the CLI to [_provide_ this service](#provide) i
`--module=app` 选项告诉 CLI 在 `AppModule` 中[提供这个服务](#provide)。 `--module=app` 选项告诉 CLI 在 `AppModule` 中[提供这个服务](#provide)。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate service message --module=app ng generate service message --module=app
</code-example> </code-example>
Open `MessageService` and replace its contents with the following. Open `MessageService` and replace its contents with the following.
@ -524,7 +504,6 @@ Open `MessageService` and replace its contents with the following.
<code-example <code-example
title = "/src/app/message.service.ts" title = "/src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts"> path="toh-pt4/src/app/message.service.ts">
</code-example> </code-example>
The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache. The service exposes its cache of `messages` and two methods: one to `add()` a message to the cache and another to `clear()` the cache.
@ -544,7 +523,6 @@ Re-open the `HeroService` and import the `MessageService`.
<code-example <code-example
title = "/src/app/hero.service.ts (import MessageService)" title = "/src/app/hero.service.ts (import MessageService)"
path="toh-pt4/src/app/hero.service.ts" region="import-message-service"> path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
</code-example> </code-example>
Modify the constructor with a parameter that declares a private `messageService` property. Modify the constructor with a parameter that declares a private `messageService` property.
@ -556,7 +534,6 @@ Angular 将会在创建 `HeroService` 时把 `MessageService` 的单例注入到
<code-example <code-example
path="toh-pt4/src/app/hero.service.ts" region="ctor"> path="toh-pt4/src/app/hero.service.ts" region="ctor">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -578,7 +555,6 @@ Modify the `getHeroes` method to send a message when the heroes are fetched.
修改 `getHeroes` 方法,在获取到英雄数组时发送一条消息。 修改 `getHeroes` 方法,在获取到英雄数组时发送一条消息。
<code-example path="toh-pt4/src/app/hero.service.ts" region="getHeroes"> <code-example path="toh-pt4/src/app/hero.service.ts" region="getHeroes">
</code-example> </code-example>
### Display the message from `HeroService` ### Display the message from `HeroService`
@ -598,19 +574,17 @@ Open `MessagesComponent` and import the `MessageService`.
<code-example <code-example
title = "/src/app/messages/messages.component.ts (import MessageService)" title = "/src/app/messages/messages.component.ts (import MessageService)"
path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service"> path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service">
</code-example> </code-example>
Modify the constructor with a parameter that declares a **public** `messageService` property. Modify the constructor with a parameter that declares a **public** `messageService` property.
Angular will inject the singleton `MessageService` into that property Angular will inject the singleton `MessageService` into that property
when it creates the `MessagesComponent`. when it creates the `HeroService`.
修改构造函数,添加一个 **public**`messageService` 属性。 修改构造函数,添加一个 **public**`messageService` 属性。
Angular 将会在创建 `MessagesComponent` 的实例时 把 `MessageService` 的实例注入到这个属性中。 Angular 将会在创建 `MessagesComponent` 的实例时 把 `MessageService` 的实例注入到这个属性中。
<code-example <code-example
path="toh-pt4/src/app/messages/messages.component.ts" region="ctor"> path="toh-pt4/src/app/messages/messages.component.ts" region="ctor">
</code-example> </code-example>
The `messageService` property **must be public** because you're about to bind to it in the template. The `messageService` property **must be public** because you're about to bind to it in the template.
@ -636,7 +610,6 @@ Replace the CLI-generated `MessagesComponent` template with the following.
<code-example <code-example
title = "src/app/messages/messages.component.html" title = "src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html"> path="toh-pt4/src/app/messages/messages.component.html">
</code-example> </code-example>
This template binds directly to the component's `messageService`. This template binds directly to the component's `messageService`.
@ -754,4 +727,4 @@ Here are the code files discussed on this page and your app should look like thi
* The `HeroService` injected into a component is created with another injected service, * The `HeroService` injected into a component is created with another injected service,
`MessageService`. `MessageService`.
`HeroService` 连同注入到它的服务 `MessageService` 一起,注入到了组件中。 `HeroService` 连同注入到它的服务 `MessageService` 一起,注入到了组件中。

View File

@ -50,9 +50,7 @@ Use the CLI to generate it.
使用 CLI 生成它。 使用 CLI 生成它。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate module app-routing --flat --module=app ng generate module app-routing --flat --module=app
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -71,7 +69,6 @@ The generated file looks like this:
<code-example path="toh-pt5/src/app/app-routing.module.0.ts" <code-example path="toh-pt5/src/app/app-routing.module.0.ts"
title="src/app/app-routing.module.ts (generated)"> title="src/app/app-routing.module.ts (generated)">
</code-example> </code-example>
You generally don't declare components in a routing module so you can delete the You generally don't declare components in a routing module so you can delete the
@ -98,7 +95,6 @@ in the `AppModule` components that will need them.
<code-example path="toh-pt5/src/app/app-routing.module.ts" <code-example path="toh-pt5/src/app/app-routing.module.ts"
region="v1" region="v1"
title="src/app/app-routing.module.ts (v1)"> title="src/app/app-routing.module.ts (v1)">
</code-example> </code-example>
### Add routes ### Add routes
@ -134,7 +130,6 @@ Then define an array of routes with a single `route` to that component.
<code-example path="toh-pt5/src/app/app-routing.module.ts" <code-example path="toh-pt5/src/app/app-routing.module.ts"
region="heroes-route"> region="heroes-route">
</code-example> </code-example>
Once you've finished setting up, the router will match that URL to `path: 'heroes'` Once you've finished setting up, the router will match that URL to `path: 'heroes'`
@ -157,7 +152,6 @@ configure it with the `routes` in one step by calling
<code-example path="toh-pt5/src/app/app-routing.module.ts" <code-example path="toh-pt5/src/app/app-routing.module.ts"
region="ngmodule-imports"> region="ngmodule-imports">
</code-example> </code-example>
<div class="l-sub-section"> <div class="l-sub-section">
@ -182,7 +176,6 @@ Open the `AppComponent` template replace the `<app-heroes>` element with a `<rou
<code-example path="toh-pt5/src/app/app.component.html" <code-example path="toh-pt5/src/app/app.component.html"
region="outlet" region="outlet"
title="src/app/app.component.html (router-outlet)"> title="src/app/app.component.html (router-outlet)">
</code-example> </code-example>
You removed `<app-heroes>` because you will only display the `HeroesComponent` when the user navigates to it. You removed `<app-heroes>` because you will only display the `HeroesComponent` when the user navigates to it.
@ -211,9 +204,7 @@ You should still be running with this CLI command.
你的 CLI 命令应该仍在运行吧。 你的 CLI 命令应该仍在运行吧。
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng serve ng serve
</code-example> </code-example>
The browser should refresh and display the app title but not the list of heroes. The browser should refresh and display the app title but not the list of heroes.
@ -255,7 +246,6 @@ The revised `AppComponent` template looks like this:
path="toh-pt5/src/app/app.component.html" path="toh-pt5/src/app/app.component.html"
region="heroes" region="heroes"
title="src/app/app.component.html (heroes RouterLink)"> title="src/app/app.component.html (heroes RouterLink)">
</code-example> </code-example>
A [`routerLink` attribute](#routerlink) is set to `"/heroes"`, A [`routerLink` attribute](#routerlink) is set to `"/heroes"`,
@ -301,9 +291,7 @@ Add a `DashboardComponent` using the CLI:
使用 CLI 添加一个 `DashboardComponent` 使用 CLI 添加一个 `DashboardComponent`
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component dashboard ng generate component dashboard
</code-example> </code-example>
The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`. The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`.
@ -315,7 +303,6 @@ Replace the default file content in these three files as follows and then return
把这三个文件中的内容改成这样,并回来做一个随堂讨论: 把这三个文件中的内容改成这样,并回来做一个随堂讨论:
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.1.html"> title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.1.html">
</code-pane> </code-pane>
@ -327,7 +314,6 @@ Replace the default file content in these three files as follows and then return
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css"> title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
The _template_ presents a grid of hero name links. The _template_ presents a grid of hero name links.
@ -368,7 +354,6 @@ This `getHeroes` reduces the number of heroes displayed to four
这个 `getHeroes` 函数把要显示的英雄的数量缩减为四个(第二、第三、第四、第五)。 这个 `getHeroes` 函数把要显示的英雄的数量缩减为四个(第二、第三、第四、第五)。
<code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" region="getHeroes"> <code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" region="getHeroes">
</code-example> </code-example>
### Add the dashboard route ### Add the dashboard route
@ -387,7 +372,6 @@ Import the `DashboardComponent` in the `AppRoutingModule`.
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="import-dashboard" region="import-dashboard"
title="src/app/app-routing.module.ts (import DashboardComponent)"> title="src/app/app-routing.module.ts (import DashboardComponent)">
</code-example> </code-example>
Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`. Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`.
@ -397,7 +381,6 @@ Add a route to the `AppRoutingModule.routes` array that matches a path to the `D
<code-example <code-example
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="dashboard-route"> region="dashboard-route">
</code-example> </code-example>
### Add a default route ### Add a default route
@ -418,7 +401,6 @@ route to the `AppRoutingModule.Routes` array.
要让应用自动导航到这个仪表盘,请把下列路由添加到 `AppRoutingModule.Routes` 数组中。 要让应用自动导航到这个仪表盘,请把下列路由添加到 `AppRoutingModule.Routes` 数组中。
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="redirect-route"> <code-example path="toh-pt5/src/app/app-routing.module.ts" region="redirect-route">
</code-example> </code-example>
This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`. This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`.
@ -445,7 +427,6 @@ Add a dashboard navigation link to the `AppComponent` shell template, just above
把仪表盘的导航链接添加到壳组件 `AppComponent` 的模板中,就放在 *Heroes* 链接的前面。 把仪表盘的导航链接添加到壳组件 `AppComponent` 的模板中,就放在 *Heroes* 链接的前面。
<code-example path="toh-pt5/src/app/app.component.html" title="src/app/app.component.html"> <code-example path="toh-pt5/src/app/app.component.html" title="src/app/app.component.html">
</code-example> </code-example>
After the browser refreshes you can navigate freely between the two views by clicking the links. After the browser refreshes you can navigate freely between the two views by clicking the links.
@ -523,7 +504,6 @@ Open `AppRoutingModule` and import `HeroDetailComponent`.
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="import-herodetail" region="import-herodetail"
title="src/app/app-routing.module.ts (import HeroDetailComponent)"> title="src/app/app-routing.module.ts (import HeroDetailComponent)">
</code-example> </code-example>
Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view. Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view.
@ -533,7 +513,6 @@ Then add a _parameterized_ route to the `AppRoutingModule.routes` array that mat
<code-example <code-example
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="detail-route"> region="detail-route">
</code-example> </code-example>
The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`. The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`.
@ -548,7 +527,6 @@ At this point, all application routes are in place.
path="toh-pt5/src/app/app-routing.module.ts" path="toh-pt5/src/app/app-routing.module.ts"
region="routes" region="routes"
title="src/app/app-routing.module.ts (all routes)"> title="src/app/app-routing.module.ts (all routes)">
</code-example> </code-example>
### `DashboardComponent` hero links ### `DashboardComponent` hero links
@ -569,7 +547,6 @@ fix the dashboard hero links to navigate via the _parameterized_ dashboard route
path="toh-pt5/src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html"
region="click" region="click"
title="src/app/dashboard/dashboard.component.html (hero links)"> title="src/app/dashboard/dashboard.component.html (hero links)">
</code-example> </code-example>
You're using Angular [interpolation binding](guide/template-syntax#interpolation) within the `*ngFor` repeater You're using Angular [interpolation binding](guide/template-syntax#interpolation) within the `*ngFor` repeater
@ -593,7 +570,6 @@ are bound to the component's `onSelect()` method.
path="toh-pt4/src/app/heroes/heroes.component.html" path="toh-pt4/src/app/heroes/heroes.component.html"
region="list" region="list"
title="src/app/heroes/heroes.component.html (list with onSelect)"> title="src/app/heroes/heroes.component.html (list with onSelect)">
</code-example> </code-example>
Strip the `<li>` back to just its `*ngFor`, Strip the `<li>` back to just its `*ngFor`,
@ -608,7 +584,6 @@ is the same as in the dashboard template
path="toh-pt5/src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html"
region="list" region="list"
title="src/app/heroes/heroes.component.html (list with links)"> title="src/app/heroes/heroes.component.html (list with links)">
</code-example> </code-example>
You'll have to fix the private stylesheet (`heroes.component.css`) to make You'll have to fix the private stylesheet (`heroes.component.css`) to make
@ -637,7 +612,6 @@ Here's the class after pruning away the dead code.
path="toh-pt5/src/app/heroes/heroes.component.ts" path="toh-pt5/src/app/heroes/heroes.component.ts"
region="class" region="class"
title="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false"> title="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false">
</code-example> </code-example>
## Routable *HeroDetailComponent* ## Routable *HeroDetailComponent*
@ -679,7 +653,6 @@ Add the following imports:
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" path="toh-pt5/src/app/hero-detail/hero-detail.component.ts"
region="added-imports" region="added-imports"
title="src/app/hero-detail/hero-detail.component.ts"> title="src/app/hero-detail/hero-detail.component.ts">
</code-example> </code-example>
{@a hero-detail-ctor} {@a hero-detail-ctor}
@ -691,7 +664,6 @@ into the constructor, saving their values in private fields:
<code-example <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ctor"> path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ctor">
</code-example> </code-example>
The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`. The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`.
@ -725,7 +697,6 @@ call `getHero()` and define it as follows.
<code-example <code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ngOnInit"> path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ngOnInit">
</code-example> </code-example>
The `route.snapshot` is a static image of the route information shortly after the component was created. The `route.snapshot` is a static image of the route information shortly after the component was created.
@ -764,7 +735,6 @@ Open `HeroService` and add this `getHero()` method
path="toh-pt5/src/app/hero.service.ts" path="toh-pt5/src/app/hero.service.ts"
region="getHero" region="getHero"
title="src/app/hero.service.ts (getHero)"> title="src/app/hero.service.ts (getHero)">
</code-example> </code-example>
<div class="alert is-important"> <div class="alert is-important">
@ -829,7 +799,6 @@ to the component's `goBack()` method.
path="toh-pt5/src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html"
region="back-button" region="back-button"
title="src/app/hero-detail/hero-detail.component.html (back button)"> title="src/app/hero-detail/hero-detail.component.html (back button)">
</code-example> </code-example>
Add a `goBack()` _method_ to the component class that navigates backward one step Add a `goBack()` _method_ to the component class that navigates backward one step
@ -870,7 +839,6 @@ Here are the code files discussed on this page and your app should look like thi
#### `AppRoutingModule`、`AppModule` 和 `HeroService` #### `AppRoutingModule`、`AppModule` 和 `HeroService`
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/app-routing.module.ts" title="src/app/app-routing.module.ts"
path="toh-pt5/src/app/app-routing.module.ts"> path="toh-pt5/src/app/app-routing.module.ts">
@ -883,7 +851,6 @@ Here are the code files discussed on this page and your app should look like thi
title="src/app/hero.service.ts" title="src/app/hero.service.ts"
path="toh-pt5/src/app/hero.service.ts"> path="toh-pt5/src/app/hero.service.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a appcomponent} {@a appcomponent}
@ -891,7 +858,6 @@ Here are the code files discussed on this page and your app should look like thi
#### _AppComponent_ #### _AppComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/app.component.html" title="src/app/app.component.html"
path="toh-pt5/src/app/app.component.html"> path="toh-pt5/src/app/app.component.html">
@ -901,7 +867,6 @@ Here are the code files discussed on this page and your app should look like thi
title="src/app/app.component.css" title="src/app/app.component.css"
path="toh-pt5/src/app/app.component.css"> path="toh-pt5/src/app/app.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a dashboardcomponent} {@a dashboardcomponent}
@ -909,7 +874,6 @@ Here are the code files discussed on this page and your app should look like thi
#### _DashboardComponent_ #### _DashboardComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html"> title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html">
</code-pane> </code-pane>
@ -921,7 +885,6 @@ Here are the code files discussed on this page and your app should look like thi
<code-pane <code-pane
title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css"> title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a heroescomponent} {@a heroescomponent}
@ -929,7 +892,6 @@ Here are the code files discussed on this page and your app should look like thi
#### _HeroesComponent_ #### _HeroesComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html"> title="src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html">
</code-pane> </code-pane>
@ -943,7 +905,6 @@ Here are the code files discussed on this page and your app should look like thi
title="src/app/heroes/heroes.component.css" title="src/app/heroes/heroes.component.css"
path="toh-pt5/src/app/heroes/heroes.component.css"> path="toh-pt5/src/app/heroes/heroes.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a herodetailcomponent} {@a herodetailcomponent}
@ -951,7 +912,6 @@ Here are the code files discussed on this page and your app should look like thi
#### _HeroDetailComponent_ #### _HeroDetailComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html"> title="src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html">
</code-pane> </code-pane>
@ -963,7 +923,6 @@ Here are the code files discussed on this page and your app should look like thi
<code-pane <code-pane
title="src/app/hero-detail/hero-detail.component.css" path="toh-pt5/src/app/hero-detail/hero-detail.component.css"> title="src/app/hero-detail/hero-detail.component.css" path="toh-pt5/src/app/hero-detail/hero-detail.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
## Summary ## Summary
@ -1000,4 +959,4 @@ Here are the code files discussed on this page and your app should look like thi
* You shared the `HeroService` among multiple components. * You shared the `HeroService` among multiple components.
在多个组件之间共享了 `HeroService` 服务。 在多个组件之间共享了 `HeroService` 服务。

View File

@ -89,9 +89,7 @@ Install the *In-memory Web API* package from _npm_
`npm` 中安装这个*内存 Web API* 包(译注:请使用 0.5+ 的版本,不要使用 0.4- `npm` 中安装这个*内存 Web API* 包(译注:请使用 0.5+ 的版本,不要使用 0.4-
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
npm install angular-in-memory-web-api --save npm install angular-in-memory-web-api --save
</code-example> </code-example>
Import the `InMemoryWebApiModule` and the `InMemoryDataService` class, Import the `InMemoryWebApiModule` and the `InMemoryDataService` class,
@ -103,7 +101,6 @@ which you will create in a moment.
path="toh-pt6/src/app/app.module.ts" path="toh-pt6/src/app/app.module.ts"
region="import-in-mem-stuff" region="import-in-mem-stuff"
title="src/app/app.module.ts (In-memory Web API imports)"> title="src/app/app.module.ts (In-memory Web API imports)">
</code-example> </code-example>
Add the `InMemoryWebApiModule` to the `@NgModule.imports` array&mdash; Add the `InMemoryWebApiModule` to the `@NgModule.imports` array&mdash;
@ -116,7 +113,6 @@ _after importing the `HttpClient`_,
<code-example <code-example
path="toh-pt6/src/app/app.module.ts" path="toh-pt6/src/app/app.module.ts"
region="in-mem-web-api-imports"> region="in-mem-web-api-imports">
</code-example> </code-example>
The `forRoot()` configuration method takes an `InMemoryDataService` class The `forRoot()` configuration method takes an `InMemoryDataService` class
@ -157,7 +153,6 @@ Import some HTTP symbols that you'll need:
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="import-httpclient" region="import-httpclient"
title="src/app/hero.service.ts (import HTTP symbols)"> title="src/app/hero.service.ts (import HTTP symbols)">
</code-example> </code-example>
Inject `HttpClient` into the constructor in a private property called `http`. Inject `HttpClient` into the constructor in a private property called `http`.
@ -167,7 +162,6 @@ Inject `HttpClient` into the constructor in a private property called `http`.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="ctor" > region="ctor" >
</code-example> </code-example>
Keep injecting the `MessageService`. You'll call it so frequently that Keep injecting the `MessageService`. You'll call it so frequently that
@ -178,7 +172,6 @@ you'll wrap it in private `log` method.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="log" > region="log" >
</code-example> </code-example>
Define the `heroesUrl` with the address of the heroes resource on the server. Define the `heroesUrl` with the address of the heroes resource on the server.
@ -188,7 +181,6 @@ Define the `heroesUrl` with the address of the heroes resource on the server.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="heroesUrl" > region="heroesUrl" >
</code-example> </code-example>
### Get heroes with _HttpClient_ ### Get heroes with _HttpClient_
@ -205,7 +197,6 @@ as an `Observable<Hero[]>`.
path="toh-pt4/src/app/hero.service.ts" path="toh-pt4/src/app/hero.service.ts"
region="getHeroes-1" region="getHeroes-1"
title="src/app/hero.service.ts (getHeroes with RxJs 'of()')"> title="src/app/hero.service.ts (getHeroes with RxJs 'of()')">
</code-example> </code-example>
Convert that method to use `HttpClient` Convert that method to use `HttpClient`
@ -215,7 +206,6 @@ Convert that method to use `HttpClient`
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="getHeroes-1"> region="getHeroes-1">
</code-example> </code-example>
Refresh the browser. The hero data should successfully load from the Refresh the browser. The hero data should successfully load from the
@ -304,7 +294,6 @@ Import the `catchError` symbol from `rxjs/operators`, along with some other oper
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="import-rxjs-operators"> region="import-rxjs-operators">
</code-example> </code-example>
Now extend the observable result with the `.pipe()` method and Now extend the observable result with the `.pipe()` method and
@ -315,7 +304,6 @@ give it a `catchError()` operator.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="getHeroes-2" > region="getHeroes-2" >
</code-example> </code-example>
The `catchError()` operator intercepts an **`Observable` that failed**. The `catchError()` operator intercepts an **`Observable` that failed**.
@ -344,7 +332,6 @@ has configured with both the name of the operation that failed and a safe return
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="handleError"> region="handleError">
</code-example> </code-example>
After reporting the error to console, the handler constructs After reporting the error to console, the handler constructs
@ -381,7 +368,6 @@ Here is the final version of `getHeroes` with the `tap` that logs the operation.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="getHeroes" > region="getHeroes" >
</code-example> </code-example>
### Get hero by id ### Get hero by id
@ -459,7 +445,6 @@ on the server.
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="updateHero" region="updateHero"
title="src/app/hero.service.ts (update)"> title="src/app/hero.service.ts (update)">
</code-example> </code-example>
The `HttpClient.put()` method takes three parameters The `HttpClient.put()` method takes three parameters
@ -491,7 +476,6 @@ That header is in the `httpOptions` constant defined in the `HeroService`.
<code-example <code-example
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="http-options"> region="http-options">
</code-example> </code-example>
Refresh the browser, change a hero name, save your change, Refresh the browser, change a hero name, save your change,
@ -690,7 +674,6 @@ Start by adding a `searchHeroes` method to the `HeroService`.
path="toh-pt6/src/app/hero.service.ts" path="toh-pt6/src/app/hero.service.ts"
region="searchHeroes" region="searchHeroes"
title="src/app/hero.service.ts"> title="src/app/hero.service.ts">
</code-example> </code-example>
The method returns immediately with an empty array if there is no search term. The method returns immediately with an empty array if there is no search term.
@ -713,7 +696,6 @@ Add the hero search element, `<app-hero-search>`, to the bottom of the `Dashboar
<code-example <code-example
path="toh-pt6/src/app/dashboard/dashboard.component.html" title="src/app/dashboard/dashboard.component.html" linenums="false"> path="toh-pt6/src/app/dashboard/dashboard.component.html" title="src/app/dashboard/dashboard.component.html" linenums="false">
</code-example> </code-example>
This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template. This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template.
@ -739,9 +721,7 @@ Create a `HeroSearchComponent` with the CLI.
使用 CLI 创建一个 `HeroSearchComponent` 使用 CLI 创建一个 `HeroSearchComponent`
<code-example language="sh" class="code-shell"> <code-example language="sh" class="code-shell">
ng generate component hero-search ng generate component hero-search
</code-example> </code-example>
The CLI generates the three `HeroSearchComponent` and adds the component to the `AppModule' declarations The CLI generates the three `HeroSearchComponent` and adds the component to the `AppModule' declarations
@ -811,7 +791,6 @@ Notice the declaration of `heroes$` as an `Observable`
<code-example <code-example
path="toh-pt6/src/app/hero-search/hero-search.component.ts" path="toh-pt6/src/app/hero-search/hero-search.component.ts"
region="heroes-stream"> region="heroes-stream">
</code-example> </code-example>
You'll set it in [`ngOnInit()`](#search-pipe). You'll set it in [`ngOnInit()`](#search-pipe).
@ -876,7 +855,6 @@ Here's the code.
<code-example <code-example
path="toh-pt6/src/app/hero-search/hero-search.component.ts" path="toh-pt6/src/app/hero-search/hero-search.component.ts"
region="search"> region="search">
</code-example> </code-example>
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds * `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
@ -960,7 +938,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
#### _HeroService_, _InMemoryDataService_, _AppModule_ #### _HeroService_, _InMemoryDataService_, _AppModule_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="hero.service.ts" title="hero.service.ts"
path="toh-pt6/src/app/hero.service.ts"> path="toh-pt6/src/app/hero.service.ts">
@ -973,7 +950,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
title="app.module.ts" title="app.module.ts"
path="toh-pt6/src/app/app.module.ts"> path="toh-pt6/src/app/app.module.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a heroescomponent} {@a heroescomponent}
@ -981,7 +957,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
#### _HeroesComponent_ #### _HeroesComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="heroes/heroes.component.html" title="heroes/heroes.component.html"
path="toh-pt6/src/app/heroes/heroes.component.html"> path="toh-pt6/src/app/heroes/heroes.component.html">
@ -994,7 +969,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
title="heroes/heroes.component.css" title="heroes/heroes.component.css"
path="toh-pt6/src/app/heroes/heroes.component.css"> path="toh-pt6/src/app/heroes/heroes.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a herodetailcomponent} {@a herodetailcomponent}
@ -1002,7 +976,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
#### _HeroDetailComponent_ #### _HeroDetailComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="hero-detail/hero-detail.component.html" title="hero-detail/hero-detail.component.html"
path="toh-pt6/src/app/hero-detail/hero-detail.component.html"> path="toh-pt6/src/app/hero-detail/hero-detail.component.html">
@ -1011,7 +984,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
title="hero-detail/hero-detail.component.ts" title="hero-detail/hero-detail.component.ts"
path="toh-pt6/src/app/hero-detail/hero-detail.component.ts"> path="toh-pt6/src/app/hero-detail/hero-detail.component.ts">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
{@a herosearchcomponent} {@a herosearchcomponent}
@ -1019,7 +991,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
#### _HeroSearchComponent_ #### _HeroSearchComponent_
<code-tabs> <code-tabs>
<code-pane <code-pane
title="hero-search/hero-search.component.html" title="hero-search/hero-search.component.html"
path="toh-pt6/src/app/hero-search/hero-search.component.html"> path="toh-pt6/src/app/hero-search/hero-search.component.html">
@ -1032,7 +1003,6 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
title="hero-search/hero-search.component.css" title="hero-search/hero-search.component.css"
path="toh-pt6/src/app/hero-search/hero-search.component.css"> path="toh-pt6/src/app/hero-search/hero-search.component.css">
</code-pane> </code-pane>
</code-tabs> </code-tabs>
## Summary ## Summary

View File

@ -3,5 +3,5 @@
import { dirs } from '../dirs'; import { dirs } from '../dirs';
import { translateFile } from '../translate'; import { translateFile } from '../translate';
const filename = 'guide/testing.md'; const filename = 'guide/aot-compiler.md';
translateFile(__dirname + '/../../../../../content-en/' + filename, dirs.content + filename); translateFile(__dirname + '/../../../../../content-en/' + filename, dirs.content + filename);

View File

@ -2,4 +2,5 @@ export class DictEntry {
original: string; original: string;
translation: string; translation: string;
sourceFile?: string; sourceFile?: string;
key: string;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
import * as globby from 'globby'; import * as globby from 'globby';
import { DictEntry } from './dict-entry'; import { DictEntry } from './dict-entry';
import { import {
extractOriginalContent,
isNotCnPages, isNotCnPages,
isOnlyBeginTag, isOnlyBeginTag, hasInlineText, kernelText,
normalizeLines, normalizeLines,
originalIsNotChinese, originalIsNotChinese,
originalIsNotCodeExampleTag, originalIsNotCodeExampleTag,
@ -29,7 +30,14 @@ export function gatherTranslations(text: string): DictEntry[] {
const result = []; const result = [];
for (let i = 1; i < lines.length; ++i) { for (let i = 1; i < lines.length; ++i) {
const translation = purifyText(lines[i]); const translation = purifyText(lines[i]);
if (isTranslation(translation)) { if (hasInlineText(translation)) {
const originalContent = extractOriginalContent(translation);
result.push({
key: kernelText(originalContent),
original: originalContent,
translation
});
} else if (isTranslation(translation)) {
const original = purifyText(lines[i - 1]); const original = purifyText(lines[i - 1]);
// 对于包裹在 html tag 中的翻译文本进行特殊处理 // 对于包裹在 html tag 中的翻译文本进行特殊处理
if (isOnlyBeginTag(original)) { if (isOnlyBeginTag(original)) {
@ -38,18 +46,18 @@ export function gatherTranslations(text: string): DictEntry[] {
const thisEndTag = lines[i + 1].trim(); const thisEndTag = lines[i + 1].trim();
if (original === prevBeginTag && prevEndTag === thisEndTag) { if (original === prevBeginTag && prevEndTag === thisEndTag) {
result.push({ result.push({
key: kernelText(lines[i - 3]),
original: lines[i - 3], original: lines[i - 3],
translation: lines[i], translation: lines[i],
}); });
} }
} else { } else {
result.push({original, translation}); result.push({key: kernelText(original), original, translation});
} }
} }
} }
return result return result
.filter(isNotCnPages) .filter(isNotCnPages)
.filter(translationHasNotCodeExample)
.filter(originalIsNotChinese) .filter(originalIsNotChinese)
.filter(originalIsNotSpecialDivTag) .filter(originalIsNotSpecialDivTag)
.filter(originalIsNotCodeExampleTag) .filter(originalIsNotCodeExampleTag)
@ -84,6 +92,7 @@ export function purifyText(text): string {
export function purifyEntry(entry: DictEntry): DictEntry { export function purifyEntry(entry: DictEntry): DictEntry {
return { return {
key: entry.key,
original: purifyText(entry.original), original: purifyText(entry.original),
translation: purifyText(entry.translation), translation: purifyText(entry.translation),
}; };

View File

@ -1,17 +1,13 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { lookup } from './translate'; import { lookup, translate } from './translate';
import { kernelText } from './utils';
describe('根据字典进行翻译', () => { describe('根据字典进行翻译', () => {
it('抽取核心字符', function () {
expect(kernelText(' # Forms ABC. ')).eql('#FormsABC');
});
it('查字典', () => { it('查字典', () => {
expect(lookup('# Forms')[0].translation).eql('# 表单'); expect(lookup('# Forms')[0].translation).eql('# 表单');
}); });
it('对包裹在 a 标签中的内容查字典', () => { it('翻译 header', () => {
expect(translate(`<header></header>`)).eql(``);
}); });
}); });

View File

@ -3,36 +3,46 @@ import * as _ from 'lodash';
import { DictEntry } from './dict-entry'; import { DictEntry } from './dict-entry';
import { dirs } from './dirs'; import { dirs } from './dirs';
import { listMarkdownFiles } from './extractor'; import { listMarkdownFiles } from './extractor';
import { exactlyTest, indentOf, normalizeLines, repeat } from './utils'; import { exactlyTest, extractOriginalContent, indentOf, hasInlineText, kernelText, normalizeLines, repeat } from './utils';
// TODO: 改用 markdown 解析器实现 // TODO: 改用 markdown 解析器实现
export const dict = require('./dict-latest.json') as DictEntry[]; export const dict = require('./dict-latest.json') as DictEntry[];
export function lookup(english: string, filename: RegExp = /.*/): DictEntry[] { export function lookup(english: string): DictEntry[] {
const englishKernel = kernelText(extractOriginalContent(english));
const entries = dict const entries = dict
.filter(entry => filename.test(entry.sourceFile)) .filter(entry => exactlyTest(entry.key, englishKernel));
.filter(entry => exactlyTest(entry.original, english));
return _.uniqBy(entries, 'translation'); return _.uniqBy(entries, 'translation');
} }
function isPureTag(line: string): boolean {
let content = line.trim();
return /^<\/?\w+\b[^>]*>$/.test(content) ||
/^<(\w+)\b[^>]*>\s*<\/\1>$/.test(content);
}
export function translate(content: string): string[] { export function translate(content: string): string[] {
const lines = normalizeLines(content) const lines = normalizeLines(content)
.split(/\n+\s*\n+/); .split(/\n{2,}/);
return lines return lines
.map(line => { .map(line => {
if (!line.trim()) { if (!line.trim() || isPureTag(line)) {
return line; return line;
} }
const translations = lookup(line); const translations = lookup(line);
const indent = indentOf(line); if (translations.length > 0 && hasInlineText(translations[0].translation)) {
const padding = repeat(indent); return translations[0].translation;
if (translations.length === 0) {
return line;
} else if (translations.length === 1) {
return line + '\n\n' + padding + translations[0].translation;
} else { } else {
return line + '\n\n' + padding + translations[translations.length - 1].translation; const indent = indentOf(line);
const padding = repeat(indent);
if (translations.length === 0) {
return line;
} else if (translations.length === 1) {
return line + '\n\n' + padding + translations[0].translation;
} else {
return line + '\n\n' + padding + translations[translations.length - 1].translation;
}
} }
}); });
} }
@ -40,7 +50,7 @@ export function translate(content: string): string[] {
export function translateFile(sourceFile: string, targetFile: string): void { export function translateFile(sourceFile: string, targetFile: string): void {
const content = fs.readFileSync(sourceFile, 'utf-8'); const content = fs.readFileSync(sourceFile, 'utf-8');
const result = translate(content); const result = translate(content);
fs.writeFileSync(targetFile, result.join('\n\n').trim() + '\n', 'utf-8'); fs.writeFileSync(targetFile, result.join('\n\n') + '\n', 'utf-8');
} }
export function translateDirectory(sourceDir: string, targetDir: string): void { export function translateDirectory(sourceDir: string, targetDir: string): void {

View File

@ -1,48 +1,40 @@
import { expect } from 'chai'; import { expect } from 'chai';
import { fuzzyTest, normalizeLines, tokenize } from './utils'; import { fuzzyTest, hasInlineText, kernelText, normalizeLines, tokenize } from './utils';
describe(' 工具函数', () => { describe(' 工具函数', () => {
it('把“1. ”列表处理成空行分隔的格式,以便处理', function () { it('把“1. ”列表处理成空行分隔的格式,以便处理', function () {
const lines = normalizeLines(`1. abc const lines = normalizeLines(`1. abc
11. def 11. def
`); `);
expect(lines).eql(` expect(lines).eql(`1. abc
1. abc
11. def 11. def`);
`);
}); });
it('把“- ”列表处理成空行分隔的格式,以便处理', function () { it('把“- ”列表处理成空行分隔的格式,以便处理', function () {
const lines = normalizeLines(`- abc const lines = normalizeLines(`- abc
- def - def
`); `);
expect(lines).eql(` expect(lines).eql(`- abc
- abc
- def - def`);
`);
}); });
it('把“* ”列表处理成空行分隔的格式,以便处理', function () { it('把“* ”列表处理成空行分隔的格式,以便处理', function () {
const lines = normalizeLines(`* abc const lines = normalizeLines(`* abc
* def * def
`); `);
expect(lines).eql(` expect(lines).eql(`* abc
* abc
* def * def`);
`);
}); });
it('把“# ”标题处理成空行分隔的格式,以便处理', function () { it('把“# ”标题处理成空行分隔的格式,以便处理', function () {
const lines = normalizeLines(`\n# abc const lines = normalizeLines(`\n# abc
def`); def`);
expect(lines).eql(` expect(lines).eql(`# abc
# abc
def def`);
`);
}); });
it('拆解单行的成对 tag', function () { it('拆解单行的成对 tag', function () {
@ -51,13 +43,11 @@ def
<div class="abc">DEF</div> <div class="abc">DEF</div>
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<div class="abc">DEF</div> <div class="abc">DEF</div>
b b`);
`);
}); });
it('拆解单行的自封闭 tag', function () { it('拆解单行的自封闭 tag', function () {
@ -66,13 +56,11 @@ def
<hr/> <hr/>
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<hr/> <hr/>
b b`);
`);
}); });
it('拆解单行的 h\\d 标签', function () { it('拆解单行的 h\\d 标签', function () {
const lines = normalizeLines(` const lines = normalizeLines(`
@ -80,13 +68,11 @@ def
<h3 id="abc">line</h3> <h3 id="abc">line</h3>
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<h3 id="abc">line</h3> <h3 id="abc">line</h3>
b b`);
`);
}); });
it('把多行 hn 处理成单行', function () { it('把多行 hn 处理成单行', function () {
@ -95,9 +81,7 @@ def
abc abc
</h3> </h3>
`); `);
expect(lines).eql(` expect(lines).eql(`<h3 id="nav">abc</h3>`);
<h3 id="nav">abc</h3>
`);
}); });
it('拆解单行的 th 标签', function () { it('拆解单行的 th 标签', function () {
@ -106,8 +90,7 @@ def
<th>line</th> <th>line</th>
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<th> <th>
@ -115,8 +98,7 @@ def
</th> </th>
b b`);
`);
}); });
it('拆解单行注释', function () { it('拆解单行注释', function () {
@ -125,13 +107,11 @@ def
<!-- no --> <!-- no -->
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<!-- no --> <!-- no -->
b b`);
`);
}); });
it('拆解多行注释', function () { it('拆解多行注释', function () {
@ -141,14 +121,12 @@ def
abc --> abc -->
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<!-- no <!-- no
abc --> abc -->
b b`);
`);
}); });
it('拆解单行br', function () { it('拆解单行br', function () {
@ -157,41 +135,83 @@ def
<br class="clear"> <br class="clear">
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
<br class="clear"> <br class="clear">
b b`);
`);
}); });
it('拆解 code-example', function () { it('拆解 code-example', function () {
const lines = normalizeLines(` const lines = normalizeLines(`
<code-example language="sh" class="code-shell"> abc
<code-example
language="sh" class="code-shell">
ng generate directive highlight ng generate directive highlight
</code-example>
def
`); `);
expect(lines).eql(` expect(lines).eql(`abc
<code-example language="sh" class="code-shell">
<code-example
language="sh" class="code-shell">
ng generate directive highlight ng generate directive highlight
`); </code-example>
def`);
}); });
it('不拆解引用的 code-example', function () {
const lines = normalizeLines(`
abc
> <code-example > abc </code-example>
def
`);
expect(lines).eql(`abc
> <code-example > abc </code-example>
def`);
});
it('为单行的 li 和 ul 前后添加空行', function () {
const lines = normalizeLines(`
a
<li>
b
</li>
c
<ul>
</ul>
`);
expect(normalizeLines(lines)).eql(`a
<li>
b
</li>
c
<ul>
</ul>`);
});
it('拆解 @a 标记', function () { it('拆解 @a 标记', function () {
const lines = normalizeLines(` const lines = normalizeLines(`
a a
{@a test} {@a test}
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
{@a test} {@a test}
b b`);
`);
}); });
it('拆解多行代码', function () { it('拆解多行代码', function () {
@ -202,8 +222,7 @@ ng generate directive highlight
\`\`\` \`\`\`
b b
`); `);
expect(lines).eql(` expect(lines).eql(`a
a
\`\`\` \`\`\`
@ -211,43 +230,29 @@ ng generate directive highlight
\`\`\` \`\`\`
b b`);
`);
}); });
it('拆解多行的成对 tag', function () { it('把多行的 p 元素合并成单行', function () {
const lines = normalizeLines(` const lines = normalizeLines(`
<p> <p>
a a
</p> </p>
<p> <p>
</p> </p>
`); `);
expect(lines).eq(` expect(lines).eq(`<p>a</p>
<p>
a <p></p>`);
</p>
<p>
</p>
`);
}); });
it('不要拆解 header', function () { it('不要拆解 header', function () {
const lines = normalizeLines(` const lines = normalizeLines(`
<header>Angular forms don't require a style library</header> <header>Angular forms don't require a style library</header>
`); `);
expect(lines).eq(` expect(lines).eq(`<header>Angular forms don't require a style library</header>`);
<header>Angular forms don't require a style library</header>
`);
}); });
it('拆解独行的 th/td', function () { it('拆解独行的 th/td', function () {
@ -255,20 +260,29 @@ ng generate directive highlight
<td> <td>
abc abc
</td> </td>
`)).eql(` `)).eql(`<td>
<td>
abc abc
</td> </td>`);
`); });
it('拆解 pre', function () {
expect(normalizeLines(`
ABC
<pre>def</pre>
ghi
`)).eql(`ABC
<pre>def</pre>
ghi`);
}); });
it('拆解任意位置的 <tr>', function () { it('拆解任意位置的 <tr>', function () {
expect(normalizeLines(` expect(normalizeLines(`
<tr><td>abc</td></tr> <tr><td>abc</td></tr>
`)).eql(` `)).eql(`<tr>
<tr>
<td> <td>
@ -276,8 +290,7 @@ ng generate directive highlight
</td> </td>
</tr> </tr>`);
`);
}); });
it('拆解独行的 li', function () { it('拆解独行的 li', function () {
expect(normalizeLines(` expect(normalizeLines(`
@ -287,8 +300,7 @@ ng generate directive highlight
<li><a href="#">c</a></li> <li><a href="#">c</a></li>
</ul> </ul>
`)).eql(` `)).eql(`<ul>
<ul>
<li> <li>
@ -308,16 +320,13 @@ ng generate directive highlight
</li> </li>
</ul> </ul>`);
`);
}); });
it('不要拆解行内的 html tag', function () { it('不要拆解行内的 html tag', function () {
expect(normalizeLines(` expect(normalizeLines(`
a <b> c a <b> c
`)).eql(` `)).eql(`a <b> c`);
a <b> c
`);
}); });
it('把连续的三行及以上空行简化为两个空行', function () { it('把连续的三行及以上空行简化为两个空行', function () {
const lines = normalizeLines(` const lines = normalizeLines(`
@ -325,17 +334,23 @@ a <b> c
b`); b`);
expect(lines).eql(` expect(lines).eql(`a
a
b b`);
`);
}); });
it('拆分', function () { it('拆分', function () {
expect(tokenize('abc def,abc.')).eql(['abc', 'def', 'abc']); expect(tokenize('abc def,abc.')).eql(['abc', 'def', 'abc']);
}); });
it('抽取核心字符', function () {
expect(kernelText(' # Forms ABC. ')).eql('#FORMSABC');
});
it('删除非核心字符', function () {
expect(kernelText('Abc-132-@#!abc')).eql('ABC132#ABC');
});
it('模糊匹配', function () { it('模糊匹配', function () {
expect(fuzzyTest(`a b c d e`, `a b c d e`)).is.false; expect(fuzzyTest(`a b c d e`, `a b c d e`)).is.false;
expect(fuzzyTest(`a b c d e f g`, `a b c d e`)).is.false; expect(fuzzyTest(`a b c d e f g`, `a b c d e`)).is.false;
@ -344,4 +359,12 @@ a <b> c
in a helper such as the \`click()\` function below: in a helper such as the \`click()\` function below:
`)).is.true; `)).is.true;
}); });
it('检测是否表格', function () {
expect(hasInlineText(`
abc | def
----|---
gh | ij
`)).eql(true);
});
}); });

View File

@ -51,51 +51,87 @@ export function isHead(line: string): boolean {
} }
export function normalizeLines(text: string): string { export function normalizeLines(text: string): string {
text = '\n' + text + '\n';
// 为列表、标题等自带换行含义的markdown多加一个空行
const blockElementPattern = /(?=\n *(\d+\.|-|\*) )\n/g;
text = text.replace(blockElementPattern, '\n\n');
const hxPattern = /(\n *#+ .*)(?=\n)/g;
text = text.replace(hxPattern, '\n$1\n');
const hxMultilinePattern = /(\n *)<(h\d+)([^>\n]*)>\n+ *(.*)\n+ *(<\/\2>)(?=\n)/g;
text = text.replace(hxMultilinePattern, '\n$1<$2$3>$4</$2>\n');
const oneLinePairedTagPattern = /\n( *)<(p|div|h\d+|code-example|section)( ?[^>\n]*)>([^<\n]*)<\/\2>( *)(?=\n)/g;
text = text.replace(oneLinePairedTagPattern, '\n\n$1<$2$3>$4</$2>$5\n');
const oneLineThTdTagPattern = /\n( *)(?!`)<(th|td|li)( ?[^>\n]*)>(?!`)(.*)<\/\2>( *)(?=\n)/g;
text = text.replace(oneLineThTdTagPattern, '\n\n$1<$2$3>\n\n$1 $4\n\n$1</$2>$5\n');
const oneLineCommentPattern = /\n( *)(<!--[\s\S]*?-->)( *)(?=\n)/g;
text = text.replace(oneLineCommentPattern, '\n\n$1$2$3\n');
const oneLineBrTagPattern = /\n( *)(<br class="clear">)( *)(?=\n)/g;
text = text.replace(oneLineBrTagPattern, '\n\n$1$2$3\n');
// 原文中有 back to top 被分成两行的情况,这里把它标准化一下 // 原文中有 back to top 被分成两行的情况,这里把它标准化一下
const specialBackToTopPattern = /<a href="#toc">Back to top\s+<\/a>/g; const specialBackToTopPattern = /<a href="#toc">Back to top\s+<\/a>/g;
text = text.replace(specialBackToTopPattern, '<a href="#toc">Back to top</a>'); text = text.replace(specialBackToTopPattern, '<a href="#toc">Back to top</a>');
// 原文中有</table为它补齐
text = text.replace(/^ *<\/table$/gm, '</table>');
// 原文中有的换行会干扰生成 html 的格式,替换一下
// tslint:disable:max-line-length
text = text.replace(`<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm">
Get them now</a> if they're not already installed on your machine.
`, `<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm">Get them now</a> if they're not already installed on your machine.
`);
const backToTopPattern = /\n( *)(<a href="#toc">Back to top<\/a>)( *)(?=\n)/g; // 为各种列表多加一个空行
text = text.replace(backToTopPattern, '\n\n$1$2$3\n'); const listElementPattern = /(?=\n *(\d+\.|-|\*) )\n/g;
const atTagCommentPattern = /\n( *)({@a.*})( *)(?=\n)/g; text = text.replace(listElementPattern, '\n\n');
text = text.replace(atTagCommentPattern, '\n\n$1$2$3\n'); // 为标题增加空行
const oneLineClosedTagPattern = /\n( *)<(hr)(\/?)>( *)(?=\n)/g; const hxPattern = /^( *#+ .*)$/gm;
text = text.replace(oneLineClosedTagPattern, '\n\n$1<$2$3>$4\n'); text = text.replace(hxPattern, '\n$1\n');
// 把多行的 HTML 标题或 p 元素变成单行
const hxMultilinePattern = /^( *)<(h\d|p|header)([^>]*)>\s*(.*)\s*<\/\2>$/gm;
text = text.replace(hxMultilinePattern, '\n$1<$2$3>$4</$2>\n');
// 为单行的成对标签前后添加空行
const oneLinePairedTagPattern = /^( *)<(p|div|h\d+|code-example|section)\b([^>]*)>([^\n]*?)<\/\2>( *)$/gm;
text = text.replace(oneLinePairedTagPattern, '\n$1<$2$3>$4</$2>$5\n');
// 为单行的注释前后添加空行
const oneLineCommentPattern = /^( *<!--[\s\S]*?--> *)$/gm;
text = text.replace(oneLineCommentPattern, '\n$1\n');
// 为单行的 back to top 前后添加空行
const backToTopPattern = /^( *<a href="#toc">Back to top<\/a> *)$/gm;
text = text.replace(backToTopPattern, '\n$1\n');
// 为单行的 {@ 语句前后添加空行
const atTagCommentPattern = /^( *{@a.*} *)$/gm;
text = text.replace(atTagCommentPattern, '\n$1\n');
// 为单行的自封闭标签前后添加空行
const oneLineClosedTagPattern = /^( *<hr *\/?>) *$/gm;
text = text.replace(oneLineClosedTagPattern, '\n$1\n');
// 为单行的 <br class="clear"> 前后添加空行
const oneLineBrTagPattern = /^( *<br class="clear"> *)$/gm;
text = text.replace(oneLineBrTagPattern, '\n$1\n');
// 为单独的 div 前后添加空行
const oneLineDivTagPattern = /^( *<\/?(div|li|ul|ol)\b([^>]*)> *)$/gm;
text = text.replace(oneLineDivTagPattern, '\n$1\n');
// 在 pre 前后添加空行
const preBeginTagPattern = /(^ *<pre)/gm;
text = text.replace(preBeginTagPattern, '\n$1');
const preEndTagPattern = /(<\/pre> *)$/gm;
text = text.replace(preEndTagPattern, '$1\n');
const trTagPattern = /( *)(<tr\b *[^>\n]*>)(.*)(<\/tr>)/g; // 为 ``` 前后添加空行
text = text.replace(trTagPattern, '\n\n$1$2\n\n$1 $3\n\n$1$4\n\n'); const multiLineCodePattern = /^( *```\w* *)$/gm;
text = text.replace(multiLineCodePattern, '\n$1\n');
const thTdTagPattern = /( *)(?!`)<(th|td)\b( *[^>\n]*)>(?!`)([\s\S]*?)<\/\2>/g; // 把单行的 tr 拆成多行,以便翻译
const trTagPattern = /^( *)(<tr\b[^>]*>)(.*)(<\/tr>)$/gm;
text = text.replace(trTagPattern, '\n$1$2\n\n$1 $3\n\n$1$4\n');
// 把单行的 th/td/li 等拆成多行,以便翻译,
const oneLineThTdTagPattern = /^( *)<(th|td|li)\b([^>]*)>(.*?)<\/\2>$/gm;
text = text.replace(oneLineThTdTagPattern, '\n$1<$2$3>\n\n$1 $4\n\n$1</$2>\n');
// 把原本就是多行的 th/td 中间添加空行
const thTdTagPattern = /^( *)<(th|td)\b( *[^>]*)>([\s\S]*?)<\/\2>$/gm;
text = text.replace(thTdTagPattern, '\n\n$1<$2$3>\n\n$1 $4\n\n$1</$2>\n\n'); text = text.replace(thTdTagPattern, '\n\n$1<$2$3>\n\n$1 $4\n\n$1</$2>\n\n');
const blockTagPattern = /\n( *)(?!`)<(\/?)(td|th|div|code-example|code-tabs|h\d+|p|tr)\b( *[^>\n]*)>(?!`)( *)(?=\n)/g; // 在所有的起始标签前面加空行
text = text.replace(blockTagPattern, '\n\n$1<$2$3$4>$5\n'); const blockBeginTagPattern = /^( *)<(code-example|code-tabs|pre|p)\b( *[^>]*)>( *)$/gm;
text = text.replace(blockBeginTagPattern, '\n$1<$2$3>$4');
const multiLineCodePattern = /\n( *)```(\w*)( *)(?=\n)/g; // 在所有的结束标签前面加空行
text = text.replace(multiLineCodePattern, '\n\n$1```$2$3\n'); const blockEndTagPattern = /^( *)<\/(code-example|code-tabs|pre|p)>( *)$/gm;
text = text.replace(blockEndTagPattern, '$1</$2>$3\n');
const multipleBlankLinePattern = /\n\s*\n+/g; // 把所有由空格组成的空行都去掉
const blankLinePattern = /^[ \t]+$/gm;
text = text.replace(blankLinePattern, '');
// 把中间的多个回车都变成两个回车
const multipleBlankLinePattern = /\n{2,}/g;
text = text.replace(multipleBlankLinePattern, '\n\n'); text = text.replace(multipleBlankLinePattern, '\n\n');
text = text.replace(/^\n+/, '\n').replace(/\n+$/, '\n'); // 去掉全文头尾的空白
text = text.trim();
return text; return text;
} }
@ -129,14 +165,13 @@ export function fuzzyTest(text1: string, text2: string): boolean {
return sameTokens.length > 5 && sameTokens.length / maxTokens >= 0.8; return sameTokens.length > 5 && sameTokens.length / maxTokens >= 0.8;
} }
export function exactlyTest(text1: string, text2: string): boolean { export function exactlyTest(key: string, text: string): boolean {
return kernelText(text1) === kernelText(text2); return key && key === text;
} }
export function kernelText(text: string): string { export function kernelText(text: string): string {
return text return text
.replace(/[\s\n]+/g, '') .replace(/([^a-zA-Z0-9#:]|\s|\.$)/g, '')
.replace(/\.$/g, '')
.toUpperCase() .toUpperCase()
.trim(); .trim();
} }
@ -146,3 +181,15 @@ export function tokenize(text: string): string[] {
.map(token => token.trim()) .map(token => token.trim())
.filter(token => !!token); .filter(token => !!token);
} }
export function hasInlineText(text: string): boolean {
return /<t>(.*?)<\/t> *<t>.*?<\/t>/g.test(text);
}
export function extractOriginalContent(text: string): string {
if (!hasInlineText(text)) {
return text;
}
return text.replace(/<t>(.*?)<\/t> *<t>.*?<\/t>/gi, '$1')
.replace(/ +/g, ' ');
}