fix: 修正最后一版的全部翻译

This commit is contained in:
Zhicheng Wang 2018-03-03 21:06:01 +08:00
parent 585e377fa8
commit 206f6ecc4f
80 changed files with 6435 additions and 7501 deletions

View File

@ -1,10 +1,18 @@
@description
<div class="nf-container l-flex-wrap flex-center">
<img src="assets/images/support/angular-404.svg" width="300" height="300"/>
<div class="nf-response l-flex-wrap">
<h1 class="no-toc">Page Not Found</h1>
<p>We're sorry. The page you are looking for cannot be found.</p>
</div>
</div>
<aio-file-not-found-search></aio-file-not-found-search>

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@ more fun but also easier to use.
## Overview
## 概
## 概
Angular's animation system lets you build animations that run with the same kind of native
performance found in pure CSS animations. You can also tightly integrate your
@ -21,7 +21,6 @@ animation logic with the rest of your application code, for ease of control.
Angular的动画系统赋予了制作各种动画效果的能力以构建出与原生CSS动画性能相同的动画。
我们也获得了额外的让动画逻辑与其它应用代码紧紧集成在一起的能力,这让动画可以被更容易的触发与控制。
<div class="alert is-helpful">
Angular animations are built on top of the standard [Web Animations API](https://w3c.github.io/web-animations/)
@ -33,6 +32,7 @@ As of Angular 6, If the Web Animations API is not supported natively by the brow
keyframes as a fallback instead (automatically). This means that the polyfill is no longer required unless any
code uses [AnimationBuilder](/api/animations/AnimationBuilder). If your code does use AnimationBuilder, then
uncomment the `web-animations-js` polyfill from the `polyfills.ts` file generated by Angular CLI.
</div>
<div class="l-sub-section">
@ -41,11 +41,12 @@ The examples in this page are available as a <live-example></live-example>.
本章中引用的这个例子可以到<live-example></live-example>去体验。
</div>
## Setup
## 准备工作
Before you can add animations to your application, you need
to import a few animation-specific modules and functions to the root application module.
@ -70,7 +71,6 @@ The buttons trigger changes to the list that all of the example components see a
## 快速起步范例:在两个状态间转场
<img src="generated/images/guide/animations/animation_basic_click.gif" alt="A simple transition animation" class="right">
You can build a simple animation that transitions an element between two states
@ -88,14 +88,10 @@ With these, you can define an *animation trigger* called `heroState` in the comp
metadata. It uses animations to transition between two states: `active` and `inactive`. When a
hero is active, the element appears in a slightly larger size and lighter color.
通过这些,可以在组件元数据中定义一个名叫`heroState`的*动画触发器*。它在两个状态`active``inactive`之间进行转场。
当英雄处于激活状态时,它会把该元素显示得稍微大一点、亮一点。
<code-example path="animations/src/app/hero-list-basic.component.ts" region="animationdef" title="hero-list-basic.component.ts (@Component excerpt)" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-basic.component.ts" region="animationdef" title="hero-list-basic.component.ts (@Component excerpt)" linenums="false"></code-example>
<div class="alert is-helpful">
@ -104,19 +100,14 @@ animation metadata.
在这个例子中,我们在元数据中用内联的方式定义了动画样式(`color``transform`)。在即将到来的一个Angular版本中还将支持从组件的CSS样式表中提取样式。
</div>
Now, using the `[@triggerName]` syntax, attach the animation that you just defined to
one or more elements in the component's template.
我们刚刚定义了一个动画,但它还没有被用到任何地方。要想使用它,可以在模板中用`[@triggerName]`语法来把它附加到一个或多个元素上。
<code-example path="animations/src/app/hero-list-basic.component.ts" region="template" title="hero-list-basic.component.ts (excerpt)" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-basic.component.ts" region="template" title="hero-list-basic.component.ts (excerpt)" linenums="false"></code-example>
Here, the animation trigger applies to every element repeated by an `ngFor`. Each of
the repeated elements animates independently. The value of the
@ -128,13 +119,9 @@ attribute is bound to the expression `hero.state` and is always either `active`
With this setup, an animated transition appears whenever a hero object changes state.
Here's the full component implementation:
通过这些设置,一旦英雄对象的状态发生了变化,就会触发一个转场动画。下面是完整的组件实现:
<code-example path="animations/src/app/hero-list-basic.component.ts" title="hero-list-basic.component.ts">
</code-example>
<code-example path="animations/src/app/hero-list-basic.component.ts" title="hero-list-basic.component.ts"></code-example>
## States and transitions
@ -154,7 +141,7 @@ component's template.
动画状态是一个由程序代码中定义的字符串值。在上面的例子中,基于英雄对象的逻辑状态,我们使用了`'active'``'inactive'`这两种状态。
状态的来源可以是像本例中这样简单的对象属性,也可以是由方法计算出来的值。重点是,我们得能从组件模板中读取它。
We can define *styles* for each animation state:
You can define *styles* for each animation state:
我们可以为每个动画状态定义了*一组样式*
@ -175,30 +162,24 @@ controls the timing of switching between one set of styles and the next:
<code-example path="animations/src/app/hero-list-basic.component.ts" region="transitions" title="src/app/hero-list-basic.component.ts" linenums="false"></code-example>
<figure>
<img src="generated/images/guide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations you define states and transitions between states" width="400">
</figure>
If several transitions have the same timing configuration, you can combine
them into the same `transition` definition:
如果多个转场都有同样的时间线配置,就可以把它们合并进同一个`transition`定义中:
<code-example path="animations/src/app/hero-list-combined-transitions.component.ts" region="transitions" title="src/app/hero-list-combined-transitions.component.ts" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-combined-transitions.component.ts" region="transitions" title="src/app/hero-list-combined-transitions.component.ts" linenums="false"></code-example>
When both directions of a transition have the same timing, as in the previous
example, you can use the shorthand syntax `<=>`:
如果要对同一个转场的两个方向都使用相同的时间线(就像前面的例子中那样),就可以使用`<=>`这种简写语法:
<code-example path="animations/src/app/hero-list-twoway.component.ts" region="transitions" title="src/app/hero-list-twoway.component.ts" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-twoway.component.ts" region="transitions" title="src/app/hero-list-twoway.component.ts" linenums="false"></code-example>
You can also apply a style during an animation but not keep it around
after the animation finishes. You can define such styles inline, in the `transition`. In this example,
@ -206,14 +187,10 @@ the element receives one set of styles immediately and is then animated to the n
When the transition finishes, none of these styles are kept because they're not
defined in a `state`.
有时希望一些样式只在动画期间生效,但在结束后并不保留它们。这时可以把这些样式内联在`transition`中进行定义。
在这个例子中,该元素会立刻获得一组样式,然后动态转场到下一个状态。当转场结束时,这些样式并不会被保留,因为它们并没有被定义在`state`中。
<code-example path="animations/src/app/hero-list-inline-styles.component.ts" region="transitions" title="src/app/hero-list-inline-styles.component.ts" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-inline-styles.component.ts" region="transitions" title="src/app/hero-list-inline-styles.component.ts" linenums="false"></code-example>
### The wildcard state `*`
@ -233,7 +210,9 @@ transitions that apply regardless of which state the animation is in. For exampl
当在*任意*两个状态之间切换时,`* => *`转场都会生效。
<figure>
<img src="generated/images/guide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400">
</figure>
### The `void` state
@ -251,11 +230,12 @@ leave animations.
For example the `* => void` transition applies when the element leaves the view,
regardless of what state it was in before it left.
比如当一个元素离开视图时,`* => void`转场就会生效,而不管它在离场以前是什么状态。
<figure>
<img src="generated/images/guide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400">
</figure>
The wildcard state `*` also matches `void`.
@ -266,7 +246,6 @@ The wildcard state `*` also matches `void`.
## 例子:进场与离场
<img src="generated/images/guide/animations/animation_enter_leave.gif" alt="Enter and leave animations" class="right" width="250">
Using the `void` and `*` states you can define transitions that animate the
@ -287,7 +266,6 @@ the `void => *` and `* => void` syntax to animate the element in and out of the
例如,在下面的`animations`数组中,这两个转场语句使用`void => *``* => void`语法来让该元素以动画形式进入和离开当前视图。
<code-example path="animations/src/app/hero-list-enter-leave.component.ts" region="animationdef" title="hero-list-enter-leave.component.ts (excerpt)" linenums="false"></code-example>
Note that in this case the styles are applied to the void state directly in the
@ -298,7 +276,6 @@ and leaves to the right.
注意,在这个例子中,这些样式在转场定义中被直接应用到了`void`状态,但并没有一个单独的`state(void)`定义。
这么做是因为希望在进场与离场时使用不一样的转换效果:元素从左侧进场,从右侧离开。
<div class="l-sub-section">
These two common animations have their own aliases:
@ -306,8 +283,10 @@ These two common animations have their own aliases:
这两个常见的动画有自己的别名:
<code-example language="typescript">
transition(':enter', [ ... ]); // void => *
transition(':leave', [ ... ]); // * => void
</code-example>
</div>
@ -316,7 +295,6 @@ These two common animations have their own aliases:
## 范例:从不同的状态下进场和离场
<img src="generated/images/guide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" class="right" width="200">
You can also combine this animation with the earlier state transition animation by
@ -344,11 +322,12 @@ is:
This gives you fine-grained control over each transition:
现在就对每一种转场都有了细粒度的控制:
<figure>
<img src="generated/images/guide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400">
</figure>
<code-example path="animations/src/app/hero-list-enter-leave-states.component.ts" region="animationdef" title="hero-list-enter-leave.component.ts (excerpt)" linenums="false"></code-example>
@ -372,7 +351,9 @@ the value as a string with the appropriate suffix:
尺寸类属性(如位置、大小、边框等)包括一个数字值和一个用来定义长度单位的后缀:
* `'50px'`
* `'3em'`
* `'100%'`
If you don't provide a unit when specifying dimension, Angular assumes the default of `px`:
@ -404,13 +385,9 @@ property is computed at runtime and then plugged into the animation.
In this example, the leave animation takes whatever height the element has before it
leaves and animates from that height to zero:
这个例子中的“离场”动画会取得该元素在离场前的高度并且把它从这个高度用动画转场到0高度
<code-example path="animations/src/app/hero-list-auto.component.ts" region="animationdef" title="src/app/hero-list-auto.component.ts" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-auto.component.ts" region="animationdef" title="src/app/hero-list-auto.component.ts" linenums="false"></code-example>
## Animation timing
@ -477,7 +454,6 @@ and the delay (or as the *second* value when there is no delay):
运行200毫秒并且带缓动`'0.2s ease-in-out'`
<img src="generated/images/guide/animations/animation_timings.gif" alt="Animations with specific timings" class="right" width="220">
### Example
@ -488,20 +464,14 @@ Here are a couple of custom timings in action. Both enter and leave last for
200 milliseconds, that is `0.2s`, but they have different easings. The leave begins after a
slight delay of 10 milliseconds as specified in `'0.2s 10 ease-out'`:
这里是两个自定义时间线的动态演示。“进场”和“离场”都持续200毫秒也就是`0.2s`但它们有不同的缓动函数。“离场”动画会在100毫秒的延迟之后开始也就是`'0.2s 10 ease-out'`
<code-example path="animations/src/app/hero-list-timings.component.ts" region="animationdef" title="hero-list-timings.component.ts (excerpt)" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-timings.component.ts" region="animationdef" title="hero-list-timings.component.ts (excerpt)" linenums="false"></code-example>
## Multi-step animations with keyframes
## 基于关键帧(Keyframes)的多阶段动画
<img src="generated/images/guide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" class="right" width="220">
Animation *keyframes* go beyond a simple transition to a more intricate animation
@ -518,13 +488,9 @@ which marks the beginning of the animation, and one, which marks the end.
This example adds some "bounce" to the enter and leave animations with
keyframes:
在这个例子中,我们使用关键帧来为进场和离场动画添加一些“反弹效果”:
<code-example path="animations/src/app/hero-list-multistep.component.ts" region="animationdef" title="hero-list-multistep.component.ts (excerpt)" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-multistep.component.ts" region="animationdef" title="hero-list-multistep.component.ts (excerpt)" linenums="false"></code-example>
Note that the offsets are *not* defined in terms of absolute time. They are relative
measures from zero to one. The final timeline of the animation is based on the combination
@ -538,7 +504,6 @@ offsets receive offsets `0`, `0.5`, and `1`.
为关键帧定义偏移量是可选的。如果省略它们,偏移量会自动根据帧数平均分布出来。例如,三个未定义过偏移量的关键帧会分别获得偏移量:`0``0.5``1`
## Parallel animation groups
## 并行动画组(Group)
@ -560,20 +525,15 @@ For this you can use animation *groups*. In this example, using groups both on
enter and leave allows for two different timing configurations. Both
are applied to the same element in parallel, but run independently of each other:
这种情况下就可以用动画*组*来解决了。在这个例子中,我们同时在进场和离场时使用了组,以便能让它们使用两种不同的时间线配置。
它们被同时应用到同一个元素上,但又彼此独立运行:
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" title="hero-list-groups.component.ts (excerpt)" linenums="false">
</code-example>
<code-example path="animations/src/app/hero-list-groups.component.ts" region="animationdef" title="hero-list-groups.component.ts (excerpt)" linenums="false"></code-example>
One group animates the element transform and width; the other group animates the opacity.
其中一个动画组对元素的`transform``width`做动画,另一个组则对`opacity`做动画。
## Animation callbacks
## 动画回调
@ -596,4 +556,5 @@ The callbacks receive an `AnimationEvent` that contains useful properties such a
Those callbacks will fire whether or not an animation is picked up.
无论动画是否实际执行过,那些回调都会触发。

View File

@ -29,13 +29,16 @@ the components and templates must be converted to executable JavaScript by an _A
Angular offers two ways to compile your application:
1. **_Just-in-Time_ (JIT)**, which compiles your app in the browser at runtime
1. **_Ahead-of-Time_ (AOT)**, which compiles your app at build time.
JIT compilation is the default when you run the _build-only_ or the _build-and-serve-locally_ CLI commands:
<code-example language="sh" class="code-shell">
ng build
ng serve
</code-example>
{@a compile}
@ -43,8 +46,10 @@ JIT compilation is the default when you run the _build-only_ or the _build-and-s
For AOT compilation, append the `--aot` flags to the _build-only_ or the _build-and-serve-locally_ CLI commands:
<code-example language="sh" class="code-shell">
ng build --aot
ng serve --aot
</code-example>
<div class="l-sub-section">
@ -288,7 +293,6 @@ rules.
*Note*: Is it not recommended to use this option as it is not yet feature complete with the Render2 code generation.
## Angular Metadata and AOT
## Angular 元数据与 AOT
@ -390,6 +394,7 @@ Angular 的 [schema.ts](https://github.com/angular/angular/blob/master/packages/
</div>
{@a expression-syntax}
### Expression syntax
The _collector_ only understands a subset of JavaScript.
@ -444,6 +449,7 @@ Angular 库通过这个选项来确保所有的 `.metadata.json` 文件都是干
{@a function-expression}
{@a arrow-functions}
### No arrow functions
The AOT compiler does not support [function expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function)
@ -479,6 +485,7 @@ export function serverFactory() {
Beginning in version 5, the compiler automatically performs this rewritting while emitting the `.js` file.
{@a function-calls}
### Limited function calls
The _collector_ can represent a function call or object creation with `new` as long as the syntax is valid. The _collector_ only cares about proper syntax.
@ -486,8 +493,8 @@ The _collector_ can represent a function call or object creation with `new` as l
But beware. The compiler may later refuse to generate a call to a _particular_ function or creation of a _particular_ object.
The compiler only supports calls to a small set of functions and will use `new` for only a few designated classes. These functions and classes are in a table of [below](#supported-functions).
### Folding
{@a exported-symbols}
The compiler can only resolve references to **_exported_** symbols.
Fortunately, the _collector_ enables limited use of non-exported symbols through _folding_.
@ -578,7 +585,6 @@ Parentheses | yes, if the expression is foldable
If an expression is not foldable, the collector writes it to `.metadata.json` as an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) for the compiler to resolve.
## Phase 2: code generation
The _collector_ makes no attempt to understand the metadata that it collects and outputs to `.metadata.json`. It represents the metadata as best it can and records errors when it detects a metadata syntax violation.
@ -607,7 +613,6 @@ export class AppComponent {
{@a supported-functions}
Most importantly, the compiler only generates code to create instances of certain classes, support certain decorators, and call certain functions from the following lists.
### New instances
The compiler only allows metadata that create instances of the class `InjectionToken` from `@angular/core`.
@ -637,7 +642,6 @@ Decorator | Module
`SkipSelf` | `@angular/core`
`ViewChild` | `@angular/core`
### Macro-functions and macro-static methods
The compiler also supports _macros_ in the form of functions or static
@ -685,8 +689,6 @@ for these methods to see how macros can simplify configuration of complex [NgMod
The compiler treats object literals containing the fields `useClass`, `useValue`, `useFactory`, and `data` specially. The compiler converts the expression initializing one of these fields into an exported variable, which replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because
the compiler doesn't need to know the expression's value&mdash;it just needs to be able to generate a reference to the value.
You might write something like:
```typescript
@ -722,7 +724,6 @@ factory without having to know what the value of `ɵ0` contains.
The compiler does the rewriting during the emit of the `.js` file. This doesn't rewrite the `.d.ts` file, however, so TypeScript doesn't recognize it as being an export. Thus, it does not pollute the ES module's exported API.
## Metadata Errors
The following are metadata errors you may encounter, with explanations and suggested corrections.
@ -770,6 +771,7 @@ and be wary of new or unusual TypeScript features.
<hr>
{@a reference-to-a-local-symbol}
<h3 class="no-toc">Reference to a local (non-exported) symbol</h3>
<div class="alert is-helpful">
@ -808,7 +810,8 @@ The compiler will [fold](#folding) the expression into the provider as if you ha
```
providers: [
{ provide: Foo, useValue: 42 }
]```
]
```
Alternatively, you can fix it by exporting `foo` with the expectation that `foo` will be assigned at runtime when you actually know its value.
@ -850,6 +853,7 @@ Prefixing the declaration with `export` merely produces a new error, "[`Only ini
<hr>
{@a only-initialized-variables}
<h3 class="no-toc">Only initialized variables and constants</h3>
<div class="alert is-helpful">
@ -946,6 +950,7 @@ export abstract class MyStrategy { }
]
...
```
<hr>
<h3 class="no-toc">Reference to a non-exported function</h3>
@ -979,9 +984,11 @@ export function myStrategy() { ... }
]
...
```
<hr>
{@a function-calls-not-supported}
<h3 class="no-toc">Function calls are not supported</h3>
<div class="alert is-helpful">
@ -1017,6 +1024,7 @@ import { calculateValue } from './utilities';
To correct this error, export a function from the module and refer to the function in a `useFactory` provider instead.
<code-example linenums="false">
// CORRECTED
import { calculateValue } from './utilities';
@ -1032,11 +1040,13 @@ export function someValueFactory() {
{ provide: SomeValue, useFactory: someValueFactory }
]
...
</code-example>
<hr>
{@a destructured-variable-not-supported}
<h3 class="no-toc">Destructured variable or constant not supported</h3>
<div class="alert is-helpful">
@ -1050,6 +1060,7 @@ The compiler does not support references to variables assigned by [destructuring
For example, you cannot write something like this:
<code-example linenums="false">
// ERROR
import { configuration } from './configuration';
@ -1061,11 +1072,13 @@ const {foo, bar} = configuration;
{provide: Bar, useValue: bar},
]
...
</code-example>
To correct this error, refer to non-destructured values.
<code-example linenums="false">
// CORRECTED
import { configuration } from './configuration';
...
@ -1074,6 +1087,7 @@ import { configuration } from './configuration';
{provide: Bar, useValue: configuration.bar},
]
...
</code-example>
<hr>
@ -1106,13 +1120,17 @@ If you must inject an instance of an ambiant type,
you can finesse the problem in four steps:
1. Create an injection token for an instance of the ambiant type.
1. Create a factory function that returns that instance.
1. Add a `useFactory` provider with that factory function.
1. Use `@Inject` to inject the instance.
Here's an illustrative example.
<code-example linenums="false">
// CORRECTED
import { Inject } from '@angular/core';
@ -1128,6 +1146,7 @@ export function _window() { return window; }
export class MyComponent {
constructor (@Inject(WINDOW) private win: Window) { ... }
}
</code-example>
The `Window` type in the constructor is no longer a problem for the compiler because it
@ -1136,6 +1155,7 @@ uses the `@Inject(WINDOW)` to generate the injection code.
Angular does something similar with the `DOCUMENT` token so you can inject the browser's `document` object (or an abstraction of it, depending upon the platform in which the application runs).
<code-example linenums="false">
import { Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';
@ -1143,7 +1163,9 @@ import { DOCUMENT } from '@angular/platform-browser';
export class MyComponent {
constructor (@Inject(DOCUMENT) private doc: Document) { ... }
}
</code-example>
<hr>
<h3 class="no-toc">Name expected</h3>
@ -1173,6 +1195,7 @@ that you referenced in metadata.
The compiler can understand simple enum values but not complex values such as those derived from computed properties.
<code-example linenums="false">
// ERROR
enum Colors {
Red = 1,
@ -1187,6 +1210,7 @@ enum Colors {
{ provide: StrongColor, useValue: Colors.Blue } // bad
]
...
</code-example>
Avoid referring to enums with complicated initializers or computed properties.
@ -1194,6 +1218,7 @@ Avoid referring to enums with complicated initializers or computed properties.
<hr>
{@a tagged-template-expressions-not-supported}
<h3 class="no-toc">Tagged template expressions are not supported</h3>
<div class="alert is-helpful">
@ -1308,7 +1333,6 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
guard to the use of its template, implying that the template will only be instantiated if
the `ngIf` input property is true.
### Non-null type assertion operator
Use the [non-null type assertion operator](guide/template-syntax#non-null-assertion-operator)
@ -1378,12 +1402,21 @@ Chuck: After reviewing your PR comment I'm still at a loss. See [comment there](
person?: Person;
}
```
## Summary
## 小结
* What the AOT compiler does and why it is important.
* Why metadata must be written in a subset of JavaScript.
* What that subset is.
* Other restrictions on metadata definition.
* Macro-functions and macro-static methods.
* Compiler errors related to metadata.
* Validation of binding expressions

View File

@ -1,175 +1,349 @@
<div class="breadcrumb">
<a href="#">API<a> / <a href="#">@core<a>
</div>
<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>
<div class="page-actions">
<a href="#"><label class="raised page-label"><i class="material-icons">mode_edit</i>suggest edits</label></a>
<a href="#"><label class="raised page-label"><i class="material-icons">code</i>view source</label></a>
</div>
<p>Class description goes here. This is a short and to the point one or two sentence description that easily introduces the reader to the class.</p>
<div class="api-body">
<section>
<h2>Overview</h2>
<code-example language="ts" hidecopy="true" ng-version="5.2.0"><aio-code class="simple-code" ng-reflect-ng-class="[object Object]" ng-reflect-code="
class <a href=&quot;api/core/Compi" ng-reflect-hide-copy="true" ng-reflect-language="ts" ng-reflect-linenums="" ng-reflect-path="" ng-reflect-region="" ng-reflect-title=""><pre class="prettyprint lang-ts">
<code class="animated fadeIn"><span class="kwd">class</span><span class="pln"> </span><a href="api/core/Compiler" class="code-anchor"><span class="typ">Compiler</span></a><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleSync"><span class="pln">compileModuleSync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">NgModuleFactory</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAsync"><span class="pln">compileModuleAsync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun">&lt;</span><span class="typ">NgModuleFactory</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsSync"><span class="pln">compileModuleAndAllComponentsSync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">ModuleWithComponentFactories</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#compileModuleAndAllComponentsAsync"><span class="pln">compileModuleAndAllComponentsAsync</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;(</span><span class="pln">moduleType</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">Promise</span><span class="pun">&lt;</span><span class="typ">ModuleWithComponentFactories</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;&gt;</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#clearCache"><span class="pln">clearCache</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">void</span></a><span class="pln">
</span><a class="code-anchor" href="api/core/Compiler#clearCacheFor"><span class="pln">clearCacheFor</span><span class="pun">(</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">&lt;</span><span class="pln">any</span><span class="pun">&gt;)</span></a><span class="pln">
</span><span class="pun">}</span></code>
</pre></aio-code></code-example>
</section>
<section>
<h2>Description</h2>
<p>The longer class description goes here which can include multiple paragraphs.</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>
<h3>Subclasses</h3>
<ul>
<li><a href="#">Subclass1</a></li>
<li><a href="#">Subclass2</a></li>
<li><a href="#">Subclass3</a></li>
</ul>
<h3>See Also</h3>
<ul>
<li><a href="#">Link1</a></li>
<li><a href="#">Link2</a></li>
</ul>
</section>
<section>
<h2>Constructor</h2>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<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">
</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"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
</pre></aio-code></code-example>
</section>
<section>
<h2>Properties</h2>
<table class="is-full-width list-table">
<thead>
<tr>
<th>Property</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code><strong>Property1</strong></code>
</td>
<td><label class="property-type-label type">Type</label></td>
<td>Description goes here</td>
</tr>
<tr>
<td>
<code><strong>Property2</strong></code>
</td>
<td>Type</td>
<td>Description goes here</td>
</tr>
<tr>
<td>
<code><strong>Property3</strong></code>
</td>
<td>Type</td>
<td>Description goes here</td>
</tr>
</tbody>
</table>
</section>
<section class="api-method">
<h2>Methods</h2>
<table class="is-full-width item-table">
<thead>
<tr>
<th>Method1Name( )</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>Description goes here</p>
<br>
<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>
</tr>
</tbody>
</table>
<table class="is-full-width api-method item-table">
<thead>
<tr>
<th>Method2Name( )</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>Description goes here</p>
<hr>
<h5>Declaration</h5>
<code-example language="ts" hidecopy="true" ng-version="5.2.0">
<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>
</aio-code>
</code-example>
<h6>Parameters</h6>
<h6>Returns</h6>
<p>Returns information and results goes here.</p>
<h6>Errors</h6>
<p>Error information goes here</p>
<hr>
<p>Further details provided as needed. 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.</p><hr>
<h6>Overloads</h6>
<table class="is-full-width">
<tbody>
<tr>
<td>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<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">
</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"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
</pre></aio-code></code-example>
</td>
<td>Description goes here</td>
</tr>
<tr>
<td>
<code-example hidecopy="true" class="no-box api-heading" ng-version="5.2.0">
<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">
</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"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
</pre></aio-code></code-example>
</td>
<td>Description goes here</td>
</tr>
</tbody>
</table>
<hr>
<h5>Example: Descriptive Title of Method Example</h5>
<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>
</tr>
</tbody>
</table>
</section>
<section>
<h2>Example: Descriptive Title of Combined Example Goes Here</h2>
<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">
<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">
</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"> duration</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> delay</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> easing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">,</span><span class="pln"> previousPlayers</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">[])</span></code>
</pre></aio-code></code-example>
<p>Further explanation provided as needed. 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.</p>
</section>
</div>

View File

@ -11,7 +11,6 @@ The framework consists of several libraries, some of them core and some optional
该框架包括一系列库,有些是核心库,有些是可选库。
You write Angular applications by composing HTML *templates* with Angularized markup,
writing *component* classes to manage those templates, adding application logic in *services*,
and boxing components and services in *modules*.
@ -32,20 +31,17 @@ You'll learn the details in the pages that follow. For now, focus on the big pic
当然,这只是冰山一角。后面我们将学习更多的细节。不过,目前我们还是先关注全景图吧。
<figure>
<img src="generated/images/guide/architecture/overview2.png" alt="overview">
</figure>
<div class="l-sub-section">
The code referenced on this page is available as a <live-example></live-example>.
<p>
本章所引用的代码见<live-example></live-example>
</p>
</div>
@ -53,9 +49,7 @@ You'll learn the details in the pages that follow. For now, focus on the big pic
## 模块
<img src="generated/images/guide/architecture/module.png" alt="模块" class="left">
<img src="generated/images/guide/architecture/module.png" alt="Component" class="left">
Angular apps are modular and Angular has its own modularity system called _NgModules_.
@ -84,7 +78,6 @@ An NgModule, whether a _root_ or _feature_, is a class with an `@NgModule` decor
Angular 模块无论是_根模块_还是_特性模块_都是一个带有`@NgModule`装饰器的类。
<div class="l-sub-section">
Decorators are functions that modify JavaScript classes.
@ -97,7 +90,6 @@ Angular 模块无论是_根模块_还是_特性模块_都是一个带有`@
Angular 有很多装饰器,它们负责把元数据附加到类上,以了解那些类的设计意图以及它们应如何工作。
关于装饰器的<a href="https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841#.x5c2ndtx0" target="_blank">更多信息</a>
</div>
`NgModule` is a decorator function that takes a single metadata object whose properties describe the module.
@ -132,7 +124,6 @@ Here's a simple root module:
下面是一个简单的根模块:
<code-example path="architecture/src/app/mini-app.ts" region="module" title="src/app/app.module.ts" linenums="false"></code-example>
<div class="l-sub-section">
@ -141,7 +132,6 @@ Here's a simple root module:
`AppComponent``export`语句只是用于演示如何导出的它在这个例子中并不是必须的。根模块不需要_导出_任何东西因为其它组件不需要导入根模块。
</div>
Launch an application by _bootstrapping_ its root module.
@ -150,7 +140,6 @@ During development you're likely to bootstrap the `AppModule` in a `main.ts` fil
我们通过_引导_根模块来启动应用。
在开发期间,你通常在一个`main.ts`文件中引导`AppModule`,就像这样:
<code-example path="architecture/src/main.ts" title="src/main.ts" linenums="false"></code-example>
### NgModules vs. JavaScript modules
@ -181,18 +170,16 @@ JavaScript 中每个_文件_是一个模块文件中定义的所有对象
<div class="l-sub-section">
<a href="http://exploringjs.com/es6/ch_modules.html">Learn more about the JavaScript module system on the web.</a>
<a href="http://exploringjs.com/es6/ch_modules.html" target="_blank">学习更多关于 JavaScript 模块的知识。</a>
<a href="http://exploringjs.com/es6/ch_modules.html">学习更多关于 JavaScript 模块的知识。</a>
</div>
These are two different and _complementary_ module systems. Use them both to write your apps.
这两个模块化系统是互补的,我们在写程序时都会用到。
### Angular libraries
### Angular 模块库
@ -209,13 +196,14 @@ Each Angular library name begins with the `@angular` prefix.
You install them with the **npm** package manager and import parts of them with JavaScript `import` statements.
**npm** 包管理工具安装它们,用 JavaScript 的`import`语句导入其中某些部件。<br class="clear">
**npm** 包管理工具安装它们,用 JavaScript 的`import`语句导入其中某些部件。
<br class="clear">
For example, import Angular's `Component` decorator from the `@angular/core` library like this:
例如,象下面这样,从`@angular/core`库中导入`Component`装饰器:
<code-example path="architecture/src/app/app.component.ts" region="import" linenums="false"></code-example>
You also import NgModules from Angular _libraries_ using JavaScript import statements:
@ -228,7 +216,6 @@ In the example of the simple root module above, the application module needs mat
在上面那个简单的根模块的例子中,应用模块需要`BrowserModule`的某些素材。要访问这些素材,就得把它加入`@NgModule`元数据的`imports`中,就像这样:
<code-example path="architecture/src/app/mini-app.ts" region="ngmodule-imports" linenums="false"></code-example>
In this way you're using both the Angular and JavaScript module systems _together_.
@ -240,11 +227,8 @@ Hang in there. The confusion yields to clarity with time and experience.
这两个系统比较容易混淆,因为它们共享相同的词汇 “imports” 和 “exports”。不过没关系先放一放随着时间和经验的增长自然就清楚了。
<div class="l-sub-section">
Learn more from the [NgModules](guide/ngmodules) page.
更多信息,见 [Angular 模块](guide/ngmodule)。
@ -294,10 +278,7 @@ that it acquires from a service.
例如,`HeroListComponent`有一个`heroes`属性,它返回一个英雄数组,这个数组从一个服务获得。
`HeroListComponent`还有一个当用户从列表中点选一个英雄时设置`selectedHero`属性的`selectHero()`方法。
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class">
</code-example>
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (class)" region="class"></code-example>
Angular creates, updates, and destroys components as the user moves through the application.
Your app can take action at each moment in this lifecycle through optional [lifecycle hooks](guide/lifecycle-hooks), like `ngOnInit()` declared above.
@ -305,15 +286,13 @@ Your app can take action at each moment in this lifecycle through optional [life
当用户在这个应用中漫游时, Angular 会创建、更新和销毁组件。
应用可以通过[生命周期钩子](guide/lifecycle-hooks)在组件生命周期的各个时间点上插入自己的操作,例如上面声明的`ngOnInit()`
<hr/>
## Templates
## 模板
<img src="generated/images/guide/architecture/template.png" alt="模板" class="left">
<img src="generated/images/guide/architecture/template.png" alt="Template" class="left">
You define a component's view with its companion **template**. A template is a form of HTML
that tells Angular how to render the component.
@ -323,13 +302,9 @@ that tells Angular how to render the component.
A template looks like regular HTML, except for a few differences. Here is a
template for our `HeroListComponent`:
多数情况下,模板看起来很像标准 HTML当然也有一点不同的地方。下面是`HeroListComponent`组件的一个模板:
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html">
</code-example>
<code-example path="architecture/src/app/hero-list.component.html" title="src/app/hero-list.component.html"></code-example>
Although this template uses typical HTML elements like `<h2>` and `<p>`, it also has some differences. Code like `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, and `<app-hero-detail>` uses Angular's [template syntax](guide/template-syntax).
@ -362,12 +337,12 @@ Notice how `<app-hero-detail>` rests comfortably among native HTML elements. Cus
## 元数据
<img src="generated/images/guide/architecture/metadata.png" alt="元数据" class="left">
<img src="generated/images/guide/architecture/metadata.png" alt="Metadata" class="left">
Metadata tells Angular how to process a class.
<p style="padding-top:10px">元数据告诉 Angular 如何处理一个类。</p>
元数据告诉 Angular 如何处理一个类。
<br class="clear">
[Looking back at the code](guide/architecture#component-code) for `HeroListComponent`, you can see that it's just a class.
@ -387,21 +362,16 @@ To tell Angular that `HeroListComponent` is a component, attach **metadata** to
In TypeScript, you attach metadata by using a **decorator**.
Here's some metadata for `HeroListComponent`:
在TypeScript中我们用**装饰器 (decorator) **来附加元数据。
下面就是`HeroListComponent`的一些元数据。
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata">
</code-example>
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (metadata)" region="metadata"></code-example>
Here is the `@Component` decorator, which identifies the class
immediately below it as a component class.
这里看到`@Component`装饰器,它把紧随其后的类标记成了组件类。
The `@Component` decorator takes a required configuration object with the
information Angular needs to create and present the component and its view.
@ -411,7 +381,6 @@ Here are a few of the most useful `@Component` configuration options:
`@Component`的配置项包括:
* `selector`: CSS selector that tells Angular to create and insert an instance of this component
where it finds a `<app-hero-list>` tag in *parent* HTML.
For example, if an app's HTML contains `<app-hero-list></app-hero-list>`, then
@ -424,7 +393,6 @@ Angular inserts an instance of the `HeroListComponent` view between those tags.
`templateUrl`:组件 HTML 模板的模块相对地址,[如前所示](guide/architecture#templates)。
* `providers`: array of **dependency injection providers** for services that the component requires.
This is one way to tell Angular that the component's constructor requires a `HeroService`
so it can get the list of heroes to display.
@ -455,12 +423,11 @@ so that Angular knows what to do.
这种架构处理方式是:你向代码中添加元数据,以便 Angular 知道该怎么做。
<hr/>
## Data binding
## 数据绑定
## 数据绑定 (data binding)
Without a framework, you would be responsible for pushing data values into the HTML controls and turning user responses
into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to
@ -469,8 +436,7 @@ read as any experienced jQuery programmer can attest.
如果没有框架,我们就得自己把数据值推送到 HTML 控件中,并把用户的反馈转换成动作和值更新。
如果手工写代码来实现这些推/拉逻辑,肯定会枯燥乏味、容易出错,读起来简直是噩梦 —— 写过 jQuery 的程序员大概都对此深有体会。
<img src="generated/images/guide/architecture/databinding.png" alt="数据绑定" class="left">
<img src="generated/images/guide/architecture/databinding.png" alt="Data Binding" class="left">
Angular supports **data binding**,
a mechanism for coordinating parts of a template with parts of a component.
@ -487,13 +453,9 @@ As the diagram shows, there are four forms of data binding syntax. Each form has
The `HeroListComponent` [example](guide/architecture#templates) template has three forms:
`HeroListComponent`[示例](guide/architecture#templates)模板中有三种形式:
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (binding)" region="binding">
</code-example>
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (binding)" region="binding"></code-example>
* The `{{hero.name}}` [*interpolation*](guide/displaying-data#interpolation)
displays the component's `hero.name` property value within the `<li>` element.
@ -513,14 +475,10 @@ the parent `HeroListComponent` to the `hero` property of the child `HeroDetailCo
that combines property and event binding in a single notation, using the `ngModel` directive.
Here's an example from the `HeroDetailComponent` template:
**双向数据绑定**是重要的第四种绑定形式,它使用`ngModel`指令组合了属性绑定和事件绑定的功能。
下面是`HeroDetailComponent`模板的范例:
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel">
</code-example>
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
In two-way binding, a data property value flows to the input box from the component as with property binding.
The user's changes also flow back to the component, resetting the property to the latest value,
@ -533,18 +491,20 @@ from the root of the application component tree through all child components.
Angular 在每个 JavaScript 事件循环中处理*所有的*数据绑定,它会从组件树的根部开始,递归处理全部子组件。
<figure>
<img src="generated/images/guide/architecture/component-databinding.png" alt="数据绑定">
<img src="generated/images/guide/architecture/component-databinding.png" alt="Data Binding">
</figure>
Data binding plays an important role in communication between a template and its component.
数据绑定在模板与对应组件的交互中扮演了重要的角色。
<br class="l-clear-both">
<figure>
<img src="generated/images/guide/architecture/parent-child-binding.png" alt="父/子绑定">
<img src="generated/images/guide/architecture/parent-child-binding.png" alt="Parent/Child binding">
</figure>
Data binding is also important for communication between parent and child components.
@ -555,10 +515,9 @@ Data binding is also important for communication between parent and child compon
## Directives
## 指令 (directive)
## 指令
<img src="generated/images/guide/architecture/directive.png" alt="父与子" class="left">
<img src="generated/images/guide/architecture/directive.png" alt="Parent child" class="left">
Angular templates are *dynamic*. When Angular renders them, it transforms the DOM
according to the instructions given by **directives**.
@ -571,7 +530,6 @@ a `@Component` decorator is actually a `@Directive` decorator extended with temp
组件是一个*带模板的指令*`@Component`装饰器实际上就是一个`@Directive`装饰器,只是扩展了一些面向模板的特性。
<div class="l-sub-section">
While **a component is technically a directive**,
@ -579,7 +537,6 @@ a `@Component` decorator is actually a `@Directive` decorator extended with temp
虽然**严格来说组件就是一个指令**,但是组件非常独特,并在 Angular 中位于中心地位,所以在架构概览中,我们把组件从指令中独立了出来。
</div>
Two *other* kinds of directives exist: _structural_ and _attribute_ directives.
@ -598,13 +555,9 @@ sometimes by name but more often as the target of an assignment or a binding.
The [example template](guide/architecture#templates) uses two built-in structural directives:
下面的[范例模板](guide/architecture#templates)中用到了两个内置的结构型指令:
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (structural)" region="structural">
</code-example>
<code-example path="architecture/src/app/hero-list.component.1.html" linenums="false" title="src/app/hero-list.component.html (structural)" region="structural"></code-example>
* [`*ngFor`](guide/displaying-data#ngFor) tells Angular to stamp out one `<li>` per hero in the `heroes` list.
@ -614,7 +567,6 @@ The [example template](guide/architecture#templates) uses two built-in structura
[`*ngIf`](guide/displaying-data#ngIf)表示只有在选择的英雄存在时,才会包含`HeroDetail`组件。
**Attribute** directives alter the appearance or behavior of an existing element.
In templates they look like regular HTML attributes, hence the name.
@ -626,14 +578,10 @@ an example of an attribute directive. `ngModel` modifies the behavior of
an existing element (typically an `<input>`)
by setting its display value property and responding to change events.
`ngModel`指令就是属性型指令的一个例子,它实现了双向数据绑定。
`ngModel`修改现有元素(一般是`<input>`)的行为:设置其显示属性值,并响应 change 事件。
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel">
</code-example>
<code-example path="architecture/src/app/hero-detail.component.html" linenums="false" title="src/app/hero-detail.component.html (ngModel)" region="ngModel"></code-example>
Angular has a few more directives that either alter the layout structure
(for example, [ngSwitch](guide/template-syntax#ngSwitch))
@ -648,6 +596,7 @@ Of course, you can also write your own directives. Components such as
当然,我们也能编写自己的指令。像`HeroListComponent`这样的组件就是一种自定义指令。
<!-- PENDING: link to where to learn more about other kinds! -->
<hr/>
@ -705,25 +654,17 @@ Yet services are fundamental to any Angular application. Components are big cons
Here's an example of a service class that logs to the browser console:
下面是一个服务类的范例,用于把日志记录到浏览器的控制台:
<code-example path="architecture/src/app/logger.service.ts" linenums="false" title="src/app/logger.service.ts (class)" region="class">
</code-example>
<code-example path="architecture/src/app/logger.service.ts" linenums="false" title="src/app/logger.service.ts (class)" region="class"></code-example>
Here's a `HeroService` that uses a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to fetch heroes.
The `HeroService` depends on the `Logger` service and another `BackendService` that handles the server communication grunt work.
下面是`HeroService`类,用于获取英雄数据,并通过一个已解析的[承诺 (Promise)](http://exploringjs.com/es6/ch_promises.html) 返回它们。
`HeroService`还依赖于`Logger`服务和另一个用于处理服务器通讯的`BackendService`服务。
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class">
</code-example>
<code-example path="architecture/src/app/hero.service.ts" linenums="false" title="src/app/hero.service.ts (class)" region="class"></code-example>
Services are everywhere.
@ -755,12 +696,11 @@ application logic into services and make those services available to components
Angular 帮助我们*遵循*这些原则 —— 它让我们能轻易地把应用逻辑拆分到服务,并通过*依赖注入*来在组件中使用这些服务。
<hr/>
## Dependency injection
## 依赖注入
## 依赖注入dependency injection
<img src="generated/images/guide/architecture/dependency-injection.png" alt="Service" class="left">
@ -769,7 +709,9 @@ with the fully-formed dependencies it requires. Most dependencies are services.
Angular uses dependency injection to provide new components with the services they need.
“依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。
Angular 使用依赖注入来提供新组件以及组件所需的服务。<br class="clear">
Angular 使用依赖注入来提供新组件以及组件所需的服务。
<br class="clear">
Angular can tell which services a component needs by looking at the types of its constructor parameters.
For example, the constructor of your `HeroListComponent` needs a `HeroService`:
@ -777,7 +719,6 @@ For example, the constructor of your `HeroListComponent` needs a `HeroService`:
Angular 通过查看构造函数的参数类型得知组件需要哪些服务。
例如,`HeroListComponent`组件的构造函数需要一个`HeroService`服务:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (constructor)" region="ctor"></code-example>
When Angular creates a component, it first asks an **injector** for
@ -801,9 +742,10 @@ The process of `HeroService` injection looks a bit like this:
`HeroService`注入的过程差不多是这样的:
<figure>
<img src="generated/images/guide/architecture/injector-injects.png" alt="服务">
<img src="generated/images/guide/architecture/injector-injects.png" alt="Service">
</figure>
If the injector doesn't have a `HeroService`, how does it know how to make one?
@ -816,8 +758,6 @@ A provider is something that can create or return a service, typically the servi
简单点说我们必须先用注入器injector`HeroService`注册一个**提供商provider**。
提供商用来创建或返回服务,通常就是这个服务类本身(相当于`new HeroService()`)。
You can register providers in modules or in components.
我们可以在模块中或组件中注册提供商。
@ -825,23 +765,15 @@ You can register providers in modules or in components.
In general, add providers to the [root module](guide/architecture#modules) so that
the same instance of a service is available everywhere.
但通常会把提供商添加到[根模块](guide/architecture#modules)上,以便在任何地方都使用服务的同一个实例。
<code-example path="architecture/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (module providers)" region="providers">
</code-example>
<code-example path="architecture/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (module providers)" region="providers"></code-example>
Alternatively, register at a component level in the `providers` property of the `@Component` metadata:
或者,也可以在`@Component`元数据中的`providers`属性中把它注册在组件层:
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers">
</code-example>
<code-example path="architecture/src/app/hero-list.component.ts" linenums="false" title="src/app/hero-list.component.ts (component providers)" region="providers"></code-example>
Registering at a component level means you get a new instance of the
service with each new instance of that component.
@ -882,7 +814,6 @@ Points to remember about dependency injection:
把*提供商*注册到注入器。
<hr/>
## Wrap up
@ -968,13 +899,15 @@ by implementing the lifecycle hook interfaces.
> [**生命周期钩子**](guide/lifecycle-hooks):通过实现生命周期钩子接口,可以切入组件生命中的几个关键点:从创建到销毁。
> [**Pipes**](guide/pipes): Use pipes in your templates to improve the user experience by transforming values for display. Consider this `currency` pipe expression:
> [**管道**](guide/pipes):在模板中使用管道转换成用于显示的值,以增强用户体验。例如,`currency`管道表达式:
>
> > `price | currency:'USD':true`
>
> It displays a price of 42.33 as `$42.33`.
> [**管道**](guide/pipes):在模板中使用管道转换成用于显示的值,以增强用户体验。例如,`currency`管道表达式:
>
> > `price | currency:'USD':true`
>
> 它把价格“42.33”显示为`$42.33`
> [**Router**](guide/router): Navigate from page to page within the client

View File

@ -52,8 +52,6 @@ can change several element styles at the same time.
*属性型*指令改变一个元素的外观或行为。例如,内置的 [NgStyle](guide/template-syntax#ngStyle) 指令可以同时修改元素的多个样式。
## Build a simple attribute directive
## 创建一个简单的属性型指令
@ -85,7 +83,9 @@ Create the directive class file in a terminal window with this CLI command.
在命令行窗口下用 CLI 命令创建指令类文件。
<code-example language="sh" class="code-shell">
ng generate directive highlight
</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`.
@ -147,7 +147,6 @@ that prefix is reserved for Angular and using it could cause bugs that are diffi
确认你**没有**给`highlight`指令添加**`ng`**前缀。
那个前缀属于 Angular使用它可能导致难以诊断的 bug。例如这个简短的前缀`my`可以帮助你区分自定义指令。
</div>
After the `@Directive` metadata comes the directive's controller class,
@ -192,7 +191,9 @@ Now run the application to see the `HighlightDirective` in action.
运行这个应用以查看`HighlightDirective`的实际效果。
<code-example language="sh" class="code-shell">
ng serve
</code-example>
To summarize, Angular found the `appHighlight` attribute on the **host** `<p>` element.
@ -204,7 +205,6 @@ which sets the `<p>` element's background style to yellow.
然后它创建了一个`HighlightDirective`类的实例,并把所在元素的引用注入到了指令的构造函数中。
在构造函数中,我们把`<p>`元素的背景设置为了黄色。
{@a respond-to-user}
## Respond to user-initiated events
@ -221,30 +221,22 @@ and respond by setting or clearing the highlight color.
Begin by adding `HostListener` to the list of imported symbols.
先把`HostListener`加进导入列表中,同时再添加`Input`符号,因为我们很快就要用到它。
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (imports)" region="imports"></code-example>
Then add two eventhandlers that respond when the mouse enters or leaves,
each adorned by the `HostListener` decorator.
然后使用`HostListener`装饰器添加两个事件处理器,它们会在鼠标进入或离开时进行响应。
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-methods)" region="mouse-methods"></code-example>
The `@HostListener` decorator lets you subscribe to events of the DOM
element that hosts an attribute directive, the `<p>` in this case.
`@HostListener`装饰器引用属性型指令的宿主元素,在这个例子中就是`<p>`
<div class="l-sub-section">
Of course you could reach into the DOM with standard JavaScript and attach event listeners manually.
@ -265,7 +257,6 @@ There are at least three problems with _that_ approach:
必须直接和 DOM API 打交道,应该避免这样做。
</div>
The handlers delegate to a helper method that sets the color on the host DOM element, `el`.
@ -273,32 +264,25 @@ The handlers delegate to a helper method that sets the color on the host DOM ele
The helper method, `highlight`, was extracted from the constructor.
The revised constructor simply declares the injected `el: ElementRef`.
这些处理器委托给了一个辅助方法它用于为DOM元素设置颜色`el`就是你在构造器中声明和初始化过的。
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (constructor)" region="ctor">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (constructor)" region="ctor"></code-example>
Here's the updated directive in full:
下面是修改后的指令代码:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" title="src/app/highlight.directive.ts">
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" title="src/app/highlight.directive.ts"></code-example>
</code-example>
Run the app and confirm that the background color appears when the mouse hovers over the `p` and
disappears as it moves out.We run the app and confirm that the background color appears as we move the mouse over the `p` and
disappears as we move out.
Run the app and confirm that the background color appears when
the mouse hovers over the `p` and disappears as it moves out.
运行本应用并确认:当把鼠标移到`p`上的时候,背景色就出现了,而移开的时候,它消失了。
<figure>
<img src="generated/images/guide/attribute-directives/highlight-directive-anim.gif" alt="Second Highlight">
</figure>
{@a bindings}
@ -323,10 +307,7 @@ Add a `highlightColor` property to the directive class like this:
然后把`highlightColor`属性添加到指令类中,就像这样:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (highlightColor)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (highlightColor)" region="color"></code-example>
{@a input}
@ -346,43 +327,27 @@ Without that input metadata, Angular rejects the binding; see [below](guide/attr
Try it by adding the following directive binding variations to the `AppComponent` template:
试试把下列指令绑定变量添加到`AppComponent`的模板中:
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-1">
</code-example>
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-1"></code-example>
Add a `color` property to the `AppComponent`.
`color`属性添加到`AppComponent`中:
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (class)" region="class">
</code-example>
<code-example path="attribute-directives/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example>
Let it control the highlight color with a property binding.
让它通过属性绑定来控制高亮颜色。
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-2">
</code-example>
<code-example path="attribute-directives/src/app/app.component.1.html" linenums="false" title="src/app/app.component.html (excerpt)" region="color-2"></code-example>
That's good, but it would be nice to _simultaneously_ apply the directive and set the color _in the same attribute_ like this.
很不错,但还可以更好。我们可以在应用该指令时在同一个属性中设置颜色,就像这样:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example>
The `[appHighlight]` attribute binding both applies the highlighting directive to the `<p>` element
and sets the directive's highlight color with a property binding.
@ -395,19 +360,14 @@ That's a crisp, compact syntax.
You'll have to rename the directive's `highlightColor` property to `appHighlight` because that's now the color property binding name.
我们还要把该指令的`highlightColor`改名为`myHighlight`,因为它是颜色属性目前的绑定名。
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (renamed to match directive selector)" region="color-2"></code-example>
This is disagreeable. The word, `appHighlight`, is a terrible property name and it doesn't convey the property's intent.
这可不好。因为`myHighlight`是一个糟糕的属性名,而且不能反映该属性的意图。
{@a input-alias}
### Bind to an _@Input_ alias
@ -420,13 +380,9 @@ Fortunately you can name the directive property whatever you want _and_ **_alias
Restore the original property name and specify the selector as the alias in the argument to `@Input`.
恢复原始属性名,并在`@Input`的参数中把选择器`myHighlight`指定为别名。
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color property with alias)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color property with alias)" region="color"></code-example>
_Inside_ the directive the property is known as `highlightColor`.
_Outside_ the directive, where you bind to it, it's known as `appHighlight`.
@ -435,41 +391,28 @@ _Outside_ the directive, where you bind to it, it's known as `appHighlight`.
You get the best of both worlds: the property name you want and the binding syntax you want:
这是最好的结果:理想的内部属性名,理想的绑定语法:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example>
Now that you're binding via the alias to the `highlightColor`, modify the `onMouseEnter()` method to use that property.
If someone neglects to bind to `appHighlightColor`, highlight the host element in red:
现在,我们绑定到了`highlightColor`属性,并修改`onMouseEnter()`方法来使用它。
如果有人忘了绑定到`highlightColor`,那就用红色进行高亮。
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (mouse enter)" region="mouse-enter"></code-example>
Here's the latest version of the directive class.
这是最终版本的指令类。
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (excerpt)">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.3.ts" linenums="false" title="src/app/highlight.directive.ts (excerpt)"></code-example>
## Write a harness to try it
## 写个测试程序试验下
It may be difficult to imagine how this directive actually works.
In this section, you'll turn `AppComponent` into a harness that
lets you pick the highlight color with a radio button and bind your color choice to the directive.
@ -479,31 +422,24 @@ lets you pick the highlight color with a radio button and bind your color choice
Update <code>app.component.html</code> as follows:
`app.component.html`修改成这样:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (v2)" region="v2">
</code-example>
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (v2)" region="v2"></code-example>
Revise the `AppComponent.color` so that it has no initial value.
修改`AppComponent.color`,让它不再有初始值。
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (class)" region="class">
</code-example>
<code-example path="attribute-directives/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (class)" region="class"></code-example>
Here are the harness and directive in action.
下面是测试程序和指令的动图。
<figure>
<img src="generated/images/guide/attribute-directives/highlight-directive-v2-anim.gif" alt="Highlight v.2">
</figure>
{@a second-property}
@ -524,24 +460,16 @@ Let the template developer set the default color.
Add a second **input** property to `HighlightDirective` called `defaultColor`:
把第二个名叫`defaultColor`的**输入**属性添加到`HighlightDirective`中:
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (defaultColor)(excerpt)">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (defaultColor)" region="defaultColor"></code-example>
Revise the directive's `onMouseEnter` so that it first tries to highlight with the `highlightColor`,
then with the `defaultColor`, and falls back to "red" if both properties are undefined.
修改该指令的`onMouseEnter`,让它首先尝试使用`highlightColor`进行高亮,然后用`defaultColor`,如果它们都没有指定,那就用红色作为后备。
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (mouse-enter)" region="mouse-enter"></code-example>
How do you bind to a second property when you're already binding to the `appHighlight` attribute name?
@ -551,14 +479,10 @@ As with components, you can add as many directive property bindings as you need
The developer should be able to write the following template HTML to both bind to the `AppComponent.color`
and fall back to "violet" as the default color.
像组件一样,你也可以绑定到指令的很多属性,只要把它们依次写在模板中就行了。
开发者可以绑定到`AppComponent.color`,并且用紫罗兰色作为默认颜色,代码如下:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (defaultColor)" region="defaultColor">
</code-example>
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (defaultColor)" region="defaultColor"></code-example>
Angular knows that the `defaultColor` binding belongs to the `HighlightDirective`
because you made it _public_ with the `@Input` decorator.
@ -567,16 +491,17 @@ Angular之所以知道`defaultColor`绑定属于`HighlightDirective`,是因为
Here's how the harness should work when you're done coding.
当这些代码完成时,测试程序工作时的动图如下:
<figure>
<img src="generated/images/guide/attribute-directives/highlight-directive-final-anim.gif" alt="Final Highlight">
</figure>
## Summary
##
##
This page covered how to:
@ -598,22 +523,26 @@ This page covered how to:
[把值**绑定**到指令中](guide/attribute-directives#bindings)。
The final source code follows:
最终的源码如下:
<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.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/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="index.html" path="attribute-directives/src/index.html"></code-pane>
</code-tabs>
You can also experience and download the <live-example title="Attribute Directive example"></live-example>.
你还可以体验和下载<live-example title="属性型指令范例"></live-example>.
@ -627,23 +556,15 @@ You can also experience and download the <live-example title="Attribute Directiv
In this demo, the `highlightColor` property is an ***input*** property of
the `HighlightDirective`. You've seen it applied without an alias:
在这个例子中`hightlightColor``HighlightDirective`的一个***输入型***属性。我们见过它没有用别名时的代码:
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.2.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example>
You've seen it with an alias:
也见过用别名时的代码:
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/highlight.directive.ts" linenums="false" title="src/app/highlight.directive.ts (color)" region="color"></code-example>
Either way, the `@Input` decorator tells Angular that this property is
_public_ and available for binding by a parent component.
@ -697,13 +618,9 @@ You can tell if `@Input` is needed by the position of the property name in a bin
Now apply that reasoning to the following example:
试用此原理分析下列范例:
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color">
</code-example>
<code-example path="attribute-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (color)" region="color"></code-example>
* The `color` property in the expression on the right belongs to the template's component.
The template and its component trust each other.
@ -716,5 +633,6 @@ Now apply that reasoning to the following example:
not a property of the template's component. There are trust issues.
Therefore, the directive property must carry the `@Input` decorator.
`myHighlight`属性位于左侧,它引用了`MyHighlightDirective`中一个*带别名的*属性,它不是模板所属组件的一部分,因此存在信任问题。
所以,该属性必须带`@Input`装饰器。

View File

@ -3,6 +3,7 @@
#### Prerequisites
A basic understanding of the following:
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr />
@ -47,8 +48,11 @@ The `@NgModule` decorator identifies `AppModule` as an `NgModule` class.
`@NgModule` takes a metadata object that tells Angular how to compile and launch the application.
* **_declarations_**&mdash;this application's lone component.
* **_imports_**&mdash;import `BrowserModule` to have browser specific services such as DOM rendering, sanitization, and location.
* **_providers_**&mdash;the service providers.
* **_bootstrap_**&mdash;the _root_ component that Angular creates and inserts
into the `index.html` host web page.
@ -92,42 +96,41 @@ import the module that has the declarable you need in it.
**Only `@NgModule` references** go in the `imports` array.
### Using directives with `@NgModule`
Use the `declarations` array for directives.
To use a directive, component, or pipe in a module, you must do a few things:
1. Export it from the file where you wrote it.
2. Import it into the appropriate module.
3. Declare it in the `@NgModule` `declarations` array.
2. Import it into the appropriate module.
3. Declare it in the `@NgModule` `declarations` array.
Those three steps look like the following. In the file where you create your directive, export it.
The following example, named `ItemDirective` is the default directive structure that the CLI generates in its own file, `item.directive.ts`:
<code-example path="bootstrapping/src/app/item.directive.ts" region="directive" title="src/app/item.directive.ts" linenums="false">
</code-example>
The key point here is that you have to export it so you can import it elsewhere. Next, import it
into the NgModule, in this example `app.module.ts`, with a JavaScript import statement:
<code-example path="bootstrapping/src/app/app.module.ts" region="directive-import" title="src/app/app.module.ts" linenums="false">
</code-example>
And in the same file, add it to the `@NgModule` `declarations` array:
<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.
Remember, components, directives, and pipes belong to one module only. You only need to declare them once in your app because you share them by importing the necessary modules. This saves you time and helps keep your app lean.
{@a imports}
## The `imports` array
@ -172,8 +175,6 @@ most applications have only one component tree and bootstrap a single root compo
This one root component is usually called `AppComponent` and is in the
root module's `bootstrap` array.
## More about Angular Modules
For more on NgModules you're likely to see frequently in apps,

View File

@ -6,17 +6,24 @@ Angular supports most recent browsers. This includes the following specific vers
Angular 支持大多数常用浏览器,包括下列版本:
<table>
<tr>
<th>
Browser
浏览器
</th>
<th>
Supported versions
支持的版本
</th>
</tr>
@ -24,86 +31,141 @@ Angular 支持大多数常用浏览器,包括下列版本:
<tr>
<td>
Chrome
</td>
<td>
<p>
latest
</p>
<p>
最新版
</p>
</td>
</tr>
<tr>
<td>
Firefox
</td>
<td>
latest
最新版
</td>
</tr>
<tr>
<td>
Edge
</td>
<td>
2 most recent major versions
最近的两个主版本
</td>
</tr>
<tr>
<td>
IE
</td>
<td>
11<br>10<br>9
</td>
</tr>
<tr>
<tr>
<td>
IE Mobile
</td>
<td>
11
</td>
</tr>
<tr>
<td>
Safari
</td>
<td>
2 most recent major versions
最近的两个主版本
</td>
</tr>
<tr>
<td>
iOS
</td>
<td>
2 most recent major versions
最近的两个主版本
</td>
</tr>
<tr>
<td>
Android
</td>
<td>
Nougat (7.0)<br>Marshmallow (6.0)<br>Lollipop (5.0, 5.1)<br>KitKat (4.4)
</td>
</tr>
</table>
@ -117,10 +179,8 @@ using <a href="https://saucelabs.com/">SauceLabs</a> and
Angular 在持续集成过程中,对每一个提交都会使用 <a href="https://saucelabs.com/" target="_blank">SauceLabs</a>
<a href="https://www.browserstack.com" target="_blank">Browserstack</a> 在上述所有浏览器上执行单元测试。
</div>
## Polyfills
## 腻子脚本 (polyfill)
@ -173,9 +233,11 @@ For example, [if you need the web animations polyfill](http://caniuse.com/#feat=
比如,[如果你需要 web 动画的腻子脚本](http://caniuse.com/#feat=web-animation),就要通过下列命令之一来安装它:
<code-example language="sh" class="code-shell">
# note that the web-animations-js polyfill is only here as an example
# it isn't a strict requirement of Angular anymore (more below)
npm install --save web-animations-js
</code-example>
Then open the `polyfills.ts` file and un-comment the corresponding `import` statement as in the following example:
@ -183,11 +245,13 @@ Then open the `polyfills.ts` file and un-comment the corresponding `import` stat
然后打开 `polyfills.ts` 文件,并反注释对应的 `import` 语句,就像这样:
<code-example title="src/polyfills.ts">
/**
* Required to support Web Animations `@angular/platform-browser/animations`.
* 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`.
</code-example>
If you can't find the polyfill you want in `polyfills.ts`,
@ -213,7 +277,6 @@ Non-CLI users should follow the instructions [below](#non-cli).
{@a polyfill-libs}
### Mandatory polyfills
### 强制性腻子脚本
@ -222,31 +285,23 @@ These are the polyfills required to run an Angular application on each supported
下表中的腻子脚本是每个浏览器都要用到的:
<table>
<tr style="vertical-align: top">
<th>
<p>
Browsers (Desktop & Mobile)
</p>
<p>
浏览器(桌面和移动)
</p>
</th>
<th>
<p>
Polyfills Required
</p>
<p>
需要的腻子脚本
</p>
</th>
@ -255,7 +310,9 @@ These are the polyfills required to run an Angular application on each supported
<tr style="vertical-align: top">
<td>
Chrome, Firefox, Edge, Safari 9+
</td>
<td>
@ -269,7 +326,9 @@ These are the polyfills required to run an Angular application on each supported
<tr style="vertical-align: top">
<td>
Safari 7 & 8, IE10 & 11, Android 4.1+
</td>
<td>
@ -283,7 +342,9 @@ These are the polyfills required to run an Angular application on each supported
<tr style="vertical-align: top">
<td>
IE9
</td>
<td>
@ -296,7 +357,6 @@ These are the polyfills required to run an Angular application on each supported
</table>
### Optional browser features to polyfill
### 可选浏览器特性的腻子脚本
@ -314,12 +374,12 @@ Here are the features which may require additional polyfills:
下列特性可能需要更多腻子脚本:
<table>
<tr style="vertical-align: top">
<th>
Feature
特性
@ -327,6 +387,7 @@ Here are the features which may require additional polyfills:
</th>
<th>
Polyfill
腻子脚本
@ -334,6 +395,7 @@ Here are the features which may require additional polyfills:
</th>
<th style="width: 50%">
Browsers (Desktop & Mobile)
浏览器(桌面和移动)
@ -357,9 +419,11 @@ Here are the features which may require additional polyfills:
<td>
[ES7/reflect](guide/browser-support#core-es7-reflect)
</td>
<td>
All current browsers. Enabled by default.
Can remove if you always use AOT and only use Angular decorators.
@ -389,13 +453,16 @@ Here are the features which may require additional polyfills:
[Web Animations](guide/browser-support#web-animations)
[Web 动画](guide/browser-support#web-animations)
</td>
<td>
<p>If AnimationBuilder is used then the polyfill will enable scrubbing
support for IE/Edge and Safari (Chrome and Firefox support this natively).</p>
<p>如果使用了AnimationBuilder那么腻子脚本将为 IE/Edge 和 Safari 启用擦除scrubbing支持Chrome 和 Firefox 原生支持此特性)</p>
</td>
</tr>
@ -425,9 +492,10 @@ Here are the features which may require additional polyfills:
</td>
<td>
<p>All but Chrome, Firefox, Edge, IE11 and Safari 10</p>
<p>除了 Chrome、Firefox、Edge、IE11 和 Safari 10 外的所有浏览器</p>
All but Chrome, Firefox, Edge, IE11 and Safari 10
除了 Chrome、Firefox、Edge、IE11 和 Safari 10 外的所有浏览器
</td>
@ -437,11 +505,12 @@ Here are the features which may require additional polyfills:
<td>
<p>[NgClass](api/common/NgClass)
[NgClass](api/common/NgClass)
on SVG elements</p>
on SVG elements
在 SVG 元素上应用时
<p>在 SVG 元素上应用 [NgClass](api/common/NgClass)</p>
</td>
<td>
@ -451,7 +520,9 @@ Here are the features which may require additional polyfills:
</td>
<td>
IE10, IE11
</td>
</tr>
@ -460,34 +531,38 @@ Here are the features which may require additional polyfills:
<td>
<p>[Http](guide/http)
[Http](guide/http)
when sending and receiving binary data</p>
when sending and receiving binary data
<p>用 [Http](guide/http) 发送和接收二进制数据</p>
用 [Http](guide/http) 发送和接收二进制数据
</td>
<td>
[Typed&nbsp;Array](guide/browser-support#typedarray)<br>
[Typed&nbsp;Array](guide/browser-support#typedarray)
[Blob](guide/browser-support#blob)<br>
<br>
[Blob](guide/browser-support#blob)
<br>
[FormData](guide/browser-support#formdata)
</td>
<td>
IE 9
</td>
</tr>
</table>
### Suggested polyfills ##
### 建议的腻子脚本 ##
@ -496,44 +571,31 @@ Below are the polyfills which are used to test the framework itself. They are a
下表中是用来测试框架本身的腻子脚本,它们是应用程序的优质起点。
<table>
<tr>
<th>
<p>
Polyfill
</p>
<p>
腻子脚本
</p>
</th>
<th>
<p>
Licence
</p>
License
<p>
授权方式
</p>
</th>
<th>
<p>
Size*
</p>
<p>
大小*
</p>
</th>
@ -548,11 +610,15 @@ Below are the polyfills which are used to test the framework itself. They are a
</td>
<td>
MIT
</td>
<td>
0.5KB
</td>
</tr>
@ -566,11 +632,15 @@ Below are the polyfills which are used to test the framework itself. They are a
</td>
<td>
MIT
</td>
<td>
27.4KB
</td>
</tr>
@ -585,18 +655,16 @@ Below are the polyfills which are used to test the framework itself. They are a
<td>
<p>
Public domain
</p>
<p>
公共域
</p>
</td>
<td>
1KB
</td>
</tr>
@ -610,11 +678,15 @@ Below are the polyfills which are used to test the framework itself. They are a
</td>
<td>
MIT / Unicode license
</td>
<td>
13.5KB
</td>
</tr>
@ -622,15 +694,21 @@ Below are the polyfills which are used to test the framework itself. They are a
<tr>
<td>
<a id='web-animations' href="https://github.com/web-animations/web-animations-js">Web Animations</a>
</td>
<td>
Apache
</td>
<td>
14.8KB
</td>
</tr>
@ -644,11 +722,15 @@ Below are the polyfills which are used to test the framework itself. They are a
</td>
<td>
MIT
</td>
<td>
4KB
</td>
</tr>
@ -662,11 +744,15 @@ Below are the polyfills which are used to test the framework itself. They are a
</td>
<td>
MIT
</td>
<td>
1.3KB
</td>
</tr>
@ -680,22 +766,28 @@ Below are the polyfills which are used to test the framework itself. They are a
</td>
<td>
MIT
</td>
<td>
0.4KB
</td>
</tr>
</table>
\* Figures are for minified and gzipped code,
computed with the <a href="http://closure-compiler.appspot.com/home">closure compiler</a>.
\* 这里的数据都按最小化并且 gzip 压缩后的版本算,是由<a href="http://closure-compiler.appspot.com/home">closure compiler</a>计算出的。
{@a non-cli}
## Polyfills for non-CLI users
## 不使用 CLI 的用户的腻子脚本
@ -705,13 +797,17 @@ If you are not using the CLI, you should add your polyfill scripts directly to t
如果你不使用 CLI就要直接把腻子脚本添加到宿主页`index.html`)中,就像这样:
<code-example title="src/index.html">
&lt;!-- pre-zone polyfills -->
&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>
/**
* you can configure some zone flags which can disable zone interception for some
* asynchronous activities to improve startup performance - use these options only
* if you know what you are doing as it could result in hard to trace down bugs..
*/
// __Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
@ -719,7 +815,9 @@ If you are not using the CLI, you should add your polyfill scripts directly to t
// __zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
/*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*/
// __Zone_enable_cross_context_check = true;
@ -728,4 +826,6 @@ 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;!-- application polyfills -->
</code-example>

View File

@ -2,8 +2,6 @@
# 变更记录
The Angular documentation is a living document with continuous improvements.
This log calls attention to recent significant changes.
@ -131,7 +129,7 @@ It includes important advice on optimizing for production.
[Hierarchical Dependency Injection](guide/hierarchical-dependency-injection) guide is significantly revised.
Closes issue #3086.
Revised samples are clearer and cover all topics discussed
Revised samples are clearer and cover all topics discussed.
[多级依赖注入](guide/hierarchical-dependency-injection)做了显著修改。关闭了issue #3086。修改过的范例更加清晰,而且涵盖了讨论到的全部主题。
@ -140,11 +138,9 @@ Revised samples are clearer and cover all topics discussed
## 杂项 (2017-01-05)
* [Setup](guide/setup) guide:
[环境搭建](guide/setup)指南:
added (optional) instructions on how to remove _non-essential_ files.
[环境搭建](guide/setup)指南:
添加了(可选的)步骤说明,告诉你如何移除*非核心*文件。
* No longer consolidate RxJS operator imports in `rxjs-extensions` file; each file should import what it needs.
@ -253,12 +249,10 @@ The documentation for the version prior to v.2.2.0 has been removed.
## 在“从TypeScript到JavaScript”增加ES6的描述 (2016-11-14)
The updated TypeScript to JavaScript guide explains how to write apps in ES6/7
更新了“[从TypeScript到JavaScript](guide/ts-to-js)”烹饪宝典解释如何使用ES6/7编写应用
by translating the common idioms in the TypeScript documentation examples
(and elsewhere on the web) to ES6/7 and ES5.
更新了“[从TypeScript到JavaScript](guide/ts-to-js)”烹饪宝典解释如何使用ES6/7编写应用。
将TypeScript文档示例中以及网站其它地方的习惯用法翻译成ES6/7和ES5。
This was [removed in August 2017](https://github.com/angular/angular/pull/18694) but can still be
@ -364,10 +358,6 @@ The _Routing Module_ replaces the previous _routing object_ involving the `Modul
[Routing and Navigation](guide/router)现在在**路由模块**中设置路由配置。
**路由模块**替换之前的**路由对象**,使用了`ModuleWithProviders`
[Routing and Navigation](guide/router)
[路由与导航](guide/router)
All guided samples with routing use the _Routing Module_ and prose content has been updated,
most conspicuously in the
[NgModule](guide/ngmodules) guide and [NgModule FAQ](guide/ngmodule-faq) guide.
@ -406,13 +396,11 @@ The new "angular-in-memory-web-api" has new features.
## “风格指南”中添加了_NgModules_(2016-09-27)
[StyleGuide](guide/styleguide) explains recommended conventions for NgModules.
[StyleGuide](guide/styleguide)解释了我们为Angular模块NgModule而推荐的约定。
Barrels now are far less useful and have been removed from the style guide;
they remain valuable but are not a matter of Angular style.
Also relaxed the rule that discouraged use of the `@Component.host` property.
[StyleGuide](guide/styleguide)解释了我们为Angular模块NgModule而推荐的约定。
现在,封装桶不再那么重要,风格指南已经移除了它们。
它们仍然很有价值但是它们与Angular风格无关。
我们同时对**不推荐使用`@Component.host`属性**的规则有所放宽。
@ -440,4 +428,5 @@ modules with SystemJS as the samples currently do.
The [Lifecycle Hooks](guide/lifecycle-hooks) guide is shorter, simpler, and
draws more attention to the order in which Angular calls the hooks.
[生命周期钩子](guide/lifecycle-hooks)章现在更加简短并且对强调了Angular是以什么顺序来调用钩子方法的。

View File

@ -1,498 +1,764 @@
<h1 class="no-toc">Cheat Sheet</h1>
<h1 class="no-toc">速查表</h1>
<h1 class="no-toc">Cheat Sheet</h1>
<div id="cheatsheet">
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Bootstrapping</p>
<p>启动</p>
</th>
<th>Bootstrapping</th>
<th><p><code>import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';</code>
</p>
</th>
</tr>
<tr>
<td><code><b>platformBrowserDynamic().bootstrapModule</b>(AppModule);</code></td>
<td><p>Bootstraps the app, using the root component from the specified <code>NgModule</code>. </p>
<p><code>NgModule</code> 中指定的根组件进行启动。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th><p>NgModules</p>
<p>Angular 模块</p>
</th>
<th>NgModules</th>
<th><p><code>import { NgModule } from '@angular/core';</code>
</p>
</th>
</tr>
<tr>
<td><code>@<b>NgModule</b>({ declarations: ..., imports: ...,<br> exports: ..., providers: ..., bootstrap: ...})<br>class MyModule {}</code></td>
<td><p>Defines a module that contains components, directives, pipes, and providers.</p>
<p>定义一个模块,其中可以包含组件、指令、管道和服务提供商。</p>
</td>
</tr><tr>
<td><code><b>declarations:</b> [MyRedComponent, MyBlueComponent, MyDatePipe]</code></td>
<td><p>List of components, directives, and pipes that belong to this module.</p>
<p>属于当前模块的组件、指令和管道的列表。</p>
</td>
</tr><tr>
<td><code><b>imports:</b> [BrowserModule, SomeOtherModule]</code></td>
<td><p>List of modules to import into this module. Everything from the imported modules
is available to <code>declarations</code> of this module.</p>
<p>本模块所导入的模块列表</p>
is available to
<code>declarations</code> of this module.</p>
</td>
</tr><tr>
<td><code><b>exports:</b> [MyRedComponent, MyDatePipe]</code></td>
<td><p>List of components, directives, and pipes visible to modules that import this module.</p>
<p>那些导入了本模块的模块所能看到的组件、指令和管道的列表</p>
</td>
</tr><tr>
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
<td><p>List of dependency injection providers visible both to the contents of this module and to importers of this module.</p>
<p>依赖注入提供商的列表,本模块以及本模块导入的所有模块中的内容都可以看见它们。</p>
</td>
</tr><tr>
<td><code><b>bootstrap:</b> [MyAppComponent]</code></td>
<td><p>List of components to bootstrap when this module is bootstrapped.</p>
<p>当本模块启动时,随之启动的组件列表。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Template syntax</p>
<p>模板语法</p>
</th>
<th>Template syntax</th>
<th></th>
</tr>
<tr>
<td><code>&lt;input <b>[value]</b>="firstName"&gt;</code></td>
<td><p>Binds property <code>value</code> to the result of expression <code>firstName</code>.</p>
<p><code>value</code>属性绑定到表达式<code>firstName</code></p>
</td>
</tr><tr>
<td><code>&lt;div <b>[attr.role]</b>="myAriaRole"&gt;</code></td>
<td><p>Binds attribute <code>role</code> to the result of expression <code>myAriaRole</code>.</p>
<p>把属性Attribute<code>role</code>绑定到表达式<code>myAriaRole</code>的结果。</p>
</td>
</tr><tr>
<td><code>&lt;div <b>[class.extra-sparkle]</b>="isDelightful"&gt;</code></td>
<td><p>Binds the presence of the CSS class <code>extra-sparkle</code> on the element to the truthiness of the expression <code>isDelightful</code>.</p>
<p>根据<code>isDelightful</code>表达式的结果是否为真决定CSS类<code>extra-sparkle</code>是否出现在当前元素上。</p>
</td>
</tr><tr>
<td><code>&lt;div <b>[style.width.px]</b>="mySize"&gt;</code></td>
<td><p>Binds style property <code>width</code> to the result of expression <code>mySize</code> in pixels. Units are optional.</p>
<p>把CSS样式属性<code>width</code>的px像素值绑定到表达式<code>mySize</code>的结果。单位是可选的。</p>
</td>
</tr><tr>
<td><code>&lt;button <b>(click)</b>="readRainbow($event)"&gt;</code></td>
<td><p>Calls method <code>readRainbow</code> when a click event is triggered on this button element (or its children) and passes in the event object.</p>
<p>当这个按钮元素及其子元素上的click事件触发时调用方法<code>readRainbow</code>,并把这个事件对象作为参数传进去。</p>
</td>
</tr><tr>
<td><code>&lt;div title="Hello <b>{{ponyName}}</b>"&gt;</code></td>
<td><p>Binds a property to an interpolated string, for example, "Hello Seabiscuit". Equivalent to:
<code>&lt;div [title]="'Hello ' + ponyName"&gt;</code></p>
<p>把一个属性绑定到插值字符串(如"Hello Seabiscuit")。这种写法等价于<code>&lt;div [title]="'Hello ' + ponyName"&gt;</code></p>
</td>
</tr><tr>
<td><code>&lt;p&gt;Hello <b>{{ponyName}}</b>&lt;/p&gt;</code></td>
<td><p>Binds text content to an interpolated string, for example, "Hello Seabiscuit".</p>
<p>把文本内容绑定到插值字符串(如"Hello Seabiscuit"</p>
</td>
</tr><tr>
<td><code>&lt;my-cmp <b>[(title)]</b>="name"&gt;</code></td>
<td><p>Sets up two-way data binding. Equivalent to: <code>&lt;my-cmp [title]="name" (titleChange)="name=$event"&gt;</code></p>
<p>设置双向绑定。等价于<code>&lt;my-cmp [title]="name" (titleChange)="name=$event"&gt;</code></p>
</td>
</tr><tr>
<td><code>&lt;video <b>#movieplayer</b> ...&gt;<br> &lt;button <b>(click)</b>="movieplayer.play()"&gt;<br>&lt;/video&gt;</code></td>
<td><p>Creates a local variable <code>movieplayer</code> that provides access to the <code>video</code> element instance in data-binding and event-binding expressions in the current template.</p>
<p>创建一个局部变量<code>movieplayer</code>,支持在当前模板的数据绑定和事件绑定表达式中访问<code>video</code>元素的实例。</p>
</td>
</tr><tr>
<td><code>&lt;p <b>*myUnless</b>="myExpression"&gt;...&lt;/p&gt;</code></td>
<td><p>The <code>*</code> symbol turns the current element into an embedded template. Equivalent to:
<code>&lt;template [myUnless]="myExpression"&gt;&lt;p&gt;...&lt;/p&gt;&lt;/template&gt;</code></p>
<p>星号<code>*</code>会把当前元素转换成内嵌式模板,等价于:<code>&lt;template [myUnless]="myExpression"&gt;&lt;p&gt;...&lt;/p&gt;&lt;/template&gt;</code></p>
<code>&lt;ng-template [myUnless]="myExpression"&gt;&lt;p&gt;...&lt;/p&gt;&lt;/ng-template&gt;</code></p>
</td>
</tr><tr>
<td><code>&lt;p&gt;Card No.: <b>{{cardNumber | myCardNumberFormatter}}</b>&lt;/p&gt;</code></td>
<td><p>Transforms the current value of expression <code>cardNumber</code> via the pipe called <code>myCardNumberFormatter</code>.</p>
<p>使用名叫<code>myCardNumberFormatter</code>的管道对表达式<code>cardNumber</code>的当前值进行变幻</p>
</td>
</tr><tr>
<td><code>&lt;p&gt;Employer: <b>{{employer?.companyName}}</b>&lt;/p&gt;</code></td>
<td><p>The safe navigation operator (<code>?</code>) means that the <code>employer</code> field is optional and if <code>undefined</code>, the rest of the expression should be ignored.</p>
<p>安全导航操作符(<code>?</code>)表示<code>employer</code>字段是可选的,如果它是 <code>undefined</code> ,那么表达式其余的部分就会被忽略,并返回 <code>undefined</code></p>
</td>
</tr><tr>
<td><code>&lt;<b>svg:</b>rect x="0" y="0" width="100" height="100"/&gt;</code></td>
<td><p>An SVG snippet template needs an <code>svg:</code> prefix on its root element to disambiguate the SVG element from an HTML component.</p>
<p>模板中的 SVG 片段需要给它的根元素加上<code>svg:</code>前缀,以便把 SVG 元素和 HTML 元素区分开。</p>
</td>
</tr><tr>
<td><code>&lt;<b>svg</b>&gt;<br> &lt;rect x="0" y="0" width="100" height="100"/&gt;<br>&lt;/<b>svg</b>&gt;</code></td>
<td><p>An <code>&lt;svg&gt;</code> root element is detected as an SVG element automatically, without the prefix.</p>
<p><code>&lt;svg&gt;</code>作为根元素时会自动识别为 SVG 元素,不需要前缀。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Built-in directives</p>
<p>内置指令</p>
</th>
<th>Built-in directives</th>
<th><p><code>import { CommonModule } from '@angular/common';</code>
</p>
</th>
</tr>
<tr>
<td><code>&lt;section <b>*ngIf</b>="showSection"&gt;</code></td>
<td><p>Removes or recreates a portion of the DOM tree based on the <code>showSection</code> expression.</p>
<p>根据<code>showSection</code>表达式的结果,移除或重新创建 DOM 树的一部分。</p>
</td>
</tr><tr>
<td><code>&lt;li <b>*ngFor</b>="let item of list"&gt;</code></td>
<td><p>Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.</p>
<p>把li元素及其内容变成一个模板并使用这个模板为列表中的每一个条目实例化一个视图。</p>
</td>
</tr><tr>
<td><code>&lt;div <b>[ngSwitch]</b>="conditionExpression"&gt;<br> &lt;template <b>[<b>ngSwitchCase</b>]</b>="case1Exp"&gt;...&lt;/template&gt;<br> &lt;template <b>ngSwitchCase</b>="case2LiteralString"&gt;...&lt;/template&gt;<br> &lt;template <b>ngSwitchDefault</b>&gt;...&lt;/template&gt;<br>&lt;/div&gt;</code></td>
<td><code>&lt;div <b>[ngSwitch]</b>="conditionExpression"&gt;<br> &lt;ng-template <b>[<b>ngSwitchCase</b>]</b>="case1Exp"&gt;...&lt;/ng-template&gt;<br> &lt;ng-template <b>ngSwitchCase</b>="case2LiteralString"&gt;...&lt;/ng-template&gt;<br> &lt;ng-template <b>ngSwitchDefault</b>&gt;...&lt;/ng-template&gt;<br>&lt;/div&gt;</code></td>
<td><p>Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of <code>conditionExpression</code>.</p>
<p>根据<code>conditionExpression</code>的当前值选择一个嵌入式模板,并用它替换这个 div 的内容。</p>
</td>
</tr><tr>
<td><code>&lt;div <b>[ngClass]</b>="{'active': isActive, 'disabled': isDisabled}"&gt;</code></td>
<td><p>Binds the presence of CSS classes on the element to the truthiness of the associated map values. The right-hand expression should return {class-name: true/false} map.</p>
<p>根据 map 中的 value 是否为真,来决定该元素上是否出现与 name 对应的 CSS 类。右侧的表达式应该返回一个形如 <code>{class-name: true/false}</code> 的 map。</p>
</td>
</tr>
<tr>
<td><code>&lt;div <b>[ngStyle]</b>="{'property': 'value'}"&gt;</code><br><code>&lt;div <b>[ngStyle]</b>="dynamicStyles()"&gt;</code></td>
<td><p>Allows you to assign styles to an HTML element using CSS. You can use CSS directly, as in the first example, or you can call a method from the component.</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Forms</p>
<p>表单</p>
</th>
<th>Forms</th>
<th><p><code>import { FormsModule } from '@angular/forms';</code>
</p>
</th>
</tr>
<tr>
<td><code>&lt;input <b>[(ngModel)]</b>="userName"&gt;</code></td>
<td><p>Provides two-way data-binding, parsing, and validation for form controls.</p>
<p>为表单控件提供双向数据绑定、解析和验证功能。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Class decorators</p>
<p>类装饰器decorator</p>
</th>
<th>Class decorators</th>
<th><p><code>import { Directive, ... } from '@angular/core';</code>
</p>
</th>
</tr>
<tr>
<td><code><b>@Component({...})</b><br>class MyComponent() {}</code></td>
<td><p>Declares that a class is a component and provides metadata about the component.</p>
<p>声明一个类是组件,并提供该组件的元数据。</p>
</td>
</tr><tr>
<td><code><b>@Directive({...})</b><br>class MyDirective() {}</code></td>
<td><p>Declares that a class is a directive and provides metadata about the directive.</p>
<p>声明一个类是指令,并提供该指令的元数据。</p>
</td>
</tr><tr>
<td><code><b>@Pipe({...})</b><br>class MyPipe() {}</code></td>
<td><p>Declares that a class is a pipe and provides metadata about the pipe.</p>
<p>声明一个类是管道,并提供该管道的元数据。</p>
</td>
</tr><tr>
<td><code><b>@Injectable()</b><br>class MyService() {}</code></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>
<p>声明一个类具有一些依赖,当依赖注入器试图创建该类的实例时,应该把这些依赖注入到该类的构造函数中。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Directive configuration</p>
<p>指令配置</p>
</th>
<th>Directive configuration</th>
<th><p><code>@Directive({ property1: value1, ... })</code>
</p>
</th>
</tr>
<tr>
<td><code><b>selector:</b> '.cool-button:not(a)'</code></td>
<td><p>Specifies a CSS selector that identifies this directive within a template. Supported selectors include <code>element</code>,
<code>[attribute]</code>, <code>.class</code>, and <code>:not()</code>.</p>
<p>指定一个 CSS 选择器,用于在模板中标记出该指令。支持的选择器类型包括:<code>元素名</code><code>[属性名]</code>, <code>.类名</code><code>:not()</code></p>
<p>Does not support parent-child relationship selectors.</p>
<p>但不支持指定父子关系的选择器。</p>
</td>
</tr><tr>
<td><code><b>providers:</b> [MyService, { provide: ... }]</code></td>
<td><p>List of dependency injection providers for this directive and its children.</p>
<p>该指令及其子指令的依赖注入提供商列表。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Component configuration</p>
<p>组件配置</p>
</th>
<th>Component configuration</th>
<th><p>
<code>@Component</code> extends <code>@Directive</code>,
so the <code>@Directive</code> configuration applies to components as well</p>
<p><code>@Component</code> 继承自 <code>@Directive</code>,因此 <code>@Directive</code> 的配置也能用于 <code>@Component</code></p>
so the
<code>@Directive</code> configuration applies to components as well</p>
</th>
</tr>
<tr>
<td><code><b>moduleId:</b> module.id</code></td>
<td><p>If set, the <code>templateUrl</code> and <code>styleUrl</code> are resolved relative to the component.</p>
<p>如果设置了,那么 <code>templateUrl</code><code>styleUrl</code> 的路径就会相对于当前组件进行解析。</p>
</td>
</tr><tr>
<td><code><b>viewProviders:</b> [MyService, { provide: ... }]</code></td>
<td><p>List of dependency injection providers scoped to this component's view.</p>
<p>依赖注入提供商列表,但它们的范围被限定为当前组件的视图。</p>
</td>
</tr><tr>
<td><code><b>template:</b> 'Hello {{name}}'<br><b>templateUrl:</b> 'my-component.html'</code></td>
<td><p>Inline template or external template URL of the component's view.</p>
<p>当前组件视图的内联模板或外部模板的 URL 。</p>
</td>
</tr><tr>
<td><code><b>styles:</b> ['.primary {color: red}']<br><b>styleUrls:</b> ['my-component.css']</code></td>
<td><p>List of inline CSS styles or external stylesheet URLs for styling the components view.</p>
<p>用于为当前组件的视图提供样式的内联 CSS 或外部样式表 URL 的列表。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Class field decorators for directives and components</p>
<p>给指令或组件类用的属性装饰器</p>
</th>
<th>Class field decorators for directives and components</th>
<th><p><code>import { Input, ... } from '@angular/core';</code>
</p>
</th>
</tr>
<tr>
<td><code><b>@Input()</b> myProperty;</code></td>
<td><p>Declares an input property that you can update via property binding (example:
<code>&lt;my-cmp [myProperty]="someExpression"&gt;</code>).</p>
<p>声明一个输入属性,你可以通过属性绑定来更新它,如 <code>&lt;my-cmp [myProperty]="someExpression"&gt;</code></p>
</td>
</tr><tr>
<td><code><b>@Output()</b> myEvent = new EventEmitter();</code></td>
<td><p>Declares an output property that fires events that you can subscribe to with an event binding (example: <code>&lt;my-cmp (myEvent)="doSomething()"&gt;</code>).</p>
<p>声明一个输出属性,它发出事件,你可以用事件绑定来订阅它们(如:<code>&lt;my-cmp (myEvent)="doSomething()"&gt;</code>)。</p>
</td>
</tr><tr>
<td><code><b>@HostBinding('class.valid')</b> isValid;</code></td>
<td><p>Binds a host element property (here, the CSS class <code>valid</code>) to a directive/component property (<code>isValid</code>).</p>
<p>把宿主元素的一个属性(这里是 CSS 类 <code>valid</code>)绑定到指令或组件上的 <code>isValid</code> 属性。</p>
</td>
</tr><tr>
<td><code><b>@HostListener('click', ['$event'])</b> onClick(e) {...}</code></td>
<td><p>Subscribes to a host element event (<code>click</code>) with a directive/component method (<code>onClick</code>), optionally passing an argument (<code>$event</code>).</p>
<p>用指令或组件上的<code>onClick</code>方法订阅宿主元素上的<code>click</code>事件,并从中获取<code>$event</code>参数(可选)</p>
</td>
</tr><tr>
<td><code><b>@ContentChild(myPredicate)</b> myChildComponent;</code></td>
<td><p>Binds the first result of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class.</p>
<p>把组件内容查询(<code>myPredicate</code>)的第一个结果绑定到该类的 <code>myChildComponent</code> 属性上。</p>
</td>
</tr><tr>
<td><code><b>@ContentChildren(myPredicate)</b> myChildComponents;</code></td>
<td><p>Binds the results of the component content query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class.</p>
<p>把组件内容查询(<code>myPredicate</code>)的全部结果绑定到该类的 <code>myChildComponents</code> 属性上</p>
</td>
</tr><tr>
<td><code><b>@ViewChild(myPredicate)</b> myChildComponent;</code></td>
<td><p>Binds the first result of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponent</code>) of the class. Not available for directives.</p>
<p>把组件视图查询(<code>myPredicate</code>)的第一个结果绑定到该类的 <code>myChildComponent</code> 属性上。对指令无效。</p>
</td>
</tr><tr>
<td><code><b>@ViewChildren(myPredicate)</b> myChildComponents;</code></td>
<td><p>Binds the results of the component view query (<code>myPredicate</code>) to a property (<code>myChildComponents</code>) of the class. Not available for directives.</p>
<p>把组件视图查询(<code>myPredicate</code>)的全部结果绑定到该类的 <code>myChildComponents</code> 属性上。对指令无效。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Directive and component change detection and lifecycle hooks</p>
<p>指令和组件的变更检测与生命周期钩子</p>
</th>
<th>Directive and component change detection and lifecycle hooks</th>
<th><p>(implemented as class methods)
</p>
<p>由类的方法实现。</p>
</th>
</tr>
<tr>
<td><code><b>constructor(myService: MyService, ...)</b> { ... }</code></td>
<td><p>Called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.</p>
<p>在任何其它生命周期钩子之前调用。可以用它来注入依赖项,但不要在这里做正事。</p>
</td>
</tr><tr>
<td><code><b>ngOnChanges(changeRecord)</b> { ... }</code></td>
<td><p>Called after every change to input properties and before processing content or child views.</p>
<p>每当输入属性发生变化时就会调用,但位于处理内容(<code>ng-content</code>)或子视图之前。</p>
</td>
</tr><tr>
<td><code><b>ngOnInit()</b> { ... }</code></td>
<td><p>Called after the constructor, initializing input properties, and the first call to <code>ngOnChanges</code>.</p>
<p>在调用完构造函数、初始化完所有输入属性并首次调用过<code>ngOnChanges</code>之后调用。</p>
</td>
</tr><tr>
<td><code><b>ngDoCheck()</b> { ... }</code></td>
<td><p>Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.</p>
<p>每当对组件或指令的输入属性进行变更检测时就会调用。可以用它来扩展变更检测逻辑,执行自定义的检测逻辑。</p>
</td>
</tr><tr>
<td><code><b>ngAfterContentInit()</b> { ... }</code></td>
<td><p>Called after <code>ngOnInit</code> when the component's or directive's content has been initialized.</p>
<p><code>ngOnInit</code>完成之后,当组件或指令的内容(<code>ng-content</code>)已经初始化完毕时调用。</p>
</td>
</tr><tr>
<td><code><b>ngAfterContentChecked()</b> { ... }</code></td>
<td><p>Called after every check of the component's or directive's content.</p>
<p>每当组件或指令的内容(<code>ng-content</code>)做变更检测时调用。</p>
</td>
</tr><tr>
<td><code><b>ngAfterViewInit()</b> { ... }</code></td>
<td><p>Called after <code>ngAfterContentInit</code> when the component's view has been initialized. Applies to components only.</p>
<p><code>ngAfterContentInit</code>完毕,并且组件的视图已经初始化完毕时调用。只适用于组件。</p>
</td>
</tr><tr>
<td><code><b>ngAfterViewChecked()</b> { ... }</code></td>
<td><p>Called after every check of the component's view. Applies to components only.</p>
<p>当组件视图每次执行变更检测时调用。只适用于组件。</p>
</td>
</tr><tr>
<td><code><b>ngOnDestroy()</b> { ... }</code></td>
<td><p>Called once, before the instance is destroyed.</p>
<p>只在实例被销毁前调用一次。</p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Dependency injection configuration</p>
<p>依赖注入的配置</p>
</th>
<th>Dependency injection configuration</th>
<th></th>
</tr>
<tr>
<td><code>{ <b>provide</b>: MyService, <b>useClass</b>: MyMockService }</code></td>
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>MyMockService</code> class.</p>
<p><code>MyService</code> 的服务提供商设置或改写为 <code>MyMockService</code> 类。</p>
</td>
</tr><tr>
<td><code>{ <b>provide</b>: MyService, <b>useFactory</b>: myFactory }</code></td>
<td><p>Sets or overrides the provider for <code>MyService</code> to the <code>myFactory</code> factory function.</p>
<p><code>MyService</code> 的服务提供商设置或改写为 <code>myFactory</code> 工厂函数。</p>
</td>
</tr><tr>
<td><code>{ <b>provide</b>: MyValue, <b>useValue</b>: 41 }</code></td>
<td><p>Sets or overrides the provider for <code>MyValue</code> to the value <code>41</code>.</p>
<p><code>MyValue</code> 的服务提供商改写为一个特定的值 <code>41</code></p>
</td>
</tr>
</tbody></table>
<table class="is-full-width is-fixed-layout">
<tbody><tr>
<th>
<p>Routing and navigation</p>
<p>路由与导航</p>
</th>
<th>Routing and navigation</th>
<th><p><code>import { Routes, RouterModule, ... } from '@angular/router';</code>
</p>
</th>
</tr>
<tr>
<td><code>const routes: <b>Routes</b> = [<br> { path: '', component: HomeComponent },<br> { path: 'path/:routeParam', component: MyComponent },<br> { path: 'staticPath', component: ... },<br> { path: '**', component: ... },<br> { path: 'oldPath', redirectTo: '/staticPath' },<br> { path: ..., component: ..., data: { message: 'Custom' } }<br>]);<br><br>const routing = RouterModule.forRoot(routes);</code></td>
<td><p>Configures routes for the application. Supports static, parameterized, redirect, and wildcard routes. Also supports custom route data and resolve.</p>
<p>为该应用配置路由。支持静态、参数化、重定向和通配符路由。也支持自定义路由数据和解析resolve函数。</p>
</td>
</tr><tr>
<td><code><br>&lt;<b>router-outlet</b>&gt;&lt;/<b>router-outlet</b>&gt;<br>&lt;<b>router-outlet</b> name="aux"&gt;&lt;/<b>router-outlet</b>&gt;<br></code></td>
<td><p>Marks the location to load the component of the active route.</p>
<p>标记出一个位置,用来加载活动路由的组件。</p>
</td>
</tr><tr>
<td><code><br>&lt;a routerLink="/path"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path', routeParam ]"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path', { matrixParam: 'value' } ]"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path' ]" [queryParams]="{ page: 1 }"&gt;<br>&lt;a <b>[routerLink]</b>="[ '/path' ]" fragment="anchor"&gt;<br></code></td>
<td><p>Creates a link to a different view based on a route instruction consisting of a route path, required and optional parameters, query parameters, and a fragment. To navigate to a root route, use the <code>/</code> prefix; for a child route, use the <code>./</code>prefix; for a sibling or parent, use the <code>../</code> prefix.</p>
<p>使用路由体系创建一个到其它视图的链接。路由体系由路由路径、必要参数、可选参数、查询参数和文档片段组成。要导航到根路由,请使用<code>/</code>前缀;要导航到子路由,使用<code>./</code>前缀;要导航到兄弟路由或父级路由,使用<code>../</code>前缀。</p>
</td>
</tr><tr>
<td><code>&lt;a [routerLink]="[ '/path' ]" routerLinkActive="active"&gt;</code></td>
<td><p>The provided classes are added to the element when the <code>routerLink</code> becomes the current active route.</p>
<p><code>routerLink</code> 指向的路由变成活动路由时,为当前元素添加一些类(比如这里的 <code>active</code>)。</p>
</td>
</tr><tr>
<td><code>class <b>CanActivate</b>Guard implements <b>CanActivate</b> {<br> canActivate(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canActivate: [<b>CanActivate</b>Guard] }</code></td>
<td><p>An interface for defining a class that the router should call first to determine if it should activate this component. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
<p>用来定义类的接口。路由器会首先调用本接口来决定是否激活该路由。应该返回一个 <code>boolean</code> 或能解析成 <code>boolean</code><code>Observable/Promise</code></p>
</td>
</tr><tr>
<td><code>class <b>CanDeactivate</b>Guard implements <b>CanDeactivate</b>&lt;T&gt; {<br> canDeactivate(<br> component: T,<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canDeactivate: [<b>CanDeactivate</b>Guard] }</code></td>
<td><p>An interface for defining a class that the router should call first to determine if it should deactivate this component after a navigation. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
<p>用来定义类的接口。路由器会在导航离开前首先调用本接口以决定是否取消激活本路由。应该返回一个 <code>boolean</code> 或能解析成 <code>boolean</code><code>Observable/Promise</code></p>
</td>
</tr><tr>
<td><code>class <b>CanActivateChild</b>Guard implements <b>CanActivateChild</b> {<br> canActivateChild(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canActivateChild: [CanActivateGuard],<br> children: ... }</code></td>
<td><p>An interface for defining a class that the router should call first to determine if it should activate the child route. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
<p>用来定义类的接口。路由器会首先调用本接口来决定是否激活一个子路由。应该返回一个 <code>boolean</code> 或能解析成 <code>boolean</code><code>Observable/Promise</code></p>
</td>
</tr><tr>
<td><code>class <b>Resolve</b>Guard implements <b>Resolve</b>&lt;T&gt; {<br> resolve(<br> route: ActivatedRouteSnapshot,<br> state: RouterStateSnapshot<br> ): Observable&lt;any&gt;|Promise&lt;any&gt;|any { ... }<br>}<br><br>{ path: ..., resolve: [<b>Resolve</b>Guard] }</code></td>
<td><p>An interface for defining a class that the router should call first to resolve route data before rendering the route. Should return a value or an Observable/Promise that resolves to a value.</p>
<p>用来定义类的接口。路由器会在渲染该路由之前,首先调用它来解析路由数据。应该返回一个值或能解析成值的 <code>Observable/Promise</code></p>
</td>
</tr><tr>
<td><code>class <b>CanLoad</b>Guard implements <b>CanLoad</b> {<br> canLoad(<br> route: Route<br> ): Observable&lt;boolean&gt;|Promise&lt;boolean&gt;|boolean { ... }<br>}<br><br>{ path: ..., canLoad: [<b>CanLoad</b>Guard], loadChildren: ... }</code></td>
<td><p>An interface for defining a class that the router should call first to check if the lazy loaded module should be loaded. Should return a boolean or an Observable/Promise that resolves to a boolean.</p>
<p>用来定义类的接口。路由器会首先调用它来决定是否应该加载一个惰性加载模块。应该返回一个 <code>boolean</code> 或能解析成 <code>boolean</code><code>Observable/Promise</code></p>
</td>
</tr>
</tbody></table>
</div>

View File

@ -16,52 +16,53 @@ Observables are often compared to promises. Here are some key differences:
* Observables `subscribe()` is responsible for handling errors. Promises push errors to the child promises. This makes observables useful for centralized and predictable error handling.
### Creation and subscription
* 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.
<code-example hideCopy>
// declare a publishing operation
new Observable((observer) => { subscriber_fn });
// initiate execution
observable.subscribe(() => {
// observer handles notifications
});
</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.
<code-example hideCopy>
// initiate execution
new Promise((resolve, reject) => { executer_fn });
// handle return value
promise.then((value) => {
// handle result here
});
</code-example>
### Chaining
* 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>
* Promises do not differentiate between the last `.then` clauses (equivalent to subscription) and intermediate `.then` clauses (equivalent to map).
<code-example hideCopy>promise.then((v) => 2*v);</code-example>
### Cancellation
* Observable subscriptions are cancellable. Unsubscribing removes the listener from receiving further values, and notifies the subscriber function to cancel work.
<code-example hideCopy>
const sub = obs.subscribe(...);
sub.unsubscribe();
</code-example>
* Promises are not cancellable.
@ -71,17 +72,21 @@ sub.unsubscribe();
* Observable execution errors are delivered to the subscriber's error handler, and the subscriber automatically unsubscribes from the observable.
<code-example hideCopy>
obs.subscribe(() => {
throw Error('my error');
});
</code-example>
* Promises push errors to the child promises.
<code-example hideCopy>
promise.then(() => {
throw Error('my error');
});
</code-example>
### Cheat sheet
@ -89,47 +94,89 @@ promise.then(() => {
The following code snippets illustrate how the same kind of operation is defined using observables and promises.
<table>
<th>
<td>Operation</td>
<td>Observable</td>
<td>Promise</td>
</th>
<tr>
<td>Creation</td>
<td>
<pre>new Observable((observer) => {
observer.next(123);
});</pre>
});
</pre>
</td>
<td>
<pre>new Promise((resolve, reject) => {
resolve(123);
});</pre>
});
</pre>
</td>
</tr>
<tr>
<td>Transform</td>
<td><pre>obs.map((value) => value * 2 );</pre></td>
<td><pre>promise.then((value) => value * 2);</pre></td>
</tr>
<tr>
<td>Subscribe</td>
<td>
<pre>sub = obs.subscribe((value) => {
console.log(value)
});</pre>
});
</pre>
</td>
<td>
<pre>promise.then((value) => {
console.log(value);
});</pre>
});
</pre>
</td>
</tr>
<tr>
<td>Unsubscribe</td>
<td><pre>sub.unsubscribe();</pre></td>
<td>Implied by promise resolution.</td>
</tr>
</table>
## Observables compared to events API
@ -141,22 +188,35 @@ Using observables to handle events and asynchronous operations can have the adva
Here are some code samples that illustrate how the same kind of operation is defined using observables and the events API.
<table>
<th>
<td>Observable</td>
<td>Events API</td>
</th>
<tr>
<td>Creation & cancellation</td>
<td>
<pre>// Setup
let clicks$ = fromEvent(buttonEl, click);
// Begin listening
let subscription = clicks$
.subscribe(e => console.log(Clicked, e))
// Stop listening
subscription.unsubscribe();</pre>
subscription.unsubscribe();
</pre>
</td>
<td>
<pre>function handler(e) {
console.log(Clicked, e);
}
@ -165,106 +225,196 @@ subscription.unsubscribe();</pre>
button.addEventListener(click, handler);
// Stop listening
button.removeEventListener(click, handler);
</pre>
</td>
</tr>
<tr>
<td>Subscription</td>
<td>
<pre>observable.subscribe(() => {
// notification handlers here
});</pre>
});
</pre>
</td>
<td>
<pre>element.addEventListener(eventName, (event) => {
// notification handler here
});</pre>
});
</pre>
</td>
</tr>
<tr>
<td>Configuration</td>
<td>Listen for keystrokes, but provide a stream representing the value in the input.
<pre>fromEvent(inputEl, 'keydown').pipe(
map(e => e.target.value)
);</pre>
);
</pre>
</td>
<td>Does not support configuration.
<pre>element.addEventListener(eventName, (event) => {
// Cannot change the passed Event into another
// value before it gets to the handler
});</pre>
</td>
</tr>
</table>
});
</pre>
</td>
</tr>
</table>
## Observables compared to arrays
An observable produces values over time. An array is created as a static set of values. In a sense, observables are asynchronous where arrays are synchronous. In the following examples, ➞ implies asynchronous value delivery.
<table>
<th>
<td>Observable</td>
<td>Array</td>
</th>
<tr>
<td>Given</td>
<td>
<pre>obs: ➞1➞2➞3➞5➞7</pre>
<pre>obsB: ➞'a'➞'b'➞'c'</pre>
</td>
<td>
<pre>arr: [1, 2, 3, 5, 7]</pre>
<pre>arrB: ['a', 'b', 'c']</pre>
</td>
</tr>
<tr>
<td><pre>concat()</pre></td>
<td>
<pre>obs.concat(obsB)</pre>
<pre>➞1➞2➞3➞5➞7➞'a'➞'b'➞'c'</pre>
</td>
<td>
<pre>arr.concat(arrB)</pre>
<pre>[1,2,3,5,7,'a','b','c']</pre>
</td>
</tr>
<tr>
<td><pre>filter()</pre></td>
<td>
<pre>obs.filter((v) => v>3)</pre>
<pre>➞5➞7</pre>
</td>
<td>
<pre>arr.filter((v) => v>3)</pre>
<pre>[5, 7]</pre>
</td>
</tr>
<tr>
<td><pre>find()</pre></td>
<td>
<pre>obs.find((v) => v>3)</pre>
<pre>➞5</pre>
</td>
<td>
<pre>arr.find((v) => v>10)</pre>
<pre>5</pre>
</td>
</tr>
<tr>
<td><pre>findIndex()</pre></td>
<td>
<pre>obs.findIndex((v) => v>3)</pre>
<pre>➞3</pre>
</td>
<td>
<pre>arr.findIndex((v) => v>3)</pre>
<pre>3</pre>
</td>
</tr>
<tr>
<td><pre>forEach()</pre></td>
<td>
<pre>obs.forEach((v) => {
console.log(v);
})
@ -272,9 +422,14 @@ An observable produces values over time. An array is created as a static set of
2
3
4
5</pre>
5
</pre>
</td>
<td>
<pre>arr.forEach((v) => {
console.log(v);
})
@ -282,32 +437,57 @@ An observable produces values over time. An array is created as a static set of
2
3
4
5</pre>
5
</pre>
</td>
</tr>
<tr>
<td><pre>map()</pre></td>
<td>
<pre>obs.map((v) => -v)</pre>
<pre>➞-1➞-2➞-3➞-5➞-7</pre>
</td>
<td>
<pre>arr.map((v) => -v)</pre>
<pre>[-1, -2, -3, -5, -7]</pre>
</td>
</tr>
<tr>
<td><pre>reduce()</pre></td>
<td>
<pre>obs.scan((s,v)=> s+v, 0)</pre>
<pre>➞1➞3➞6➞11➞18</pre>
</td>
<td>
<pre>arr.reduce((s,v) => s+v, 0)</pre>
<pre>18</pre>
</td>
</tr>
</table>

View File

@ -9,19 +9,6 @@ in which two or more components share information.
本烹饪宝典包含了常见的组件通讯场景,也就是让两个或多个组件之间共享信息的方法。
<div class="l-sub-section">
For an in-depth look at each fundamental concepts in component communication, we can find detailed description and
samples in the [Component Communication]() document.
要深入了解组件通讯的各个基本概念,在[组件通讯]()文档中可以找到详细的描述和例子。
</div>
{@a toc}
<!--
@ -67,55 +54,44 @@ typically adorned with [@Input decorations](guide/template-syntax#inputs-outputs
`HeroChildComponent` 有两个***输入型属性***,它们通常带[@Input装饰器](guide/template-syntax#inputs-outputs)。
<code-example path="component-interaction/src/app/hero-child.component.ts" title="component-interaction/src/app/hero-child.component.ts">
</code-example>
The second `@Input` aliases the child component property name `masterName` as `'master'`.
第二个`@Input`为子组件的属性名`masterName`指定一个别名`master`(译者注:不推荐为起别名,请参见风格指南).
The `HeroParentComponent` nests the child `HeroChildComponent` inside an `*ngFor` repeater,
binding its `master` string property to the child's `master` alias, and each iteration's `hero` instance to the child's `hero` property.
binding its `master` string property to the child's `master` alias,
and each iteration's `hero` instance to the child's `hero` property.
父组件`HeroParentComponent`把子组件的`HeroChildComponent`放到`*ngFor`循环器中,把自己的`master`字符串属性绑定到子组件的`master`别名上,并把每个循环的`hero`实例绑定到子组件的`hero`属性。
<code-example path="component-interaction/src/app/hero-parent.component.ts" title="component-interaction/src/app/hero-parent.component.ts">
</code-example>
The running application displays three heroes:
运行应用程序会显示三个英雄:
<figure>
<img src="generated/images/guide/component-interaction/parent-to-child.png" alt="Parent-to-child">
</figure>
<h3 class="no-toc">Test it</h3>
### 测试
E2E test that all children were instantiated and displayed as expected:
端到端测试,用于确保所有的子组件都像所期待的那样被初始化并显示出来。
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child" title="component-interaction/e2e/app.e2e-spec.ts">
</code-example>
[Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top)
@ -135,45 +111,34 @@ trims the whitespace from a name and replaces an empty value with default text.
子组件`NameChildComponent`的输入属性`name`上的这个setter会trim掉名字里的空格并把空值替换成默认字符串。
<code-example path="component-interaction/src/app/name-child.component.ts" title="component-interaction/src/app/name-child.component.ts">
</code-example>
Here's the `NameParentComponent` demonstrating name variations including a name with all spaces:
下面的`NameParentComponent`展示了各种名字的处理方式,包括一个全是空格的名字。
<code-example path="component-interaction/src/app/name-parent.component.ts" title="component-interaction/src/app/name-parent.component.ts">
</code-example>
<figure>
<img src="generated/images/guide/component-interaction/setter.png" alt="Parent-to-child-setter">
</figure>
<h3 class="no-toc">Test it</h3>
### 测试
E2E tests of input property setter with empty and non-empty names:
端到端测试输入属性的setter分别使用空名字和非空名字。
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child-setter" title="component-interaction/e2e/app.e2e-spec.ts">
</code-example>
[Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top)
@ -188,11 +153,8 @@ Detect and act upon changes to input property values with the `ngOnChanges()` me
使用`OnChanges`生命周期钩子接口的`ngOnChanges()`方法来监测输入属性值的变化并做出回应。
<div class="l-sub-section">
You may prefer this approach to the property setter when watching multiple, interacting input properties.
当需要监视多个、交互式输入属性的时候本方法比用属性的setter更合适。
@ -201,60 +163,47 @@ Learn about `ngOnChanges()` in the [LifeCycle Hooks](guide/lifecycle-hooks) chap
学习关于`ngOnChanges()`的更多知识,参见[生命周期钩子](guide/lifecycle-hooks)一章。
</div>
This `VersionChildComponent` detects changes to the `major` and `minor` input properties and composes a log message reporting these changes:
这个`VersionChildComponent`会监测输入属性`major``minor`的变化,并把这些变化编写成日志以报告这些变化。
<code-example path="component-interaction/src/app/version-child.component.ts" title="component-interaction/src/app/version-child.component.ts">
</code-example>
The `VersionParentComponent` supplies the `minor` and `major` values and binds buttons to methods that change them.
`VersionParentComponent`提供`minor``major`值,把修改它们值的方法绑定到按钮上。
<code-example path="component-interaction/src/app/version-parent.component.ts" title="component-interaction/src/app/version-parent.component.ts">
</code-example>
Here's the output of a button-pushing sequence:
下面是点击按钮的结果。
<figure>
<img src="generated/images/guide/component-interaction/parent-to-child-on-changes.gif" alt="Parent-to-child-onchanges">
</figure>
<h3 class="no-toc">Test it</h3>
### 测试
<h3 class="no-toc">测试一下</h3>
Test that ***both*** input properties are set initially and that button clicks trigger
the expected `ngOnChanges` calls and values:
测试确保***这两个***输入属性值都被初始化了,当点击按钮后,`ngOnChanges`应该被调用,属性的值也符合预期。
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="parent-to-child-onchanges" title="component-interaction/e2e/app.e2e-spec.ts">
</code-example>
[Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top)
@ -276,13 +225,10 @@ The child's `EventEmitter` property is an ***output property***,
子组件的`EventEmitter`属性是一个**输出属性**,通常带有[@Output装饰器](guide/template-syntax#inputs-outputs),就像在`VoterComponent`中看到的。
<code-example path="component-interaction/src/app/voter.component.ts" title="component-interaction/src/app/voter.component.ts">
</code-example>
Clicking a button triggers emission of a `true` or `false`, the boolean *payload*.
点击按钮会触发`true``false`(布尔型*有效载荷*)的事件。
@ -292,46 +238,37 @@ payload `$event` and updates a counter.
父组件`VoteTakerComponent`绑定了一个事件处理器(`onVoted()`),用来响应子组件的事件(`$event`)并更新一个计数器。
<code-example path="component-interaction/src/app/votetaker.component.ts" title="component-interaction/src/app/votetaker.component.ts">
</code-example>
The framework passes the event argument&mdash;represented by `$event`&mdash;to the handler method,
and the method processes it:
框架(Angular)把事件参数(用`$event`表示)传给事件处理方法,这个方法会处理:
<figure>
<img src="generated/images/guide/component-interaction/child-to-parent.gif" alt="Child-to-parent">
</figure>
<h3 class="no-toc">Test it</h3>
### 测试
<h3 class="no-toc">测试一下</h3>
Test that clicking the *Agree* and *Disagree* buttons update the appropriate counters:
测试确保点击*Agree*和*Disagree*按钮时,计数器被正确更新。
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="child-to-parent" title="component-interaction/e2e/app.e2e-spec.ts">
</code-example>
[Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top)
## Parent interacts with child via *local variable*
## 父组件与子组件通过*本地变量*互动
@ -345,28 +282,24 @@ as seen in the following example.
父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法,如下例所示。
{@a countdown-timer-example}
The following is a child `CountdownTimerComponent` that repeatedly counts down to zero and launches a rocket. It has `start` and `stop` methods that control the clock and it displays a countdown status message in its own template.
The following is a child `CountdownTimerComponent` that repeatedly counts down to zero and launches a rocket.
It has `start` and `stop` methods that control the clock and it displays a
countdown status message in its own template.
子组件`CountdownTimerComponent`进行倒计时,归零时发射一个导弹。`start``stop`方法负责控制时钟并在模板里显示倒计时的状态信息。
<code-example path="component-interaction/src/app/countdown-timer.component.ts" title="component-interaction/src/app/countdown-timer.component.ts">
</code-example>
The `CountdownLocalVarParentComponent` that hosts the timer component is as follows:
让我们来看看计时器组件的宿主组件`CountdownLocalVarParentComponent`
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="lv" title="component-interaction/src/app/countdown-parent.component.ts">
</code-example>
The parent component cannot data bind to the child's
`start` and `stop` methods nor to its `seconds` property.
@ -387,19 +320,17 @@ Here we see the parent and child working together.
下面是父组件和子组件一起工作时的效果。
<figure>
<img src="generated/images/guide/component-interaction/countdown-timer-anim.gif" alt="countdown timer">
</figure>
{@a countdown-tests}
<h3 class="no-toc">Test it</h3>
### 测试
<h3 class="no-toc">测试一下</h3>
Test that the seconds displayed in the parent template
match the seconds displayed in the child's status message.
@ -407,13 +338,10 @@ Test also that clicking the *Stop* button pauses the countdown timer:
测试确保在父组件模板中显示的秒数和子组件状态信息里的秒数同步。它还会点击*Stop*按钮来停止倒计时:
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="countdown-timer-tests" title="component-interaction/e2e/app.e2e-spec.ts">
</code-example>
[Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top)
@ -448,32 +376,23 @@ The child [CountdownTimerComponent](guide/component-interaction#countdown-timer-
下面的例子用与[倒计时](guide/component-interaction#countdown-timer-example)相同的范例来解释这种技术。
我们没有改变它的外观或行为。子组件[CountdownTimerComponent](guide/component-interaction#countdown-timer-example)也和原来一样。
<div class="l-sub-section">
The switch from the *local variable* to the *ViewChild* technique
is solely for the purpose of demonstration.
由*本地变量*切换到*ViewChild*技术的唯一目的就是做示范。
</div>
Here is the parent, `CountdownViewChildParentComponent`:
下面是父组件`CountdownViewChildParentComponent`:
<code-example path="component-interaction/src/app/countdown-parent.component.ts" region="vc" title="component-interaction/src/app/countdown-parent.component.ts">
</code-example>
It takes a bit more work to get the child view into the parent component *class*.
把子组件的视图插入到父组件类需要做一点额外的工作。
@ -517,13 +436,12 @@ that it takes future values from the timer component.
<h3 class="no-toc">Test it</h3>
<h3 class="no-toc">测试一下</h3>
<h3 class="no-toc">测试一下</h3>
Use [the same countdown timer tests](guide/component-interaction#countdown-tests) as before.
使用和之前[一样的倒计时测试](guide/component-interaction#countdown-tests)。
[Back to top](guide/component-interaction#top)
[回到顶部](guide/component-interaction#top)
@ -534,7 +452,8 @@ Use [the same countdown timer tests](guide/component-interaction#countdown-tests
## 父组件和子组件通过服务来通讯
A parent component and its children share a service whose interface enables bi-directional communication *within the family*.
A parent component and its children share a service whose interface enables bi-directional communication
*within the family*.
父组件和它的子组件共享同一个服务,利用该服务*在家庭内部*实现双向通讯。
@ -547,41 +466,30 @@ This `MissionService` connects the `MissionControlComponent` to multiple `Astron
这个`MissionService``MissionControlComponent`和多个`AstronautComponent`子组件连接起来。
<code-example path="component-interaction/src/app/mission.service.ts" title="component-interaction/src/app/mission.service.ts">
</code-example>
The `MissionControlComponent` both provides the instance of the service that it shares with its children
(through the `providers` metadata array) and injects that instance into itself through its constructor:
`MissionControlComponent`提供服务的实例,并将其共享给它的子组件(通过`providers`元数据数组),子组件可以通过构造函数将该实例注入到自身。
<code-example path="component-interaction/src/app/missioncontrol.component.ts" title="component-interaction/src/app/missioncontrol.component.ts">
</code-example>
The `AstronautComponent` also injects the service in its constructor.
Each `AstronautComponent` is a child of the `MissionControlComponent` and therefore receives its parent's service instance:
`AstronautComponent`也通过自己的构造函数注入该服务。由于每个`AstronautComponent`都是`MissionControlComponent`的子组件,所以它们获取到的也是父组件的这个服务实例。
<code-example path="component-interaction/src/app/astronaut.component.ts" title="component-interaction/src/app/astronaut.component.ts">
</code-example>
<div class="l-sub-section">
Notice that this example captures the `subscription` and `unsubscribe()` when the `AstronautComponent` is destroyed.
This is a memory-leak guard step. There is no actual risk in this app because the
lifetime of a `AstronautComponent` is the same as the lifetime of the app itself.
@ -595,40 +503,34 @@ it controls the lifetime of the `MissionService`.
不需要在`MissionControlComponent`中添加这个保护措施,因为它作为父组件,控制着`MissionService`的生命期。
</div>
The *History* log demonstrates that messages travel in both directions between
the parent `MissionControlComponent` and the `AstronautComponent` children,
facilitated by the service:
*History*日志证明了:在父组件`MissionControlComponent`和子组件`AstronautComponent`之间,信息通过该服务实现了双向传递。
<figure>
<img src="generated/images/guide/component-interaction/bidirectional-service.gif" alt="bidirectional-service">
</figure>
<h3 class="no-toc">Test it</h3>
### 测试
<h3 class="no-toc">测试一下</h3>
Tests click buttons of both the parent `MissionControlComponent` and the `AstronautComponent` children
and verify that the history meets expectations:
测试确保点击父组件`MissionControlComponent`和子组件`AstronautComponent`两个的组件的按钮时,*History*日志和预期的一样。
<code-example path="component-interaction/e2e/app.e2e-spec.ts" region="bidirectional-service" title="component-interaction/e2e/app.e2e-spec.ts">
</code-example>
[Back to 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.
你可以在Plunker上运行本章这些代码的<live-example></live-example>并下载这些代码。
你可以在 Stackblitz 上运行本章这些代码的<live-example></live-example>并下载这些代码。
## Using component styles
@ -41,8 +41,8 @@ Usually you give it one string, as in the following example:
`styles`属性可以接受一个包含 CSS 代码的字符串数组。
通常我们只给它一个字符串就行了,如同下例:
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts" linenums="false">
</code-example>
## Style scope
@ -93,7 +93,6 @@ This scoping restriction is a ***styling modularity feature***.
将来我们可以修改或移除组件的 CSS 代码,而不用遍历整个应用来看它有没有被别处用到,只要看看当前组件就可以了。
{@a special-selectors}
## Special selectors
@ -116,8 +115,8 @@ targeting elements *inside* the component's template).
使用`: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>
The `:host` selector is the only way to target the host element. You can't reach
@ -137,6 +136,7 @@ The next example targets the host element again, but only when it also has the `
在下一个例子中,我们又一次把宿主元素作为目标,但是只有当它同时带有`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>
### :host-context
@ -163,6 +163,7 @@ if some ancestor element has the CSS class `theme-light`.
在下面的例子中,只有当某个祖先元素有 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>
### (deprecated) `/deep/`, `>>>`, and `::ng-deep`
@ -185,7 +186,6 @@ through this component to all of its child elements in the DOM.
在这个例子中,我们以所有的`<h3>`元素为目标,从宿主元素到当前元素再到 DOM 中的所有子元素:
<code-example path="component-styles/src/app/hero-details.component.css" region="deep" title="src/app/hero-details.component.css" linenums="false">
</code-example>
@ -204,7 +204,6 @@ Emulated is the default and most commonly used view encapsulation. For more info
这种方式是默认值,也是用得最多的方式。
更多信息,见[控制视图封装模式](guide/component-styles#view-encapsulation)一节。
</div>
<div class="alert is-important">
@ -258,6 +257,7 @@ Each string in the array defines some CSS for this component.
这个数组中的每一个字符串(通常也只有一个)定义一份 CSS。
<code-example path="component-styles/src/app/hero-app.component.ts" title="src/app/hero-app.component.ts (CSS inline)">
</code-example>
<div class="alert is-critical">
@ -275,7 +275,9 @@ The CLI defines an empty `styles` array when you create the component with the `
当使用 `--inline-styles` 标识创建组件时CLI 就会定义一个空的 `styles` 数组
<code-example language="sh" class="code-shell">
ng generate component hero-app --inline-style
</code-example>
### Style files in component metadata
@ -288,8 +290,11 @@ to a component's `@Component` decorator:
我们可以通过把外部 CSS 文件添加到 `@Component``styleUrls` 属性中来加载外部样式。
<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.css" path="component-styles/src/app/hero-app.component.css"></code-pane>
</code-tabs>
<div class="alert is-critical">
@ -313,7 +318,9 @@ They are _not inherited_ by any components nested within the template nor by any
The CLI creates an empty styles file for you by default and references that file in the component's generated `styleUrls`.
<code-example language="sh" class="code-shell">
ng generate component hero-app
</code-example>
### Template inline styles
@ -325,8 +332,8 @@ inside `<style>` tags.
我们也可以在组件的 HTML 模板中嵌入`<style>`标签。
<code-example path="component-styles/src/app/hero-controls.component.ts" region="inlinestyles" title="src/app/hero-controls.component.ts">
</code-example>
### Template link tags
@ -336,6 +343,7 @@ You can also write `<link>` tags into the component's HTML template.
我们也可以在组件的 HTML 模板中写`<link>`标签。
<code-example path="component-styles/src/app/hero-team.component.ts" region="stylelink" title="src/app/hero-team.component.ts">
</code-example>
<div class="alert is-critical">
@ -358,13 +366,12 @@ on the [MDN](https://developer.mozilla.org) site.
我们还可以利用标准的 CSS [`@import`规则](https://developer.mozilla.org/en/docs/Web/CSS/@import)来把其它
CSS 文件导入到我们的 CSS 文件中。
In this case, the URL is relative to the CSS file into which you're importing.
在*这种*情况下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>
### External and global style files
@ -381,12 +388,14 @@ If you're building with the CLI,
you can write style files in [sass](http://sass-lang.com/), [less](http://lesscss.org/), or [stylus](http://stylus-lang.com/) and specify those files in the `@Component.styleUrls` metadata with the appropriate extensions (`.scss`, `.less`, `.styl`) as in the following example:
<code-example>
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
...
</code-example>
The CLI build process runs the pertinent CSS preprocessor.
@ -449,8 +458,8 @@ To set the components encapsulation mode, use the `encapsulation` property in th
通过组件元数据中的`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>
`Native` view encapsulation only works on browsers that have native support
@ -462,7 +471,6 @@ in most cases.
原生(`Native`)模式只适用于[有原生 Shadow DOM 支持的浏览器](http://caniuse.com/#feat=shadowdom)。
因此仍然受到很多限制,这就是为什么我们会把仿真 (`Emulated`) 模式作为默认选项,并建议将其用于大多数情况。
{@a inspect-generated-css}
## Inspecting generated CSS
@ -480,8 +488,8 @@ attached to it:
当我们查看启用了仿真模式的 Angular 应用时,我们看到每个 DOM 元素都被加上了一些额外的属性。
<code-example format="">
&lt;hero-details _nghost-pmm-5>
&lt;h2 _ngcontent-pmm-5>Mister Fantastic&lt;/h2>
&lt;hero-team _ngcontent-pmm-5 _nghost-pmm-6>
@ -513,8 +521,8 @@ by the generated component styles, which are in the `<head>` section of the DOM:
这些属性的具体值并不重要。它们是自动生成的,并且我们永远不会在程序代码中直接引用到它们。
但它们会作为生成的组件样式的目标,就像我们在 DOM 的`<head>`区所看到的:
<code-example format="">
[_nghost-pmm-5] {
display: block;
border: 1px solid black;
@ -524,11 +532,13 @@ by the generated component styles, which are in the `<head>` section of the DOM:
background-color: white;
border: 1px solid #777;
}
</code-example>
These styles are post-processed so that each selector is augmented
with `_nghost` or `_ngcontent` attribute selectors.
These extra selectors enable the scoping rules described in this page.
这些就是我们写的那些样式被处理后的结果,于是每个选择器都被增加了`_nghost``_ngcontent`属性选择器。
在这些附加选择器的帮助下,我们实现了本指南中所描述的这些作用域规则。

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@ To understand why dependency injection is so important, consider an example with
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>
The `Car` class creates everything it needs inside its constructor.
@ -69,9 +70,11 @@ That's super easy. Change the `Car` constructor to a version with DI:
<code-tabs>
<code-pane title="src/app/car/car.ts (excerpt with DI)" path="dependency-injection/src/app/car/car.ts" region="car-ctor">
</code-pane>
<code-pane title="src/app/car/car.ts (excerpt without DI)" path="dependency-injection/src/app/car/car-no-di.ts" region="car-ctor">
</code-pane>
</code-tabs>
@ -91,6 +94,7 @@ parameters and properties simultaneously.
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>
How cool is that?
@ -121,6 +125,7 @@ You can pass mocks to the constructor that do exactly what you want them to do
during each test:
<code-example path="dependency-injection/src/app/car/car-creations.ts" region="car-ctor-instantiation-with-mocks" linenums="false">
</code-example>
**You just learned what dependency injection is**.
@ -137,6 +142,7 @@ You need something that takes care of assembling these parts.
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>
It's not so bad now with only three creation methods.
@ -154,6 +160,7 @@ You register some classes with this injector, and it figures out how to create t
When you need a `Car`, you simply ask the injector to get it for you and you're good to go.
<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>
Everyone wins. The `Car` knows nothing about creating an `Engine` or `Tires`.

View File

@ -16,17 +16,22 @@ Start by reviewing this simplified version of the _heroes_ feature
from the [The Tour of Heroes](tutorial/).
<code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="dependency-injection/src/app/heroes/heroes.component.1.ts"
region="v1">
</code-pane>
<code-pane title="src/app/heroes/hero-list.component.ts" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane>
<code-pane title="src/app/heroes/hero.ts" path="dependency-injection/src/app/heroes/hero.ts">
</code-pane>
<code-pane title="src/app/heroes/mock-heroes.ts" path="dependency-injection/src/app/heroes/mock-heroes.ts">
</code-pane>
</code-tabs>
@ -40,6 +45,7 @@ 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"
region="class">
</code-example>
That may suffice in the early stages of development, but it's far from ideal.
@ -55,12 +61,15 @@ It's better to hide these details inside a _service_ class,
The [**Angular CLI**](https://cli.angular.io/) can generate a new `HeroService` class in the `src/app/heroes` folder with this command.
<code-example language="sh" class="code-shell">
ng generate service heroes/hero
</code-example>
That command creates the following `HeroService` skeleton.
<code-example path="dependency-injection/src/app/heroes/hero.service.0.ts" title="src/app/heroes/hero.service.ts (CLI-generated)">
</code-example>
Assume for now that the [`@Injectable` decorator](#injectable) is an essential ingredient in every Angular service definition.
@ -68,6 +77,7 @@ The rest of the class has been rewritten to expose a `getHeroes` method
that returns the same mock data as before.
<code-example path="dependency-injection/src/app/heroes/hero.service.1.ts" title="src/app/heroes/hero.service.ts">
</code-example>
Of course, this isn't a real data service.
@ -77,7 +87,6 @@ the `getHeroes` method signature would have to be asynchronous.
That's a defect we can safely ignore in this guide where our focus is on
_injecting the service_ into the `HeroList` component.
{@a injector-config}
{@a bootstrap}
@ -123,6 +132,7 @@ Here's a revised `HeroesComponent` that registers the `HeroService` in its `prov
下面是修改过的`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>
{@a register-providers-ngmodule}
@ -132,6 +142,7 @@ Here's a revised `HeroesComponent` that registers the `HeroService` in its `prov
In the following excerpt, the root `AppModule` registers two providers in its `providers` array.
<code-example path="dependency-injection/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers">
</code-example>
The first entry registers the `UserService` class (_not shown_) under the `UserService` _injection token_.
@ -143,8 +154,8 @@ into any class that it creates.
<div class="l-sub-section">
You'll learn about _injection tokens_ and _provider_ syntax [below](#providers).
</div>
</div>
{@a ngmodule-vs-comp}
@ -181,8 +192,7 @@ Note that a component-provided service may have a limited lifetime. Each new ins
and, when the component instance is destroyed, so is that service instance.
In this sample app, the `HeroComponent` is created when the application starts
and is never destroyed so the `HeroService` created for the `HeroComponent` also live for
the life of the app.
and is never destroyed so the `HeroService` created for the `HeroComponent` also live for the life of the app.
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.
@ -205,17 +215,22 @@ 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"
region="ctor-signature">
</code-example>
Of course, the `HeroListComponent` should do something with the injected `HeroService`.
Here's the revised component, making use of the injected service, side-by-side with the previous version for comparison.
<code-tabs>
<code-pane title="hero-list.component (with DI)" path="dependency-injection/src/app/heroes/hero-list.component.2.ts">
</code-pane>
<code-pane title="hero-list.component (without DI)" path="dependency-injection/src/app/heroes/hero-list.component.1.ts">
</code-pane>
</code-tabs>
Notice that the `HeroListComponent` doesn't know where the `HeroService` comes from.
@ -280,8 +295,8 @@ under test:
例如,新建的`HeroListComponent`实例使用一个模拟 (mock) 服务,以便可以在测试中操纵它:
<code-example path="dependency-injection/src/app/test.component.ts" region="spec" title="src/app/test.component.ts" linenums="false">
</code-example>
<div class="l-sub-section">
@ -314,9 +329,11 @@ Here is the revised `HeroService` that injects the `Logger`, side-by-side with t
<code-tabs>
<code-pane title="src/app/heroes/hero.service (v2)" path="dependency-injection/src/app/heroes/hero.service.2.ts">
</code-pane>
<code-pane title="src/app/heroes/hero.service (v1)" path="dependency-injection/src/app/heroes/hero.service.1.ts">
</code-pane>
</code-tabs>
@ -327,7 +344,6 @@ The `getHeroes()` method logs a message when asked to fetch heroes.
这个构造函数要求注入一个`Logger`类的实例,并把它存到名为`logger`的私有字段中。
当请求英雄数据时,`getHeroes()`中就会记录一个消息。
{@a logger-service}
#### The dependent _Logger_ service
@ -335,6 +351,7 @@ The `getHeroes()` method logs a message when asked to fetch heroes.
The sample app's `Logger` service is quite simple:
<code-example path="dependency-injection/src/app/logger.service.ts" title="src/app/logger.service.ts">
</code-example>
If the app didn't provide this `Logger`,
@ -342,17 +359,18 @@ Angular would throw an exception when it looked for a `Logger` to inject
into the `HeroService`.
<code-example language="sh" class="code-shell">
ERROR Error: No provider for Logger!
</code-example>
Because a singleton logger service is useful everywhere,
it's provided in the root `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>
{@a injectable}
## _@Injectable()_
@ -379,6 +397,7 @@ While _any_ decorator will do,
the `@Injectable()` decorator is the standard decorator for service classes.
<div class="l-sub-section">
The decorator requirement is imposed by TypeScript.
TypeScript normally discards parameter type information when it _transpiles_ the code to JavaScript.
@ -427,6 +446,7 @@ The `Logger` class itself is an obvious and natural provider.
`Logger`类本身是一个显而易见而且自然而然的提供商。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger">
</code-example>
But it's not the only way.
@ -456,16 +476,17 @@ What matters is that the injector has a provider to go to when it needs a `Logge
Here's the class-provider syntax again.
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-logger">
</code-example>
This is actually a shorthand expression for a provider registration
using a _provider_ object literal with two properties:
这其实是用于注册提供商的简写表达式。
使用的是一个带有两个属性的_提供商_对象字面量
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-3" >
</code-example>
The `provide` property holds the [token](guide/dependency-injection#token) that serves as the key for both locating a dependency value
@ -491,11 +512,11 @@ Occasionally you'll ask a different class to provide the service.
The following code tells the injector
to return a `BetterLogger` when something asks for the `Logger`.
某些时候,我们会请求一个不同的类来提供服务。
下列代码告诉注入器,当有人请求`Logger`时,返回`BetterLogger`
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-4" >
</code-example>
{@a class-provider-dependencies}
@ -513,6 +534,7 @@ which is also injected at the application level.
`UserService`通常也会在应用级注入。
<code-example path="dependency-injection/src/app/providers.component.ts" region="EvenBetterLogger" linenums="false">
</code-example>
Configure it like `BetterLogger`.
@ -520,6 +542,7 @@ Configure it like `BetterLogger`.
就像之前在`BetterLogger`中那样配置它。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-5" linenums="false">
</code-example>
{@a aliased-class-providers}
@ -551,19 +574,19 @@ The `OldLogger` should be an alias for `NewLogger`.
You certainly do not want two different `NewLogger` instances in your app.
Unfortunately, that's what you get if you try to alias `OldLogger` to `NewLogger` with `useClass`.
我们当然不会希望应用中有两个不同的`NewLogger`实例。
不幸的是,如果尝试通过`useClass`来把`OldLogger`作为`NewLogger`的别名,就会导致这样的后果。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6a" linenums="false">
</code-example>
The solution: alias with the `useExisting` option.
解决方案:使用`useExisting`选项指定别名。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-6b" linenums="false">
</code-example>
{@a value-provider}
@ -572,13 +595,12 @@ The solution: alias with the `useExisting` option.
### 值提供商
Sometimes it's easier to provide a ready-made object rather than ask the injector to create it from a class.
有时,提供一个预先做好的对象会比请求注入器从类中创建它更容易。
<code-example path="dependency-injection/src/app/providers.component.ts" region="silent-logger" linenums="false">
</code-example>
Then you register a provider with the `useValue` option,
@ -586,8 +608,8 @@ which makes this object play the logger role.
于是可以通过`useValue`选项来注册提供商,它会让这个对象直接扮演 logger 的角色。
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-7" linenums="false">
</code-example>
See more `useValue` examples in the
@ -641,13 +663,12 @@ who is authorized and who is not.
`EvenBetterLogger`不同,不能把`UserService`注入到`HeroService`中。
`HeroService`无权访问用户信息,来决定谁有授权谁没有授权。
Instead, the `HeroService` constructor takes a boolean flag to control display of secret heroes.
`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>
You can inject the `Logger`, but you can't inject the boolean `isAuthorized`.
@ -660,8 +681,8 @@ 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>
Although the `HeroService` has no access to the `UserService`, the factory function does.
@ -673,8 +694,8 @@ and let the injector pass them along to the factory function:
同时把`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>
<div class="l-sub-section">
@ -692,7 +713,6 @@ The injector resolves these tokens and injects the corresponding services into t
`Logger``UserService`类作为它们自身类提供商的令牌。
注入器解析这些令牌,把相应的服务注入到工厂函数中相应的参数中去。
</div>
Notice that you captured the factory provider in an exported variable, `heroServiceProvider`.
@ -711,13 +731,14 @@ Here you see the new and the old implementation side-by-side:
这里,它代替了元数据`providers`数组中原来的`HeroService`注册。
对比一下新的和旧的实现:
<code-tabs>
<code-pane title="src/app/heroes/heroes.component (v3)" path="dependency-injection/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane title="src/app/heroes/heroes.component (v2)" path="dependency-injection/src/app/heroes/heroes.component.1.ts">
</code-pane>
</code-tabs>
@ -743,8 +764,8 @@ Here you get a `HeroService` directly from the injector by supplying the `HeroSe
在前面的所有例子中,依赖值都是一个类*实例*,并且类的*类型*作为它自己的查找键值。
在下面的代码中,`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>
You have similar good fortune when you write a constructor that requires an injected class-based dependency.
@ -756,15 +777,14 @@ service associated with that `HeroService` class token:
只要定义一个`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>
This is especially convenient when you consider that most dependency values are provided by classes.
这是一个特殊的规约,因为大多数依赖值都是以类的形式提供的。
{@a non-class-dependencies}
### Non-class dependencies
@ -785,6 +805,7 @@ 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>
What if you'd like to make this configuration object available for injection?
@ -792,7 +813,6 @@ You know you can register an object with a [value provider](guide/dependency-inj
我们想让这个配置对象在注入时可用,而且知道可以使用[值提供商](guide/dependency-injection#value-provider)来注册一个对象。
But what should you use as the token?
You don't have a class to serve as a token.
There is no `AppConfig` class.
@ -800,7 +820,6 @@ There is no `AppConfig` class.
但是,这种情况下用什么作令牌呢?
我们没办法找一个类来当作令牌,因为没有`Config`类。
<div class="l-sub-section">
### TypeScript interfaces aren't valid tokens
@ -812,11 +831,12 @@ Unfortunately, you cannot use a TypeScript interface as a token:
`CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9-interface" linenums="false">
</code-example>
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-9-ctor-interface" linenums="false">
</code-example>
That seems strange if you're used to dependency injection in strongly typed languages, where
@ -833,7 +853,6 @@ There is no interface type information left for Angular to find at runtime.
TypeScript 接口不会出现在生成的 JavaScript 代码中。
在运行期,没有接口类型信息可供 Angular 查找。
</div>
{@a injection-token}
@ -849,8 +868,8 @@ The definition of such a token looks like this:
解决方案是为非类依赖定义和使用<a href="../api/core/InjectionToken"><b>InjectionToken</b></a>作为提供商令牌。
定义方式是这样的:
<code-example path="dependency-injection/src/app/app.config.ts" region="token" title="src/app/app.config.ts" linenums="false">
</code-example>
The type parameter, while optional, conveys the dependency's type to developers and tooling.
@ -861,10 +880,10 @@ The token description is another developer aid.
Register the dependency provider using the `InjectionToken` object:
使用这个`InjectionToken`对象注册依赖的提供商:
<code-example path="dependency-injection/src/app/providers.component.ts" region="providers-9" linenums="false">
</code-example>
Now you can inject the configuration object into any constructor that needs it, with
@ -872,8 +891,8 @@ the help of an `@Inject` decorator:
现在,在`@Inject`装饰器的帮助下,这个配置对象可以注入到任何需要它的构造函数中:
<code-example path="dependency-injection/src/app/app.component.2.ts" region="ctor" title="src/app/app.component.ts" linenums="false">
</code-example>
<div class="l-sub-section">
@ -883,7 +902,6 @@ it supports typing of the configuration object within the class.
虽然`AppConfig`接口在依赖注入过程中没有任何作用,但它为该类中的配置对象提供了强类型信息。
</div>
Alternatively, you can provide and inject the configuration object in an ngModule like `AppModule`.
@ -892,7 +910,6 @@ Alternatively, you can provide and inject the configuration object in an ngModul
<code-example path="dependency-injection/src/app/app.module.ts" region="providers" title="src/app/app.module.ts (providers)"></code-example>
{@a optional}
## Optional dependencies
@ -907,11 +924,12 @@ constructor argument with `@Optional()`:
`HeroService`*需要*一个`Logger`,但是如果想不提供 Logger 也能得到它,该怎么办呢?
可以把构造函数的参数标记为`@Optional()`,告诉 Angular 该依赖是可选的:
<code-example path="dependency-injection/src/app/providers.component.ts" region="import-optional">
</code-example>
<code-example path="dependency-injection/src/app/providers.component.ts" region="provider-10-ctor" linenums="false">
</code-example>
When using `@Optional()`, your code must be prepared for a null value. If you
@ -923,7 +941,7 @@ value of `logger` to null.
## Summary
##
##
You learned the basics of Angular dependency injection in this page.
You can register various kinds of providers,
@ -953,8 +971,8 @@ here's an `InjectorComponent` that does.
这里的`InjectorComponent`直接使用了注入器,
但我们很少直接使用它。
<code-example path="dependency-injection/src/app/injector.component.ts" region="injector" title="src/app/injector.component.ts">
</code-example>
An `Injector` is itself an injectable service.
@ -980,11 +998,8 @@ is not found. Angular can't find the service if it's not registered with this or
调用`get()`时,还可以使用第二个参数,一旦获取的服务没有在当前或任何祖先注入器中注册过,
就把它作为返回值。
<div class="l-sub-section">
The technique is an example of the
[service locator pattern](https://en.wikipedia.org/wiki/Service_locator_pattern).
@ -1009,7 +1024,6 @@ must acquire services generically and dynamically.
框架开发人员必须采用通用的或者动态的方式获取服务时,可能采用这个方法。
</div>
{@a one-class-per-file}
@ -1035,7 +1049,6 @@ you'll get a runtime null reference error.
如果把组件定义在了服务的前面,
在运行时抛出空指针错误。
<div class="l-sub-section">
You actually can define the component first with the help of the `forwardRef()` method as explained

View File

@ -22,9 +22,10 @@ For the simplest deployment, build for development and copy the output directory
使用开发环境进行构建
<code-example language="none" class="code-shell">
ng build
</code-example>
ng build
</code-example>
2. Copy _everything_ within the output folder (`dist/` by default) to a folder on the server.
@ -40,7 +41,9 @@ For the simplest deployment, build for development and copy the output directory
比如,如果 `index.html` 位于服务器上的 `/my/app/index.html` 路径下,就要把 *base href* 设置为 `<base href="/my/app/">`,就像这样:
<code-example language="none" class="code-shell">
ng build --base-href=/my/app/
</code-example>
You'll see that the `<base href>` is set properly in the generated `dist/index.html`.<br><br>
@ -73,7 +76,9 @@ starting with `--prod`.
### Build with _--prod_
<code-example language="none" class="code-shell">
ng build --prod
</code-example>
The `--prod` _meta-flag_ engages the following optimization features.
@ -109,7 +114,9 @@ The remaining [copy deployment steps](#copy-files) are the same as before.
You may further reduce bundle sizes by adding the `build-optimizer` flag.
<code-example language="none" class="code-shell">
ng build --prod --build-optimizer
</code-example>
See the [CLI Documentation](https://github.com/angular/angular-cli/wiki/build)
@ -126,9 +133,10 @@ console:
Angular应用默认运行在开发模式下正如在浏览器控制台中看到的如下信息
<code-example format="nocode">
Angular is running in the development mode. Call enableProdMode() to enable the production mode.
</code-example>
Switching to _production mode_ can make it run faster by disabling development specific checks such as the dual change detection cycles.
@ -171,7 +179,6 @@ If you do that, the module will be loaded immediately.
我们本打算惰性加载一个模块,但可能无意中在根模块`AppModule`文件中使用一个JavaScript的`import`语句导入了它。
这样一来,该模块就被立即加载了。
The bundling configuration must take lazy loading into consideration.
Because lazy loaded modules aren't imported in JavaScript (as just noted), bundlers exclude them by default.
Bundlers don't know about the router configuration and won't create separate bundles for lazy loaded modules.
@ -213,26 +220,34 @@ tool is a great way to inspect the generated JavaScript bundles after a producti
Install `source-map-explorer`:
<code-example language="none" class="code-shell">
npm install source-map-explorer --save-dev
</code-example>
Build your app for production _including the source maps_
<code-example language="none" class="code-shell">
ng build --prod --sourcemaps
</code-example>
List the generated bundles in the `dist/` folder.
<code-example language="none" class="code-shell">
ls dist/*.bundle.js
</code-example>
Run the explorer to generate a graphical representation of one of the bundles.
The following example displays the graph for the _main_ bundle.
<code-example language="none" class="code-shell">
node_modules/.bin/source-map-explorer dist/main.*.bundle.js
</code-example>
The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
@ -241,7 +256,9 @@ showing exactly which classes are included in the bundle.
Here's the output for the _main_ bundle of the QuickStart.
<figure>
<img src="generated/images/guide/cli-quickstart/quickstart-sourcemap-explorer.png" alt="quickstart sourcemap explorer">
</figure>
{@a base-tag}
@ -296,7 +313,6 @@ The `ng build --watch` command will regenerate output files when source files ch
This `--watch` flag is useful if you're building during development and
are automatically re-deploying changes to another server.
See the [CLI `build` topic](https://github.com/angular/angular-cli/wiki/build) for more details and options.
<hr>
@ -311,7 +327,6 @@ This section covers changes you may have make to the server or to files deployed
这一节涵盖了我们对服务器或准备部署到服务器的文件要做的那些修改。
{@a fallback}
### Routed apps must fallback to `index.html`
@ -330,10 +345,8 @@ to return the application's host page (`index.html`) when asked for a file that
如果该应用使用Angular路由器我们就必须配置服务器让它对不存在的文件返回应用的宿主页(`index.html`)。
{@a deep-link}
A routed application should support "deep links".
A _deep link_ is a URL that specifies a path to a component inside the app.
For example, `http://www.mysite.com/heroes/42` is a _deep link_ to the hero detail page
@ -391,26 +404,27 @@ 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`,代码如下:
<code-example>
historyApiFallback: {
disableDotRule: true,
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
}
</code-example>
</code-example>
#### Production servers
#### 生产服务器
* [Apache](https://httpd.apache.org/): add a
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html)
to the `.htaccess` file as shown
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
[Apache](https://httpd.apache.org/):在`.htaccess`文件中添加一个[重写规则](http://httpd.apache.org/docs/current/mod/mod_rewrite.html)
代码如下([出处](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/)
<code-example format=".">
RewriteEngine On
&#35 If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
@ -419,8 +433,8 @@ to the `.htaccess` file as shown
&#35 If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
</code-example>
</code-example>
* [NGinx](http://nginx.org/): use `try_files`, as described in
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
@ -429,17 +443,18 @@ 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)。
<code-example format=".">
try_files $uri $uri/ /index.html;
</code-example>
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
[here](http://stackoverflow.com/a/26152011/2116927):
[IIS](https://www.iis.net/):往`web.config`中添加一条重写规则,类似于[这里](http://stackoverflow.com/a/26152011/2116927)
<code-example format='.'>
&lt;system.webServer&gt;
&lt;rewrite&gt;
&lt;rules&gt;
@ -457,7 +472,6 @@ modified to serve `index.html`:
</code-example>
* [GitHub Pages](https://pages.github.com/): you can't
[directly configure](https://github.com/isaacs/github/issues/408)
the GitHub Pages server, but you can add a 404 page.
@ -476,10 +490,10 @@ and to
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
[rewrite rule](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=".">
"rewrites": [ {
"source": "**",
"destination": "/index.html"
@ -507,6 +521,7 @@ The server must be configured to accept the application's requests.
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>.
客户端应用对这种错误无能为力。
服务器必须配置成可以接受来自该应用的请求。
要了解如何对特定的服务器开启CORS参见<a href="http://enable-cors.org/server.html" target="_blank" title="Enabling CORS server">enable-cors.org</a>

View File

@ -17,24 +17,21 @@ The final UI looks like this:
最终的用户界面是这样的:
<figure>
<img src="generated/images/guide/displaying-data/final.png" alt="Final UI">
</figure>
<div class="l-sub-section">
The <live-example></live-example> demonstrates all of the syntax and code
snippets described in this page.
这个<live-example></live-example>演示了本章中描述的所有语法和代码片段。
</div>
{@a interpolation}
## Showing component properties with interpolation
@ -66,13 +63,10 @@ When you're done, it should look like this:
修改完之后,它应该是这样的:
<code-example path="displaying-data/src/app/app.component.1.ts" title="src/app/app.component.ts">
</code-example>
You added two properties to the formerly empty component: `title` and `myHero`.
再把两个属性`title``myHero`添加到之前空白的组件中。
@ -82,17 +76,12 @@ interpolation:
修改完的模板会使用双花括号形式的插值表达式来显示这两个模板属性:
<code-example path="displaying-data/src/app/app.component.1.ts" linenums="false" title="src/app/app.component.ts (template)" region="template">
</code-example>
<div class="l-sub-section">
The template is a multi-line string within ECMAScript 2015 backticks (<code>\`</code>).
The backtick (<code>\`</code>)&mdash;which is *not* the same character as a single
quote (`'`)&mdash;allows you to compose a string over several lines, which makes the
@ -102,32 +91,23 @@ HTML more readable.
反引号 (<code>\`</code>) &mdash; 注意,不是单引号 (') &mdash; 允许把一个字符串写在多行上,
使 HTML 模板更容易阅读。
</div>
Angular automatically pulls the value of the `title` and `myHero` properties from the component and
inserts those values into the browser. Angular updates the display
when these properties change.
Angular 自动从组件中提取`title``myHero`属性的值并且把这些值插入浏览器中。当这些属性发生变化时Angular 就会自动刷新显示。
<div class="l-sub-section">
More precisely, the redisplay occurs after some kind of asynchronous event related to
the view, such as a keystroke, a timer completion, or a response to an HTTP request.
严格来说,“重新显示”是在某些与视图有关的异步事件之后发生的,例如,按键、定时器完成或对 HTTP 请求的响应。
</div>
Notice that you don't call **new** to create an instance of the `AppComponent` class.
Angular is creating an instance for you. How?
@ -139,13 +119,10 @@ That element is a placeholder in the body of your `index.html` file:
注意`@Component`装饰器中指定的 CSS 选择器`selector`,它指定了一个叫`my-app`的元素。
该元素是`index.html``body`里的占位符。
<code-example path="displaying-data/src/index.html" linenums="false" title="src/index.html (body)" region="body">
</code-example>
When you bootstrap with the `AppComponent` class (in <code>main.ts</code>), Angular looks for a `<app-root>`
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
inside the `<app-root>` tag.
@ -157,18 +134,16 @@ Now run the app. It should display the title and hero name:
运行应用。它应该显示出标题和英雄名:
<figure>
<img src="generated/images/guide/displaying-data/title-and-hero.png" alt="Title and Hero">
</figure>
The next few sections review some of the coding choices in the app.
回顾一下前面所做的决定,看看还有哪些其它选择。
## Template inline or template file?
## 内联 (inline) 模板还是模板文件?
@ -202,12 +177,13 @@ In either style, the template data bindings have the same access to the componen
默认情况下Angular CLI 生成组件时会带有模板文件,我们可以通过参数覆盖它:
<code-example hideCopy language="sh" class="code-shell">
ng generate component hero -it
</code-example>
</div>
## Constructor or variable initialization?
## 使用构造函数还是变量初始化?
@ -216,18 +192,14 @@ Although this example uses variable assignment to initialize the components, you
虽然这个例子使用了变量赋值的方式初始化组件,你还可以使用构造函数来声明和初始化属性。
<code-example path="displaying-data/src/app/app-ctor.component.ts" linenums="false" region="class">
</code-example>
This app uses more terse "variable assignment" style simply for brevity.
为了让本应用更加简短,它采用了更简单的“变量赋值”风格。
{@a ngFor}
## Showing an array property with ***ngFor**
@ -238,25 +210,19 @@ To display a list of heroes, begin by adding an array of hero names to the compo
要显示一个英雄列表,先向组件中添加一个英雄名字数组,然后把`myHero`重定义为数组中的第一个名字。
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (class)" region="class">
</code-example>
Now use the Angular `ngFor` directive in the template to display
each item in the `heroes` list.
接着,在模板中使用 Angular 的`ngFor`指令来显示`heroes`列表中的每一项。
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (template)" region="template">
</code-example>
This UI uses the HTML unordered list with `<ul>` and `<li>` tags. The `*ngFor`
in the `<li>` element is the Angular "repeater" directive.
It marks that `<li>` element (and its children) as the "repeater template":
@ -264,28 +230,20 @@ It marks that `<li>` element (and its children) as the "repeater template":
这个界面使用了由`<ul>``<li>`标签组成的无序列表。`<li>`元素里的`*ngFor`是 Angular 的“迭代”指令。
它将`<li>`元素及其子级标记为“迭代模板”:
<code-example path="displaying-data/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (li)" region="li">
</code-example>
<div class="alert is-important">
Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax.
For more information, see the [Template Syntax](guide/template-syntax#ngFor) page.
不要忘记`*ngFor`中的前导星号 (\*)。它是语法中不可或缺的一部分。
更多信息,见[模板语法](guide/template-syntax#ngFor)。
</div>
Notice the `hero` in the `ngFor` double-quoted instruction;
it is an example of a template input variable. Read
more about template input variables in the [microsyntax](guide/template-syntax#microsyntax) section of
@ -302,34 +260,26 @@ context for the interpolation in the double curly braces.
Angular 为列表中的每个条目复制一个`<li>`元素,在每个迭代中,把`hero`变量设置为当前条目(英雄)。
Angular 把`hero`变量作为双花括号插值表达式的上下文。
<div class="l-sub-section">
In this case, `ngFor` is displaying an array, but `ngFor` can
repeat items for any [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) object.
本例中,`ngFor`用于显示一个“数组”,
`ngFor`可以为任何[可迭代的 (iterable) ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)对象重复渲染条目。
</div>
Now the heroes appear in an unordered list.
现在,英雄们出现在了一个无序列表中。
<figure>
<img src="generated/images/guide/displaying-data/hero-names-list.png" alt="ngfor之后">
<img src="generated/images/guide/displaying-data/hero-names-list.png" alt="After ngfor">
</figure>
## Creating a class for the data
## 为数据创建一个类
@ -351,7 +301,9 @@ of hero names into an array of `Hero` objects. For that you'll need a `Hero` cla
要将此绑定转换成使用对象,需要把这个英雄名字数组变成`Hero`对象数组。但首先得有一个`Hero`类。
<code-example language="sh" class="code-shell">
ng generate class hero
</code-example>
With the following code:
@ -362,8 +314,6 @@ With the following code:
</code-example>
You've defined a class with a constructor and two properties: `id` and `name`.
你定义了一个类,具有一个构造函数和两个属性:`id``name`
@ -377,30 +327,25 @@ Consider the first parameter:
来看第一个参数:
<code-example path="displaying-data/src/app/hero.ts" linenums="false" title="src/app/hero.ts (id)" region="id">
</code-example>
That brief syntax does a lot:
这个简写语法做了很多:
* Declares a constructor parameter and its type
* Declares a constructor parameter and its type.
声明了一个构造函数参数及其类型
声明了一个构造函数参数及其类型
* Declares a public property of the same name
* Declares a public property of the same name.
声明了一个同名的公共属性
* Initializes that property with the corresponding argument when we "new" an instance of the class
当我们`new`出该类的一个实例时,把该属性初始化为相应的参数值
声明了一个同名的公共属性。
* Initializes that property with the corresponding argument when creating an instance of the class.
当我们`new`出该类的一个实例时,把该属性初始化为相应的参数值。
### Using the Hero class
@ -411,13 +356,10 @@ of `Hero` objects:
导入了`Hero`类之后,组件的`heroes`属性就可以返回一个*类型化的*`Hero`对象数组了。
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (heroes)" region="heroes">
</code-example>
Next, update the template.
At the moment it displays the hero's `id` and `name`.
Fix that to display only the hero's `name` property.
@ -426,16 +368,13 @@ Fix that to display only the hero's `name` property.
现在它显示的是英雄的`id``name`
要修复它,只显示英雄的`name`属性就行了。
<code-example path="displaying-data/src/app/app.component.3.ts" linenums="false" title="src/app/app.component.ts (template)" region="template">
</code-example>
The display looks the same, but the code is clearer.
Our display looks the same, but now we know much better what a hero really is.
从显示上看还是一样,但现在我们知道了更多英雄信息。
显示上还和以前一样,不过代码更清晰了。
{@a ngIf}
@ -457,28 +396,20 @@ To see it in action, add the following paragraph at the bottom of the template:
Angular 的`ngIf`指令会根据一个布尔条件来显示或移除一个元素。
来看看实际效果,把下列语句加到模板的底部:
<code-example path="displaying-data/src/app/app.component.ts" linenums="false" title="src/app/app.component.ts (message)" region="message">
</code-example>
<div class="alert is-important">
Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax.
Read more about `ngIf` and `*` in the [ngIf section](guide/template-syntax#ngIf) of the [Template Syntax](guide/template-syntax) page.
不要忘了`*ngIf`中的前导星号 (\*)。它是本语法中不可或缺的一部分。
更多`ngIf``* `的内容,见[模板语法](guide/template-syntax)中的[ngIf](guide/template-syntax#ngIf)。
</div>
The template expression inside the double quotes,
`*ngIf="heroes.length > 3"`, looks and behaves much like TypeScript.
When the component's list of heroes has more than three items, Angular adds the paragraph
@ -491,22 +422,16 @@ see the [template expressions](guide/template-syntax#template-expressions) secti
当组件中的英雄列表有三个以上的条目时Angular 把这个段落添加到 DOM 中,于是消息显示了出来。
更多信息,见[模板语法](guide/template-syntax)中的[模板表达式](guide/template-syntax#template-expressions)。
<div class="alert is-helpful">
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. That improves performance, especially in larger projects when conditionally including or excluding
big chunks of HTML with many data bindings.
Angular 并不是在显示和隐藏这条消息,它是在从 DOM 中添加和移除这个段落元素。
这会提高性能,特别是在一些大的项目中有条件地包含或排除一大堆带着很多数据绑定的 HTML 时。
</div>
Try it out. Because the array has four items, the message should appear.
Go back into <code>app.component.ts"</code> and delete or comment out one of the elements from the hero array.
The browser should refresh automatically and the message should disappear.
@ -515,8 +440,6 @@ The browser should refresh automatically and the message should disappear.
回到`app.component.ts`,从英雄数组中删除或注释掉一个元素。
浏览器应该自动刷新,消息应该会消失。
## Summary
## 小结
@ -545,7 +468,6 @@ Here's the final code:
下面是最终的代码:
<code-tabs>
<code-pane title="src/app/app.component.ts" path="displaying-data/src/app/app.component.ts" region="final">

View File

@ -44,7 +44,6 @@ The reader requests a page by its Page URL. The doc viewer fetches the correspon
Page URLs mirror the `content` file structure. The URL for the page of a guide is in the form `guide/{page-name}`. The page for _this_ "Authors Style Guide" is located at `content/guide/docs-style-guide.md` and its URL is `guide/docs-style-guide`.
<div class="l-sub-section">
_Tutorial_ pages are exactly like guide pages. The only difference is that they reside in `content/tutorial` instead of `content/guide` and have URLs like `tutorial/{page-name}`.
@ -75,11 +74,13 @@ Standard markdown processors don't allow you to put markdown _within_ HTML tags.
</div>
```html
<div class="alert is-critical">
**Always** follow every opening and closing HTML tag with _a blank line_.
</div>
```
<div class="l-sub-section">
@ -96,7 +97,9 @@ The title should appear at the top of the physical page.
Begin the title with the markdown `#` character. Alternatively, you can write the equivalent `<h1>`.
```html
# Authors Style Guide
```
**Only one title (`<h1>`) per document!**
@ -104,7 +107,9 @@ Begin the title with the markdown `#` character. Alternatively, you can write th
Title text should be in "Title Case", which means that you use capital letters to start the first words and all _principal_ words. Use lower case letters for _secondary_ words such as "in", "of", and "the".
```html
# The Meat of the Matter
```
**Always follow the title with at least one blank line.**
@ -118,8 +123,11 @@ All section heading text should be in "Sentence case", which means the first wor
**Always follow the section heading with at least one blank line.**
<h2 class="no-toc">
Main section heading
</h2>
There are usually one or more main sections that may be further divided into secondary sections.
Begin a main section heading with the markdown `##` characters. Alternatively, you can write the equivalent `<h2>` HTML tag.
@ -127,13 +135,16 @@ Begin a main section heading with the markdown `##` characters. Alternatively, y
The main section heading should be followed by a blank line and then the content for that heading.
```html
## Sections
A typical document is divided into sections.
```
<h3 class="no-toc">
Secondary section heading
</h3>
A secondary section heading is related to a main heading and _falls textually within_ the bounds of that main heading.
@ -143,6 +154,7 @@ Begin a secondary heading with the markdown `###` characters. Alternatively, you
The secondary heading should be followed by a blank line and then the content for that heading.
```html
### Secondary section heading
A secondary section ...
@ -155,6 +167,7 @@ Try to minimize the heading depth, preferably only two. But more headings, such
**N.B.**: The [Table-of-contents](#table-of-contents) generator only considers main (`<h2>`) and secondary (`<h3>`) headings.
```html
#### Additional section headings
Try to minimize ...
@ -179,11 +192,13 @@ Here is an example of a subsection `<div>` surrounding the subsection content wr
</div>
```html
<div class="l-sub-section">
You'll learn about styles for live examples in the [section below](guide/docs-style-guide#live-examples "Live examples").
</div>
```
Note that at least one blank line must follow the opening `<div>`. A blank line before the closing `</div>` is customary but not required.
@ -197,21 +212,31 @@ You should not create your own TOC by hand. The TOC is generated automatically f
To exclude a heading from the TOC, create the heading as an `<h2>` or `<h3>` element with a class called 'no-toc'. You can't do this with markdown.
```html
<h3 class="no-toc">
This heading is not displayed in the TOC
</h3>
```
You can turn off TOC generation for the _entire_ page by writing the title with an `<h1>` tag and the `no-toc` class.
```html
<h1 class="no-toc">
A guide without a TOC
</h1>
```
## Navigation
## 导航
The navigation links at the top, left, and bottom of the screen are generated from the JSON configuration file, `content/navigation.json`.
The authority to change the `navigation.json` file is limited to a few core team members.
@ -253,28 +278,24 @@ A navigation node has the following properties:
* `hidden` - defined and set true if this is a guide page that should _not_ be displayed in the navigation panel. Rarely needed, it is a way to hide the page from navigation while making it available to readers who should know about it. _This_ "Authors Style Guide" is a hidden page.
<div class="alert is-critical">
Do not create a node that is both a _header_ and an _item_ node. That is, do not specify the `url` property of a _header_ node.
</div>
<div class="alert is-critical">
The current guidelines allow for a three-level navigation structure with two header levels. Don't add a third header level.
</div>
## Code snippets
Guides are rich in examples of working Angular code. Example code can be commands entered in a terminal window, a fragment of TypeScript or HTML, or an entire code file.
Whatever the source, the doc viewer renders them as "code snippets", either individually with the [_code-example_](#code-example "code-example") component or as a tabbed collection with the [_code-tabs_](#code-tabs "code-tabs") component.
{@a code-example}
### Code example
@ -291,13 +312,19 @@ 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.
<code-example language="sh" class="code-shell">
npm start
</code-example>
```html
<code-example language="sh" class="code-shell">
npm start
</code-example>
```
Inline, hand-coded snippets like this one are _not_ testable and, therefore, are intrinsically unreliable.
@ -344,7 +371,9 @@ Here's the brief markup that produced that lengthy snippet:
<code-example
path="docs-style-guide/src/app/app.module.ts"
title="src/app/app.module.ts">
</code-example>
```
You identified the snippet's source file by setting the `path` attribute to sample folder's location _within_ `content/examples`.
@ -370,9 +399,12 @@ If you want to include an ignored code file in your project and display it in a
The preferred way to un-ignore a file is to update the `content/examples/.gitignore` like this:
<code-example title="content/examples/.gitignore">
# my-guide
!my-guide/src/something.js
!my-guide/more-javascript*.js
</code-example>
</div>
@ -404,17 +436,19 @@ Often you want to focus on a fragment of code within a sample code file. In this
<code-example
path="docs-style-guide/src/app/app.module.ts"
region="class">
</code-example>
First you surround that fragment in the source file with a named _docregion_ as described [below](#source-code-markup).
Then you reference that _docregion_ in the `region` attribute of the `<code-example>` like this
```html
<code-example
path="docs-style-guide/src/app/app.module.ts"
region="class">
</code-example>
```
A couple of observations:
@ -442,13 +476,17 @@ 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"
region="example"
title="app/heroes/hero-button/hero-button.component.ts">
</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>
{@a code-tabs}
### Code Tabs
Code tabs display code much like _code examples_ do. The added advantage is that they can display multiple code samples within a tabbed interface. Each tab is displayed using _code pane_.
@ -460,31 +498,42 @@ Code tabs display code much like _code examples_ do. The added advantage is tha
#### Code-pane attributes
* `path` - a file in the content/examples folder
* `title` - seen in the header of a tab
* `linenums` - overrides the `linenums` property at the `code-tabs` level for this particular pane. The value can be `true`, `false` or a number indicating the starting line number. If not specified, line numbers are enabled only when the number of lines of code are greater than 10.
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.
<code-tabs linenums="false">
<code-pane
title="app.component.html"
path="docs-style-guide/src/app/app.component.html">
</code-pane>
<code-pane
title="app.component.ts"
path="docs-style-guide/src/app/app.component.ts"
linenums="true">
</code-pane>
<code-pane
title="app.component.css (heroes)"
path="docs-style-guide/src/app/app.component.css"
region="heroes">
</code-pane>
<code-pane
title="package.json (scripts)"
path="docs-style-guide/package.1.json">
</code-pane>
</code-tabs>
Here's the markup for that example.
@ -493,26 +542,37 @@ Note how the `linenums` attribute in the `<code-tabs>` explicitly disables numb
The `linenums` attribute in the second pane restores line numbering for _itself only_.
```html
<code-tabs linenums="false">
<code-pane
title="app.component.html"
path="docs-style-guide/src/app/app.component.html">
</code-pane>
<code-pane
title="app.component.ts"
path="docs-style-guide/src/app/app.component.ts"
linenums="true">
</code-pane>
<code-pane
title="app.component.css (heroes)"
path="docs-style-guide/src/app/app.component.css"
region="heroes">
</code-pane>
<code-pane
title="package.json (scripts)"
path="docs-style-guide/package.1.json">
</code-pane>
</code-tabs>
```
{@a source-code-markup}
@ -558,7 +618,6 @@ See [below](#json-files) for details and workarounds.
</div>
#### _#docregion_
The _#docregion_ is the most important kind of code snippet markup.
@ -574,7 +633,9 @@ The `src/main.ts` is a simple example of a file with a single _#docregion_ at th
<code-example
path="docs-style-guide/src/main.ts"
title="src/main.ts"></code-example>
title="src/main.ts">
</code-example>
</div>
@ -594,7 +655,10 @@ Remember to refer to this region by name in the `region` attribute of the `<code
```html
<code-example
path="docs-style-guide/src/app/app.module.ts"
region="class"></code-example>
region="class">
</code-example>
```
The _#docregion_ with no name is the _default region_. Do _not_ set the `region` attribute when referring to the default _#docregion_.
@ -611,6 +675,7 @@ You can nest _#docregions_ within _#docregions_
... yet more code ...
/// #enddocregion
```
<div class="l-sub-section">
The `src/app/app.module.ts` file has a good example of a nested region.
@ -627,6 +692,7 @@ 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.
<code-example linenums="false">
// #docplaster
...
// #docregion class, class-skeleton
@ -642,21 +708,27 @@ export class AppComponent {
// #docregion class-skeleton
}
// #enddocregion class, class-skeleton
</code-example>
Here's are the two corresponding code snippets displayed side-by-side.
<code-tabs>
<code-pane
title="app.component.ts (class)"
path="docs-style-guide/src/app/app.component.ts"
region="class">
</code-pane>
<code-pane
title="app.component.ts (class-skeleton)"
path="docs-style-guide/src/app/app.component.ts"
region="class-skeleton">
</code-pane>
</code-tabs>
Some observations:
@ -686,12 +758,17 @@ Here's an example that excerpts certain scripts from `package.json` into a parti
<code-example
path="docs-style-guide/package.1.json"
title="package.json (selected scripts)"></code-example>
title="package.json (selected scripts)">
</code-example>
```html
<code-example
path="docs-style-guide/package.1.json"
title="package.json (selected scripts)"></code-example>
title="package.json (selected scripts)">
</code-example>
```
#### Partial file naming
@ -715,9 +792,12 @@ Remember to exclude these files from stackblitz by listing them in the `stackbli
<code-example
path="docs-style-guide/stackblitz.json"
title="stackblitz.json"></code-example>
title="stackblitz.json">
</code-example>
{@a live-examples}
## Live examples
By adding `<live-example>` to the page you generate links that run sample code in the Stackblitz live coding environment and download that code to the reader's file system.
@ -744,7 +824,6 @@ Clicking the first link opens the code sample in a new browser tab in the "embed
You can change the appearance and behavior of the live example with attributes and classes.
<h3 class="no-toc">Custom label and tooltip</h3>
Give the live example anchor a custom label and tooltip by setting the `title` attribute.
@ -752,7 +831,9 @@ Give the live example anchor a custom label and tooltip by setting the `title` a
<live-example title="Live Example with title"></live-example>
```html
<live-example title="Live Example with title"></live-example>
```
You can achieve the same effect by putting the label between the `<live-example>` tags:
@ -760,7 +841,9 @@ You can achieve the same effect by putting the label between the `<live-example>
<live-example>Live example with content label</live-example>
```html
<live-example>Live example with content label</live-example>
```
<h3 class="no-toc">Live example from another guide</h3>
@ -770,7 +853,9 @@ To link to a Stackblitz in a folder whose name is not the same as the current gu
<live-example name="router">Live Example from the Router guide</live-example>
```html
<live-example name="router">Live Example from the Router guide</live-example>
```
<h3 class="no-toc">Live Example for named Stackblitz</h3>
@ -780,7 +865,9 @@ To link to a Stackblitz defined by a named `stackblitz.json` file, set the `stac
<live-example stackblitz="second"></live-example>
```html
<live-example stackblitz="second"></live-example>
```
<h3 class="no-toc">Live Example without download</h3>
@ -790,7 +877,9 @@ To skip the download link, add the `noDownload` attribute.
<live-example noDownload>Just the Stackblitz</live-example>
```html
<live-example noDownload>Just the Stackblitz</live-example>
```
<h3 class="no-toc">Live Example with download-only</h3>
@ -800,7 +889,9 @@ To skip the live Stackblitz link and only link to the download, add the `downloa
<live-example downloadOnly>Download only</live-example>
```html
<live-example downloadOnly>Download only</live-example>
```
<h3 class="no-toc">Embedded live example</h3>
@ -816,7 +907,9 @@ Store that image in the `content/images` directory in a folder with a name match
Here's an embedded live example for this guide. It has a custom image created from a snapshot of the running app, overlayed with `content/images/Stackblitz/unused/click-to-run.png`.
```html
<live-example embedded img="guide/docs-style-guide/docs-style-guide-Stackblitz.png"></live-example>
```
<live-example embedded img="guide/docs-style-guide/docs-style-guide-Stackblitz.png"></live-example>
@ -834,11 +927,13 @@ See the ["Anchors"](guide/docs-style-guide#anchors "Style Guide - Anchors") sect
</div>
```html
<div class="l-sub-section">
See the ["Anchors"](guide/docs-style-guide#anchors "Style Guide - Anchors") section for details.
</div>
```
When navigating within the page, you can omit the page URL when specifying the link that [scrolls up](#anchors "Anchors") to the beginning of this section.
@ -865,9 +960,11 @@ 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.
<code-example language="html">
&#123;@a ugly-anchors&#125;
#### Ugly, long section header anchors
</code-example>
Now [link to that custom anchor name](#ugly-anchors) as you did before.
@ -886,6 +983,7 @@ If you do, be sure to set the `id` attribute - not the `name` attribute! The doc
<a id="anchors"></a>
## Anchors
```
</div>
@ -895,31 +993,44 @@ If you do, be sure to set the `id` attribute - not the `name` attribute! The doc
Alerts draw attention to important points. Alerts should not be used for multi-line content (use callouts insteads) or stacked on top of each other. Note that the content of an alert is indented to the right by two spaces.
<div class="alert is-critical">
A critical alert.
</div>
<div class="alert is-important">
An important alert.
</div>
<div class="alert is-helpful">
A helpful, informational alert.
</div>
A helpful, informational alert.
</div>
Here is the markup for these alerts.
```html
<div class="alert is-critical">
A critical alert.
</div>
<div class="alert is-important">
An important alert.
</div>
<div class="alert is-helpful">
A helpful, informational alert.
</div>
```
Alerts are meant to grab the user's attention and should be used sparingly.
@ -930,6 +1041,7 @@ They are not for casual asides or commentary. Use [subsections](#subsections "su
Callouts (like alerts) are meant to draw attention to important points. Use a callout when you want a riveting header and multi-line content.
<div class="callout is-critical">
<header>A critical point</header>
**Pitchfork hoodie semiotics**, roof party pop-up _paleo_ messenger messenger bag cred Carles tousled Truffaut yr. Semiotics viral freegan VHS, Shoreditch disrupt McSweeney's. Intelligentsia kale chips Vice four dollar toast, Schlitz crucifix
@ -937,6 +1049,7 @@ Callouts (like alerts) are meant to draw attention to important points. Use a ca
</div>
<div class="callout is-important">
<header>An important point</header>
**Pitchfork hoodie semiotics**, roof party pop-up _paleo_ messenger bag cred Carles tousled Truffaut yr. Semiotics viral freegan VHS, Shoreditch disrupt McSweeney's. Intelligentsia kale chips Vice four dollar toast, Schlitz crucifix
@ -944,6 +1057,7 @@ Callouts (like alerts) are meant to draw attention to important points. Use a ca
</div>
<div class="callout is-helpful">
<header>A helpful point</header>
**Pitchfork hoodie semiotics**, roof party pop-up _paleo_ messenger bag cred Carles tousled Truffaut yr. Semiotics viral freegan VHS, Shoreditch disrupt McSweeney's. Intelligentsia kale chips Vice four dollar toast, Schlitz crucifix
@ -952,17 +1066,23 @@ Callouts (like alerts) are meant to draw attention to important points. Use a ca
Here is the markup for the first of these callouts.
```html
<div class="callout is-critical">
<header>A critical point</header>
**Pitchfork hoodie semiotics**, roof party pop-up _paleo_ messenger bag cred Carles tousled Truffaut yr. Semiotics viral freegan VHS, Shoreditch disrupt McSweeney's. Intelligentsia kale chips Vice four dollar toast, Schlitz crucifix
</div>
```
Notice that
* the callout header text is forced to all upper case.
* the callout body can be written in markdown.
* a blank line separates the `</header>` tag from the markdown content.
Callouts are meant to grab the user's attention. They are not for casual asides. Please use them sparingly.
@ -974,49 +1094,67 @@ Trees can represent hierarchical data.
<div class='filetree'>
<div class='file'>
sample-dir
</div>
<div class='children'>
<div class='file'>
src
</div>
<div class='children'>
<div class='file'>
app
</div>
<div class='children'>
<div class='file'>
app.component.ts
</div>
<div class='file'>
app.module.ts
</div>
</div>
<div class='file'>
styles.css
</div>
<div class='file'>
tsconfig.json
</div>
</div>
<div class='file'>
node_modules ...
</div>
<div class='file'>
package.json
</div>
</div>
@ -1026,123 +1164,207 @@ Trees can represent hierarchical data.
Here is the markup for this file tree.
```html
<div class='filetree'>
<div class='file'>
sample-dir
</div>
<div class='children'>
<div class='file'>
src
</div>
<div class='children'>
<div class='file'>
app
</div>
<div class='children'>
<div class='file'>
app.component.ts
</div>
<div class='file'>
app.module.ts
</div>
</div>
<div class='file'>
styles.css
</div>
<div class='file'>
tsconfig.json
</div>
</div>
<div class='file'>
node_modules ...
</div>
<div class='file'>
package.json
</div>
</div>
</div>
```
<div class='filetree'>
<div class='file'>
sample-dir
</div>
<div class='children'>
<div class='file'>
src
</div>
<div class='children'>
<div class='file'>
app
</div>
<div class='children'>
<div class='file'>
app.component.ts
</div>
<div class='file'>
app.module.ts
</div>
</div>
<div class='file'>
styles.css
</div>
<div class='file'>
tsconfig.json
</div>
</div>
<div class='file'>
node_modules ...
</div>
<div class='file'>
package.json
</div>
</div>
</div>
```
## Tables
Use HTML tables to present tabular data.
<style>
td, th {vertical-align: top}
</style>
<table>
<tr>
<th>Framework</th>
<th>Task</th>
<th>Speed</th>
</tr>
<tr>
<td><code>AngularJS</code></td>
<td>Routing</td>
<td>Fast</td>
</tr>
<tr>
<td><code>Angular v2</code></td>
<td>Routing</td>
<!-- can use markdown too; remember blank lines -->
<td>
*Faster*
</td>
</tr>
<tr>
<td><code>Angular v4</code></td>
<td>Routing</td>
<td>
**Fastest :)**
</td>
</tr>
</table>
Here is the markup for this table.
```html
<style>
td, th {vertical-align: top}
</style>
<table>
<tr>
<th>Framework</th>
<th>Task</th>
<th>Speed</th>
</tr>
<tr>
<td><code>AngularJS</code></td>
<td>Routing</td>
<td>Fast</td>
</tr>
<tr>
<td><code>Angular v2</code></td>
<td>Routing</td>
<!-- can use markdown too; remember blank lines -->
<td>
*Faster*
</td>
</tr>
<tr>
<td><code>Angular v4</code></td>
<td>Routing</td>
<td>
**Fastest :)**
</td>
</tr>
</table>
```
## Images
@ -1173,14 +1395,20 @@ You should nest the `<img>` tag within a `<figure>` tag, which styles the image
Here's a conforming example
<figure>
<img src="generated/images/guide/docs-style-guide/flying-hero.png" alt="flying hero">
</figure>
```html
<figure>
<img src="generated/images/guide/docs-style-guide/flying-hero.png"
alt="flying hero">
</figure>
```
_Note that the HTML image element does not have a closing tag._
@ -1192,16 +1420,21 @@ The doc generator reads the image dimensions from the file and adds width and he
Here's the "flying hero" at a more reasonable scale.
<figure>
<img src="generated/images/guide/docs-style-guide/flying-hero.png" alt="flying Angular hero" width="200">
</figure>
```html
<figure>
<img src="generated/images/guide/docs-style-guide/flying-hero.png"
alt="flying Angular hero"
width="200">
</figure>
```
Wide images can be a problem. Most browsers try to rescale the image but wide images may overflow the document in certain viewports.
@ -1209,9 +1442,13 @@ Wide images can be a problem. Most browsers try to rescale the image but wide im
**Do not set a width greater than 700px**. If you wish to display a larger image, provide a link to the actual image that the user can click on to see the full size image separately as in this example of `source-map-explorer` output from the "Ahead-of-time Compilation" guide:
<a href="generated/images/guide/docs-style-guide/toh-pt6-bundle.png" title="Click to view larger image">
<figure>
<img src="generated/images/guide/docs-style-guide/toh-pt6-bundle-700w.png" alt="toh-pt6-bundle" width="300px">
</figure>
</a>
<h3 class="no-toc">Image compression</h3>
@ -1247,6 +1484,7 @@ This text wraps around to the right of the floating "flying hero" image.
Headings and code-examples automatically clear a floating image. If you need to force a piece of text to clear a floating image, add `<br class="clear">` where the text should break.
<br class="clear">
```
Note that you generally don't wrap a floating image in a `<figure>` element.
@ -1267,6 +1505,7 @@ If you have a floating image inside an alert, callout, or a subsection, it is a
</div>
```html
<div class="l-sub-section clear-fix">
<img src="generated/images/guide/docs-style-guide/flying-hero.png"
@ -1277,4 +1516,5 @@ If you have a floating image inside an alert, callout, or a subsection, it is a
A subsection with **markdown** formatted text.
</div>
```

View File

@ -13,7 +13,7 @@ This cookbook shows you how to use `ComponentFactoryResolver` to add components
See the <live-example name="dynamic-component-loader"></live-example>
of the code in this cookbook.
<live-example name="cb-dynamic-component-loader"></live-example>查看本烹饪书的源码。
<live-example name="dynamic-component-loader"></live-example>查看本烹饪书的源码。
{@a dynamic-loading}
@ -42,7 +42,6 @@ Angular comes with its own API for loading components dynamically.
Angular 自带的API就能支持动态加载组件。
{@a directive}
## The anchor directive
@ -59,13 +58,10 @@ mark valid insertion points in the template.
广告条使用一个名叫`AdDirective`的辅助指令来在模板中标记出有效的插入点。
<code-example path="dynamic-component-loader/src/app/ad.directive.ts" title="src/app/ad.directive.ts" linenums="false">
</code-example>
`AdDirective` injects `ViewContainerRef` to gain access to the view
container of the element that will host the dynamically added component.
@ -99,22 +95,17 @@ where to dynamically load components.
要应用`AdDirective`,回忆一下来自`ad.directive.ts`的选择器`ad-host`。把它应用到`<ng-template>`(不用带方括号)。
这下Angular就知道该把组件动态加载到哪里了。
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" title="src/app/ad-banner.component.ts (template)" linenums="false">
</code-example>
The `<ng-template>` element is a good choice for dynamic components
because it doesn't render any additional output.
`<ng-template>`元素是动态加载组件的最佳选择,因为它不会渲染任何额外的输出。
{@a resolving-components}
## Resolving components
## 解析组件
@ -142,24 +133,18 @@ and loads a new component every 3 seconds by calling `loadComponent()`.
通过`getAds()`方法,`AdBannerComponent`可以循环遍历`AdItems`的数组,并且每三秒调用一次`loadComponent()`来加载新组件。
<code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" title="src/app/ad-banner.component.ts (excerpt)" linenums="false">
</code-example>
The `loadComponent()` method is doing a lot of the heavy lifting here.
Take it step by step. First, it picks an ad.
这里的`loadComponent()`方法很重要。
我们来一步步看看。首先,它选取了一个广告。
<div class="l-sub-section">
**How _loadComponent()_ chooses an ad**
**`loadComponent()`如何选择广告**
@ -176,11 +161,8 @@ value to select an `adItem` from the array.
(译注:循环选取算法)首先,它把`currentAddIndex`递增一,然后用它除以`AdItem`数组长度的*余数*作为新的`currentAddIndex`的值,
最后用这个值来从数组中选取一个`adItem`
</div>
After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver`
to resolve a `ComponentFactory` for each specific component.
The `ComponentFactory` then creates an instance of each component.
@ -212,10 +194,8 @@ Use that reference to interact with the component by assigning to its properties
`createComponent()`方法返回一个引用,指向这个刚刚加载的组件。
使用这个引用就可以与该组件进行交互,比如设置它的属性或调用它的方法。
{@a selector-references}
#### Selector references
#### 对选择器的引用
@ -233,16 +213,12 @@ add dynamically loaded components to the `NgModule`'s `entryComponents` array:
要想确保编译器照常生成工厂类,就要把这些动态加载的组件添加到`NgModule``entryComponents`数组中:
<code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" title="src/app/app.module.ts (entry components)" linenums="false">
</code-example>
{@a common-interface}
## The _AdComponent_ interface
## 公共的`AdComponent`接口
@ -256,7 +232,6 @@ Here are two sample components and the `AdComponent` interface for reference:
下面就是两个范例组件及其`AdComponent`接口:
<code-tabs>
<code-pane title="hero-job-ad.component.ts" path="dynamic-component-loader/src/app/hero-job-ad.component.ts">
@ -273,11 +248,8 @@ Here are two sample components and the `AdComponent` interface for reference:
</code-tabs>
{@a final-ad-baner}
## Final ad banner
## 最终的广告栏
@ -286,13 +258,13 @@ The final ad banner looks like this:
最终的广告栏是这样的:
<figure>
<img src="generated/images/guide/dynamic-component-loader/ads.gif" alt="Ads">
</figure>
See the <live-example name="dynamic-component-loader"></live-example>.
参见<live-example name="cb-dynamic-component-loader"></live-example>

View File

@ -10,7 +10,8 @@ to meet rapidly changing business and regulatory requirements.
有时候手动编写和维护表单所需工作量和时间会过大。特别是在需要编写大量表单时。表单都很相似,而且随着业务和监管需求的迅速变化,表单也要随之变化,这样维护的成本过高。
It may be more economical to create the forms dynamically, based on metadata that describes the business object model.
It may be more economical to create the forms dynamically, based on
metadata that describes the business object model.
基于业务对象模型的元数据,动态创建表单可能会更划算。
@ -36,12 +37,11 @@ See the <live-example name="dynamic-form"></live-example>.
参见<live-example name="dynamic-form"></live-example>
{@a bootstrap}
## Bootstrap
## 程序启动
## 启动/引导 (bootstrap)
Start by creating an `NgModule` called `AppModule`.
@ -61,7 +61,6 @@ Bootstrap the `AppModule` in `main.ts`.
我们在`main.ts`中启动`AppModule`
<code-tabs>
<code-pane title="app.module.ts" path="dynamic-form/src/app/app.module.ts">
@ -74,7 +73,6 @@ Bootstrap the `AppModule` in `main.ts`.
</code-tabs>
{@a object-model}
## Question model
@ -91,13 +89,10 @@ The following `QuestionBase` is a fundamental question class.
下面是我们建立的最基础的问卷问题基类,名叫`QuestionBase`
<code-example path="dynamic-form/src/app/question-base.ts" title="src/app/question-base.ts">
</code-example>
From this base you can derive two new classes in `TextboxQuestion` and `DropdownQuestion`
that represent textbox and dropdown questions.
The idea is that the form will be bound to specific question types and render the
@ -110,24 +105,18 @@ via the `type` property.
`TextboxQuestion`可以通过`type`属性来支持多种HTML5元素类型比如文本、邮件、网址等。
<code-example path="dynamic-form/src/app/question-textbox.ts" title="src/app/question-textbox.ts" linenums="false">
</code-example>
`DropdownQuestion` presents a list of choices in a select box.
`DropdownQuestion`表示一个带可选项列表的选择框。
<code-example path="dynamic-form/src/app/question-dropdown.ts" title="src/app/question-dropdown.ts" linenums="false">
</code-example>
Next is `QuestionControlService`, a simple service for transforming the questions to a `FormGroup`.
In a nutshell, the form group consumes the metadata from the question model and
allows you to specify default values and validation rules.
@ -135,8 +124,6 @@ allows you to specify default values and validation rules.
接下来,我们定义了`QuestionControlService`,一个可以把问卷问题转换为`FormGroup`的服务。
简而言之,这个`FormGroup`使用问卷模型的元数据,并允许我们设置默认值和验证规则。
<code-example path="dynamic-form/src/app/question-control.service.ts" title="src/app/question-control.service.ts" linenums="false">
</code-example>
@ -152,12 +139,10 @@ to create components to represent the dynamic form.
现在我们已经有一个定义好的完整模型了,接着就可以开始创建一个展现动态表单的组件。
`DynamicFormComponent` is the entry point and the main container for the form.
`DynamicFormComponent`是表单的主要容器和入口点。
<code-tabs>
<code-pane title="dynamic-form.component.html" path="dynamic-form/src/app/dynamic-form.component.html">
@ -170,8 +155,6 @@ to create components to represent the dynamic form.
</code-tabs>
It presents a list of questions, each bound to a `<app-question>` component element.
The `<app-question>` tag matches the `DynamicFormQuestionComponent`,
the component responsible for rendering the details of each _individual_
@ -180,7 +163,6 @@ question based on values in the data-bound question object.
它代表了问卷问题列表,每个问题都被绑定到一个`<df-question>`组件元素。
`<df-question>`标签匹配到的是组件`DynamicFormQuestionComponent`,该组件的职责是根据各个问卷问题对象的值来动态渲染表单控件。
<code-tabs>
<code-pane title="dynamic-form-question.component.html" path="dynamic-form/src/app/dynamic-form-question.component.html">
@ -193,8 +175,6 @@ question based on values in the data-bound question object.
</code-tabs>
Notice this component can present any type of question in your model.
You only have two types of questions at this point but you can imagine many more.
The `ngSwitch` determines which type of question to display.
@ -211,13 +191,13 @@ underlying control objects, populated from the question model with display and v
directly since you imported `ReactiveFormsModule` from `AppModule`.
`formControlName``formGroup`是在`ReactiveFormsModule`中定义的指令。我们之所以能在模板中使用它们,是因为我们往`AppModule`中导入了`ReactiveFormsModule`
{@a questionnaire-data}
## Questionnaire data
## 问卷数据
`DynamicFormComponent` expects the list of questions in the form of an array bound to `@Input() questions`.
`DynamicForm`期望得到一个问题列表,该列表被绑定到`@Input() questions`属性。
@ -235,18 +215,14 @@ directly since you imported `ReactiveFormsModule` from `AppModule`.
关键是,我们完全根据`QuestionService`返回的对象来控制英雄的工作申请表。
要维护这份问卷,只要非常简单的添加、更新和删除`questions`数组中的对象就可以了。
<code-example path="dynamic-form/src/app/question.service.ts" title="src/app/question.service.ts">
</code-example>
Finally, display an instance of the form in the `AppComponent` shell.
最后,在`AppComponent`里显示出表单。
<code-example path="dynamic-form/src/app/app.component.ts" title="app.component.ts">
</code-example>
@ -280,18 +256,17 @@ Saving and retrieving the data is an exercise for another time.
表单验证通过之前,*保存*按钮是禁用的。验证通过后,就可以点击*保存*按钮程序会把当前值渲染成JSON显示出来。
这表明任何用户输入都被传到了数据模型里。至于如何储存和提取数据则是另一话题了。
The final form looks like this:
完整的表单是这样的:
<figure>
<img src="generated/images/guide/dynamic-form/dynamic-form.png" alt="Dynamic-Form">
</figure>
[Back to top](guide/dynamic-form#top)
[回到顶部](guide/dynamic-form#top)

View File

@ -2,7 +2,12 @@
#### Prerequisites:
#### 前提条件:
A basic understanding of the following concepts:
对下列概念有基本的理解:
* [Bootstrapping](guide/bootstrapping).
<hr />
@ -15,16 +20,14 @@ To contrast the two types of components, there are components which are included
</div>
There are two main kinds of entry components:
* The bootstrapped root component.
* A component you specify in a route definition.
## A bootstrapped entry component
The following is an example of specifying a bootstrapped component,
`AppComponent`, in a basic `app.module.ts`:
@ -58,12 +61,10 @@ it should generate code to bootstrap the application with this component.
</div>
A bootstrapped component is necessarily an entry component because bootstrapping is an imperative process, thus it needs to have an entry component.
## A routed entry component
The second kind of entry component occurs in a route definition like
this:
@ -80,7 +81,6 @@ A route definition refers to a component by its type with `component: CustomerLi
All router components must be entry components. Because this would require you to add the component in two places (router and `entryComponents`) the Compiler is smart enough to recognize that this is a router definition and automatically add the router component into `entryComponents`.
## The `entryComponents` array
Though the `@NgModule` decorator has an `entryComponents` array, most of the time
@ -101,13 +101,16 @@ If a component isn't an _entry component_ and isn't found in a template,
the tree shaker will throw it away. So, it's best to add only the components that are truly entry components to help keep your app
as trim as possible.
<hr />
## More on Angular modules
You may also be interested in the following:
* [Types of NgModules](guide/module-types)
* [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules).
* [Providers](guide/providers).
* [NgModules FAQ](guide/ngmodule-faq).

View File

@ -3,9 +3,13 @@
Feature modules are NgModules for the purpose of organizing code.
#### Prerequisites
A basic understanding of the following:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app with a feature module that this page describes,
@ -20,7 +24,6 @@ separate from other code. Delineating areas of your
app helps with collaboration between developers and teams, separating
directives, and managing the size of the root module.
## Feature modules vs. root modules
A feature module is an organizational best practice, as opposed to a concept of the core Angular API. A feature module delivers a cohesive set of functionality focused on a
@ -43,7 +46,6 @@ ng generate module CustomerDashboard
```
This causes the CLI to create a folder called `customer-dashboard` with a file inside called `customer-dashboard.module.ts` with the following contents:
```typescript
@ -71,12 +73,10 @@ ng generate component customer-dashboard/CustomerDashboard
This generates a folder for the new component within the customer-dashboard folder and updates the feature module with the `CustomerDashboardComponent` info:
<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>
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.
## Importing a feature module
@ -84,38 +84,37 @@ The `CustomerDashboardComponent` is now in the JavaScript import list at the top
To incorporate the feature module into your app, you have to let the root module, `app.module.ts`, know about it. Notice the `CustomerDashboardModule` export at the bottom of `customer-dashboard.module.ts`. This exposes it so that other modules can get to it. To import it into the `AppModule`, add it to the imports in `app.module.ts` and to the `imports` array:
<code-example path="feature-modules/src/app/app.module.ts" region="app-module" title="src/app/app.module.ts" linenums="false">
</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.
## Rendering a feature modules component template
When the CLI generated the `CustomerDashboardComponent` for the feature module, it included a template, `customer-dashboard.component.html`, with the following markup:
<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`:
<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>
Next, in the `AppComponent`, `app.component.html`, add the tag `<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>
</code-example>
Now, in addition to the title that renders by default, the `CustomerDashboardComponent` template renders too:
<figure>
<img src="generated/images/guide/feature-modules/feature-module.png" alt="feature module component">
</figure>
<hr />
@ -123,6 +122,9 @@ Now, in addition to the title that renders by default, the `CustomerDashboardCom
## More on NgModules
You may also be interested in the following:
* [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules).
* [Providers](guide/providers).
* [Types of Feature Modules](guide/module-types).

View File

@ -2,9 +2,6 @@
# 表单验证
Improve overall data quality by validating user input for accuracy and completeness.
我们可以通过验证用户输入的准确性和完整性,来增强整体数据质量。
@ -15,7 +12,6 @@ forms modules.
在本烹饪书中,我们展示在界面中如何验证用户输入,并显示有用的验证信息,先使用模板驱动表单方式,再使用响应式表单方式。
<div class="l-sub-section">
If you're new to forms, start by reviewing the [Forms](guide/forms) and
@ -23,10 +19,8 @@ If you're new to forms, start by reviewing the [Forms](guide/forms) and
参见[表单](guide/forms)和[响应式表单](guide/reactive-forms)了解关于这些选择的更多知识。
</div>
## Template-driven validation
## 模板驱动验证
@ -53,7 +47,6 @@ The following example exports `NgModel` into a variable called `name`:
</code-example>
Note the following:
请注意以下几点:
@ -82,13 +75,10 @@ There are messages for `required`, `minlength`, and `forbiddenName`.
<div class="l-sub-section">
#### Why check _dirty_ and _touched_?
#### 为何检查**dirty**和**touched**
You may not want your application to display errors before the user has a chance to edit the form.
The checks for `dirty` and `touched` prevent errors from showing until the user
does one of two things: changes the value,
@ -150,6 +140,7 @@ built-in validators&mdash;this time, in function form. See below:
{@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>
Note that:
@ -173,12 +164,12 @@ for the template.
这个例子添加了一些getter方法。在响应式表单中我们通常会通过它所属的控件组FormGroup`get`方法来访问表单控件但有时候为模板定义一些getter作为简短形式。
If you look at the template for the name input again, it is fairly similar to the template-driven example.
如果我们到模板中找到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>
Key takeaways:
@ -210,6 +201,7 @@ this guide. Here's what the definition of that function looks like:
考虑前面的[例子](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>
The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name and returns a validator function.
@ -249,6 +241,7 @@ to the `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>
### Adding to template-driven forms
@ -269,8 +262,8 @@ with the `NG_VALIDATORS` provider, a provider with an extensible collection of v
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>
The directive class then implements the `Validator` interface, so that it can easily integrate
@ -280,6 +273,7 @@ comes together:
然后该指令类实现了`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>
Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector, `appForbiddenName`, to any input element to activate it. For example:
@ -290,7 +284,6 @@ Once the `ForbiddenValidatorDirective` is ready, you can simply add its selector
</code-example>
<div class="l-sub-section">
You may have noticed that the custom validation directive is instantiated with `useExisting`
@ -313,11 +306,17 @@ Like in AngularJS, Angular automatically mirrors many control properties onto th
像 AngularJS 中一样Angular 会自动把很多控件属性作为 CSS 类映射到控件所在的元素上。我们可以使用这些类来根据表单状态给表单控件元素添加样式。目前支持下列类:
* `.ng-valid`
* `.ng-invalid`
* `.ng-pending`
* `.ng-pristine`
* `.ng-dirty`
* `.ng-untouched`
* `.ng-touched`
The hero form uses the `.ng-valid` and `.ng-invalid` classes to
@ -329,7 +328,7 @@ set the color of each form control's border.
</code-example>
**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.**
**你可以运行<live-example></live-example>来查看完整的响应式和模板驱动表单的代码。**

View File

@ -49,13 +49,13 @@ 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.
你可以在Plunker中运行<live-example></live-example>,并且从那里下载代码。
运行<live-example></live-example>来试用本页的代码。
{@a template-driven}
## Template-driven forms
## 模板驱动表单
## 模板驱动表单 (template-driven forms)
You can build forms by writing templates in the Angular [template syntax](guide/template-syntax) with
the form-specific directives and techniques described in this page.
@ -1209,7 +1209,7 @@ When you click the *Edit* button, this block disappears and the editable form re
## Summary
##
##
The Angular form discussed in this page takes advantage of the following
framework features to provide support for data modification, validation, and more:

View File

@ -4,7 +4,6 @@
A basic understanding of [Bootstrapping](guide/bootstrapping).
<hr>
An Angular app needs at least one module that serves as the root module.
@ -12,57 +11,88 @@ As you add features to your app, you can add them in modules.
The following are frequently used Angular modules with examples
of some of the things they contain:
<table>
<tr>
<th style="vertical-align: top">
NgModule
</th>
<th style="vertical-align: top">
Import it from
</th>
<th style="vertical-align: top">
Why you use it
</th>
</tr>
<tr>
<td><code>BrowserModule</code></td>
<td><code>@angular/platform-browser</code></td>
<td>When you want to run your app in a browser</td>
</tr>
<tr>
<td><code>CommonModule</code></td>
<td><code>@angular/common</code></td>
<td>When you want to use <code>NgIf</code>, <code>NgFor</code></td>
</tr>
<tr>
<td><code>FormsModule</code></td>
<td><code>@angular/forms</code></td>
<td>When you build template driven forms (includes <code>NgModel</code>)</td>
</tr>
<tr>
<td><code>ReactiveFormsModule</code></td>
<td><code>@angular/forms</code></td>
<td>When building reactive forms</td>
</tr>
<tr>
<td><code>RouterModule</code></td>
<td><code>@angular/router</code></td>
<td>For Routing and when you want to use <code>RouterLink</code>,<code>.forRoot()</code>, and <code>.forChild()</code></td>
</tr>
<tr>
<td><code>HttpClientModule</code></td>
<td><code>@angular/common/http</code></td>
<td>When you to talk to a server</td>
</tr>
</table>
@ -75,7 +105,6 @@ or your feature module as appropriate, and list them in the `@NgModule`
`BrowserModule` is the first import at the top of the `AppModule`,
`app.module.ts`.
```typescript
/* import modules so that AppModule can access them */
import { BrowserModule } from '@angular/platform-browser';
@ -100,7 +129,6 @@ The imports at the top of the array are JavaScript import statements
while the `imports` array within `@NgModule` is Angular specific.
For more information on the difference, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
## `BrowserModule` and `CommonModule`
`BrowserModule` imports `CommonModule`, which contributes many common
@ -119,15 +147,19 @@ If you do import `BrowserModule` into a lazy loaded feature module,
Angular returns an error telling you to use `CommonModule` instead.
<figure>
<img src="generated/images/guide/frequent-ngmodules/browser-module-error.gif" width=750 alt="BrowserModule error">
</figure>
<hr />
## More on NgModules
You may also be interested in the following:
* [Bootstrapping](guide/bootstrapping).
* [NgModules](guide/ngmodules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).

View File

@ -22,7 +22,6 @@ unexpected definitions.
{@a A}
{@a aot}
## Ahead-of-time (AOT) compilation
## 预 (ahead-of-time, AoT) 编译
@ -36,8 +35,6 @@ Ahead-of-time compiled applications also benefit from decreased load time and in
意味着不再需要把 Angular 编译器添加到 JavaScript 包中。
预编译的应用程序加载迅速,具有更高的性能。
## Annotation
## 注解
@ -46,13 +43,10 @@ In practice, a synonym for [Decoration](guide/glossary#decorator).
实际上,是[装饰 (decoration)](guide/glossary#decorator) 的同义词。
{@a attribute-directive}
{@a attribute-directives}
## Attribute directives
## 属性型指令
@ -71,7 +65,6 @@ Learn about them in the [_Attribute Directives_](guide/attribute-directives) gui
要了解更多信息,请参见[_属性型指令_](guide/attribute-directives)页。
{@a B}
## Barrel
@ -88,8 +81,8 @@ For example, imagine three ES2015 modules in a `heroes` folder:
例如,设想在`heroes`目录下有三个 ES2015 模块:
<code-example>
// heroes/hero.component.ts
export class HeroComponent {}
@ -98,65 +91,55 @@ For example, imagine three ES2015 modules in a `heroes` folder:
// heroes/hero.service.ts
export class HeroService {}
</code-example>
Without a barrel, a consumer needs three import statements:
如果没有封装桶,消费者需要三条导入语句:
<code-example>
import { HeroComponent } from '../heroes/hero.component.ts';
import { Hero } from '../heroes/hero.model.ts';
import { HeroService } from '../heroes/hero.service.ts';
</code-example>
You can add a barrel to the `heroes` folder (called `index`, by convention) that exports all of these items:
`heroes`目录下添加一个封装桶(按约定叫做`index`),它导出所有这三项:
<code-example>
export * from './hero.model.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
</code-example>
Now a consumer can import what it needs from the barrel.
现在,消费者就就可以从这个封装桶中导入它需要的东西了。
<code-example>
import { Hero, HeroService } from '../heroes'; // index is implied
</code-example>
The Angular [scoped packages](guide/glossary#scoped-package) each have a barrel named `index`.
Angular 的每个[范围化包 (scoped package)](guide/glossary#scoped-package) 都有一个名为`index`的封装桶。
<div class="alert is-important">
You can often achieve the same result using [NgModules](guide/glossary#ngmodule) instead.
注意,你可以利用 [Angular 模块](guide/glossary#ngmodule)达到同样的目的。
</div>
## Binding
## 绑定 (binding)
@ -173,7 +156,6 @@ between a "token"&mdash;also referred to as a "key"&mdash;and a dependency [prov
之间的[依赖注入 (dependency injection)](guide/glossary#dependency-injection) 绑定。
这种用法很少,而且一般都会在上下文中写清楚。
## Bootstrap
## 启动/引导 (bootstrap)
@ -191,7 +173,6 @@ You can bootstrap multiple apps in the same `index.html`, each app with its own
你可以在同一个`index.html`中引导多个应用,每个应用都有它自己的顶级根组件。
{@a C}
## camelCase
@ -213,7 +194,6 @@ In Angular documentation, "camelCase" always means *lower camel case*.
这种形式也叫做**小写驼峰式命名法 (lower camel case)**,以区分于**大写驼峰式命名法**,也称 [Pascal 命名法 (PascalCase)](guide/glossary#pascalcase)。
在文档中提到“驼峰式命名法 (camelCase) ”的时候,我们所指的都是小驼峰命名法。
## CLI
The Angular CLI is a `command line interface` tool that can create a project, add files, and perform a variety of ongoing development tasks such as testing, bundling, and deployment.
@ -222,7 +202,6 @@ Learn more in the [Getting Started](guide/quickstart) guide.
{@a component}
## Component
## 组件 (component)
@ -268,7 +247,6 @@ spelled in dash-case.
[指令](guide/glossary#directive)的选择器(例如`my-app`)和文件名(例如`hero-list.component.ts`)通常是用中线命名法来命名。
## Data binding
## 数据绑定 (data binding)
@ -296,40 +274,38 @@ Angular 有一个非常强大的数据绑定框架,具有各种数据绑定操
更多的绑定形式,见[模板语法](guide/template-syntax)
* [Interpolation](guide/template-syntax#interpolation)
* [Interpolation](guide/template-syntax#interpolation).
[插值表达式 (interpolation)](guide/template-syntax#interpolation)
[插值表达式 (interpolation)](guide/template-syntax#interpolation)
* [Property binding](guide/template-syntax#property-binding)
* [Property binding](guide/template-syntax#property-binding).
[property 绑定 (property binding)](guide/template-syntax#property-binding)
[property 绑定 (property binding)](guide/template-syntax#property-binding)
* [Event binding](guide/template-syntax#event-binding)
* [Event binding](guide/template-syntax#event-binding).
[事件绑定 (event binding)](guide/template-syntax#event-binding)
[事件绑定 (event binding)](guide/template-syntax#event-binding)
* [Attribute binding](guide/template-syntax#attribute-binding)
* [Attribute binding](guide/template-syntax#attribute-binding).
[attribute 绑定 (attribute binding)](guide/template-syntax#attribute-binding)
[attribute 绑定 (attribute binding)](guide/template-syntax#attribute-binding)
* [Class binding](guide/template-syntax#class-binding)
* [Class binding](guide/template-syntax#class-binding).
[CSS 类绑定 (class binding)](guide/template-syntax#class-binding)
[CSS 类绑定 (class binding)](guide/template-syntax#class-binding)
* [Style binding](guide/template-syntax#style-binding)
* [Style binding](guide/template-syntax#style-binding).
[样式绑定 (style binding)](guide/template-syntax#style-binding)
[样式绑定 (style binding)](guide/template-syntax#style-binding)
* [Two-way data binding with ngModel](guide/template-syntax#ngModel)
* [Two-way data binding with ngModel](guide/template-syntax#ngModel).
[基于 ngModel 的双向数据绑定 (Two-way data binding with ngModel)](guide/template-syntax#ngModel)
[基于 ngModel 的双向数据绑定 (Two-way data binding with ngModel)](guide/template-syntax#ngModel)
{@a decorator}
{@a decoration}
## Decorator | decoration
## 装饰器decorator | decoration
@ -356,7 +332,8 @@ Angular 使用自己的一套装饰器来实现应用程序各部件之间的相
并将`@Input`装饰器来应用到组件的`name`属性。
`@Component`装饰器中省略的参数对象会包含与组件有关的元数据。
```@Component({...})
```
@Component({...})
export class AppComponent {
constructor(@Inject('SpecialFoo') public foo:Foo) {}
@Input() name:string;
@ -370,19 +347,14 @@ classes that follow it in the file.
装饰器的作用域会被限制在它所装饰的语言特性。
在同一文件中,装饰器不会“泄露”到它后面的其它类。
<div class="alert is-important">
Always include parentheses `()` when applying a decorator.
永远别忘了在装饰器后面加括号`()`
</div>
## Dependency injection
## 依赖注入dependency injection
@ -414,7 +386,6 @@ for us and handle all the dependencies.
If "A" needs "B" and "B" needs "C," the system resolves that chain of dependencies
and returns a fully prepared instance of "A."
可以要求“依赖注入系统”为我们创建 “A” 并处理所有依赖。如果 “A” 需要 “B” “B” 需要 “C ”,
系统将解析这个依赖链,返回一个完全准备好的 “A” 实例。
@ -473,13 +444,10 @@ Read more in the [Dependency Injection](guide/dependency-injection) page.
更多信息,参见[依赖注入 (dependency injection)](guide/dependency-injection)。
{@a directive}
{@a directives}
## Directive
## 指令 (directive)
@ -492,12 +460,14 @@ in the browser DOM. The directive is Angular's most fundamental feature.
A directive is usually associated with an HTML element or attribute.
This element or attribute is often referred to as the directive itself.
指令几乎总与 HTML 元素或属性 (attribute) 相关。
我们通常把这些关联到的 HTML 元素或者属性 (attribute) 当做指令本身。
When Angular finds a directive in an HTML template,
it creates the matching directive class instance
and gives the instance control over that portion of the browser DOM.
指令几乎总与 HTML 元素或属性 (attribute) 相关。
我们通常把这些关联到的 HTML 元素或者属性 (attribute) 当做指令本身。
当 Angular 在 HTML 模板中遇到一个指令的时候,
它会创建匹配的指令类的实例,并把浏览器中这部分 DOM 的控制权交给它。
@ -565,14 +535,13 @@ Angular developers can write in ES5 directly.
Angular 的开发人员也可以选择直接使用 ES5 编程。
## ES2015
## ES2015 语言
Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
[ECMAScript](guide/glossary#ecmascript) 2015 的写。
[ECMAScript](guide/glossary#ecmascript) 2015 的写。
## ES5
@ -592,10 +561,8 @@ Short hand for [ECMAScript](guide/glossary#ecmascript) 2015.
{@a F}
{@a G}
{@a H}
{@a I}
@ -625,8 +592,7 @@ in the template expression to the right of the equal sign.
See the [Input and output properties](guide/template-syntax#inputs-outputs) section of the [Template Syntax](guide/template-syntax) page.
见[模板语法](guide/template-syntax)中的[输入与输出属性](guide/template-syntax#inputs-outputs)。
参见[模板语法](guide/template-syntax)中的[输入与输出属性](guide/template-syntax#inputs-outputs)部分。
## Interpolation
@ -641,25 +607,21 @@ or displayed between element tags, as in this example.
[属性数据绑定 (property data binding)](guide/glossary#data-binding) 的一种形式,位于双大括号中的[模板表达式 (template expression)](guide/glossary#template-expression)会被渲染成文本。
在被赋值给元素属性或者显示在元素标签中之前,这些文本可能会先与周边的文本合并,参见下面的例子。
<code-example language="html" escape="html">
<label>My current hero is {{hero.name}}</label>
</code-example>
Read more about [interpolation](guide/template-syntax#interpolation) in the
[Template Syntax](guide/template-syntax) page.
更多信息,见[模板语法](guide/template-syntax)中的[插值表达式](guide/template-syntax#interpolation)。
{@a J}
{@a jit}
## Just-in-time (JIT) compilation
## 即时 (just-in-time, JiT) 编译
@ -671,7 +633,6 @@ Consider using the [ahead-of-time](guide/glossary#aot) mode for production apps.
Angular 的即时编译在浏览器中启动并编译所有的组件和模块,动态运行应用程序。
它很适合在开发过程中使用。但是在产品发布时,推荐采用[预编译 (ahead-of-time)](guide/glossary#aot) 模式。
{@a K}
## kebab-case
@ -682,12 +643,11 @@ See [dash-case](guide/glossary#dash-case).
见[中线命名法 (dash-case)](guide/glossary#dash-case)。
{@a L}
## Lifecycle hooks
## 生命周期钩子 (lifecycle hook)
## 生命周期钩子
[Directives](guide/glossary#directive) and [components](guide/glossary#component) have a lifecycle
managed by Angular as it creates, updates, and destroys them.
@ -752,7 +712,6 @@ Read more in the [Lifecycle Hooks](guide/lifecycle-hooks) page.
<div class="alert is-important">
Angular has the following types of modules:
Angular有下列模块类型
@ -766,10 +725,12 @@ For details and examples, see the [NgModules](guide/ngmodules) page.
ES2015模块如本节所述。
For a comparison, see [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
要对比这两个概念,请参见[JavaScript 模块 vs. NgModules](guide/ngmodule-vs-jsmodule)。
</div>
A cohesive block of code dedicated to a single purpose.
模块是一个内聚的代码块,具有单一用途。
@ -814,16 +775,10 @@ You rarely access Angular feature modules directly. You usually import them from
你很少需要直接访问 Angular 的特性模块。
而通常会从一个 Angular [范围化包 (scoped package)](guide/glossary#scoped-package)中导入它们,例如`@angular/core`
{@a N}
## NgModule
<div class="l-sub-section">
Helps you organize an application into cohesive blocks of functionality.
An NgModule identifies the components, directives, and pipes that the application uses along with the list of external NgModules that the application needs, such as `FormsModule`.
@ -833,9 +788,6 @@ called `AppModule` and resides in a file named `app.module.ts`.
For details and examples, see [NgModules](guide/ngmodules) and the
related files in that section.
{@a O}
## Observable
@ -856,7 +808,6 @@ Observables are a proposed feature for ES 2016, the next version of JavaScript.
为了使用`Observable` Angular 采用了名为 Reactive Extensions (RxJS) 的第三方包。
在下个版本的 JavaScript - ES 2016 中,`Observable`是建议的特性之一。
## Output
## 输出属性 (output)
@ -874,7 +825,6 @@ See the [Input and output properties](guide/template-syntax#inputs-outputs) sect
参见[模板语法](guide/template-syntax)中的[输入与输出属性](guide/template-syntax#inputs-outputs)部分。
{@a P}
## PascalCase
@ -893,7 +843,6 @@ In this documentation, "PascalCase" means *upper camel case* and "camelCase" me
这种形式也称**大写驼峰式命名法**,以区别于**小写驼峰式命名法”或[驼峰式命名法 (camelCase)](guide/glossary#camelcase)** 。
在本文档中“Pascal 命名法”都是指的*大写驼峰式命名法*,“驼峰式命名法”指的都是*小写驼峰式命名法*。
## Pipe
## 管道 (pipe)
@ -906,21 +855,18 @@ a numeric value in the local currency.
Angular 管道是一个函数,用于把输入值转换成输出值以供[视图 (view)](guide/glossary#view)显示。
下面这个例子中,用内置的`currency`管道把数字值显示为本地货币格式。
<code-example language="html" escape="html">
<label>Price: </label>{{product.price | currency}}
</code-example>
You can also write your own custom pipes.
Read more in the page on [pipes](guide/pipes).
我们还可以写自己的自定义管道。
更多信息,见[管道](guide/pipes)。
## Provider
## 提供商 (provider)
@ -932,7 +878,6 @@ It relates a lookup token to code&mdash;sometimes called a "recipe"&mdash;that c
依赖注入系统依靠提供商来创建依赖的实例。
它把一个查找令牌和代码(有时也叫“配方”)关联到一起,以便创建依赖值。
{@a Q}
{@a R}
@ -971,7 +916,6 @@ Reactive forms are powerful, flexible, and a good choice for more complex data-e
动态表单非常强大、灵活,它在复杂数据输入的场景下尤其好用,例如动态的生成表单控制器。
## Router
## 路由器 (router)
@ -1008,10 +952,9 @@ For more information, see the [Routing & Navigation](guide/router) page.
更多信息,见[路由与导航](guide/router)。
## Router module
<div class="l-sub-section">
## 路由器模块
A separate [NgModule](guide/glossary#ngmodule) that provides the necessary service providers and directives for navigating through application views.
@ -1021,7 +964,6 @@ For more information, see the [Routing & Navigation](guide/router) page.
更多信息,见[路由与导航](guide/router)。
## Routing component
## 路由组件 (routing component)
@ -1034,7 +976,6 @@ For more information, see the [Routing & Navigation](guide/router) page.
更多信息,见[路由与导航](guide/router)。
{@a S}
## Scoped package
@ -1058,12 +999,10 @@ is that the scoped package name begins with the Angular *scope name*, `@angular`
导入范围化包与导入*普通*包方式相同。
从消费者的视角看,唯一的不同是那些包的名字是用 Angular 的*范围化包名*`@angular`开头的。
<code-example path="architecture/src/app/app.component.ts" linenums="false" title="architecture/src/app/app.component.ts (import)" region="import">
</code-example>
## Service
## 服务 (service)
@ -1096,7 +1035,6 @@ For more information, see the [Services](tutorial/toh-pt4) page of the [Tour of
{@a snake-case}
## snake_case
## 蛇形命名法
@ -1106,13 +1044,10 @@ underscore (`_`) separates one word from the next. This form is also known as *u
写复合词或短语的一种方式,在多个词之间用下划线(`_`)分隔。也叫*下划线命名法*
{@a structural-directive}
{@a structural-directives}
## Structural directives
## 结构型指令
@ -1129,7 +1064,6 @@ Read more in the [Structural Directives](guide/structural-directives) page.
更多信息,见[结构型指令](guide/structural-directives)。
{@a T}
## Template
@ -1143,7 +1077,6 @@ most notably a [component](guide/glossary#component).
模板是一大块 HTML。Angular 会在[指令 (directive)](guide/glossary#directive) 特别是[组件 (component)](guide/glossary#component)
的支持和持续指导下,用它来渲染[视图 (view)](guide/glossary#view)。
## Template-driven forms
## 模板驱动表单 (template-driven forms)
@ -1183,7 +1116,6 @@ in the [Forms](guide/forms) page.
要了解如何构建模板驱动表单的更多信息,参见[表单](guide/forms)页。
## Template expression
## 模板表达式 (template expression)
@ -1199,7 +1131,6 @@ of the [Template Syntax](guide/template-syntax) page.
到[模板语法](guide/template-syntax)一章的[模板表达式](guide/template-syntax#template-expressions)部分了解更多模板表达式的知识。
## Transpile
## 转译transpile)
@ -1209,7 +1140,6 @@ The process of transforming code written in one form of JavaScript
把一种形式的 JavaScript例如 TypeScript转换成另一种形式的 JavaScript例如 [ES5](guide/glossary#es5))的过程。
## TypeScript
## TypeScript 语言
@ -1237,7 +1167,6 @@ Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org
更多信息,见[typescript.org](http://www.typescriptlang.org/)。
{@a U}
{@a V}
@ -1267,16 +1196,12 @@ under the control of a [router](guide/glossary#router).
视图一般包含其它视图,在用户在应用程序中导航时,
任何视图都可能被动态加载或卸载,这一般会在[路由器 (router)](guide/glossary#router) 的控制下进行。
{@a W}
{@a X}
{@a Y}
{@a Z}
## Zone
@ -1312,4 +1237,5 @@ Angular 会在一个 Zone 区域中运行应用程序,在这个区域中,它
Learn more about zones in this
[Brian Ford video](https://www.youtube.com/watch?v=3IqtmUscE_U).
更多信息,见 [Brian Ford 的视频](https://www.youtube.com/watch?v=3IqtmUscE_U)。

View File

@ -21,9 +21,7 @@ This guide explores this system and how to use it to your advantage.
Try the <live-example></live-example>.
试试<live-example></live-example>.
试试<live-example></live-example>
## The injector tree
@ -43,11 +41,8 @@ The tree of components parallels the tree of injectors.
一个 Angular 应用是一个组件树。每个组件实例都有自己的注入器!
组件的树与注入器的树平行。
<div class="l-sub-section">
The component's injector may be a _proxy_ for an ancestor injector higher in the component tree.
That's an implementation detail that improves efficiency.
You won't notice the difference and
@ -56,11 +51,8 @@ your mental model should be that every component has its own injector.
组件的注入器可能是一个组件树中更高级的祖先注入器的*代理*。
但这只是提升效率的实现细节,我们不用在乎这点差异,在你的脑海里只要想象成每个组件都有自己的注入器就可以了。
</div>
Consider this guide's variation on the Tour of Heroes application.
At the top is the `AppComponent` which has some sub-components.
One of them is the `HeroesListComponent`.
@ -74,11 +66,11 @@ open simultaneously.
<figure>
<img src="generated/images/guide/dependency-injection/component-hierarchy.png" alt="injector tree">
</figure>
### Injector bubbling
### 注入器冒泡
@ -95,11 +87,8 @@ If it runs out of ancestors, Angular throws an error.
这个申请继续往上冒泡 —— 直到我们找到了一个能处理此申请的注入器或者超出了组件树中的祖先位置为止。
如果超出了组件树中的祖先还未找到Angular 就会抛出一个错误。
<div class="l-sub-section">
You can cap the bubbling. An intermediate component can declare that it is the "host" component.
The hunt for providers will climb no higher than the injector for that host component.
This is a topic for another day.
@ -108,11 +97,8 @@ The hunt for providers will climb no higher than the injector for that host comp
向上查找提供商的过程会截止于这个“宿主”组件。
我们先保留这个问题,等改天再讨论这个选项。
</div>
### Re-providing a service at different levels
### 在不同层级再次提供同一个服务
@ -138,8 +124,6 @@ All requests bubble up to the root <code>NgModule</code> injector that you confi
如果我们只在顶级(通常是根模块`AppModule`),这三个注入器看起来将是“平面”的。
所有的申请都会冒泡到根<code>NgModule</code>进行处理,也就是我们在`bootstrapModule`方法中配置的那个。
## Component injectors
## 组件注入器
@ -176,13 +160,10 @@ Instead, provide the `VillainsService` in the `providers` metadata of the `Villa
我们可以换一种方案:在`VillainsListComponent`元数据的`providers`中提供`VillainsService`,就像这样:
<code-example path="hierarchical-dependency-injection/src/app/villains-list.component.ts" linenums="false" title="src/app/villains-list.component.ts (metadata)" region="metadata">
</code-example>
By providing `VillainsService` in the `VillainsListComponent` metadata and nowhere else,
the service becomes available only in the `VillainsListComponent` and its sub-component tree.
It's still a singleton, but it's a singleton that exist solely in the _villain_ domain.
@ -233,13 +214,12 @@ Each tax return component has the following characteristics:
能把所做的修改保存到它的报税单中,或者放弃它们。
<figure>
<img src="generated/images/guide/dependency-injection/hid-heroes-anim.gif" alt="Heroes in action">
</figure>
One might suppose that the `HeroTaxReturnComponent` has logic to manage and restore changes.
That would be a pretty easy task for a simple hero tax return.
In the real world, with a rich tax return data model, the change management would be tricky.
@ -258,24 +238,18 @@ It also delegates to the application-wide singleton `HeroService`, which it gets
它缓存了单条`HeroTaxReturn`,用于跟踪那个申报单的变更,并且可以保存或还原它。
它还委托给了全应用级的单例服务`HeroService`,它是通过依赖注入机制取得的。
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.service.ts" title="src/app/hero-tax-return.service.ts">
</code-example>
Here is the `HeroTaxReturnComponent` that makes use of it.
下面是正在使用它的`HeroTaxReturnComponent`组件。
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" title="src/app/hero-tax-return.component.ts">
</code-example>
The _tax-return-to-edit_ arrives via the input property which is implemented with getters and setters.
The setter initializes the component's own instance of the `HeroTaxReturnService` with the incoming return.
The getter always returns what that service says is the current state of the hero.
@ -297,13 +271,10 @@ Look closely at the metadata for the `HeroTaxReturnComponent`. Notice the `provi
但仔细看`HeroTaxReturnComponent`的元数据,注意`providers`属性。
<code-example path="hierarchical-dependency-injection/src/app/hero-tax-return.component.ts" linenums="false" title="src/app/hero-tax-return.component.ts (providers)" region="providers">
</code-example>
The `HeroTaxReturnComponent` has its own provider of the `HeroTaxReturnService`.
Recall that every component _instance_ has its own injector.
Providing the service at the component level ensures that _every_ instance of the component gets its own, private instance of the service.
@ -314,22 +285,16 @@ No tax return overwriting. No mess.
在组件级提供服务可以确保组件的*每个*实例都得到一个自己的、私有的服务实例。
报税单不会再被意外覆盖,这下清楚了。
<div class="l-sub-section">
The rest of the scenario code relies on other Angular features and techniques that you can learn about elsewhere in the documentation.
You can review it and download it from the <live-example></live-example>.
该场景代码中的其它部分依赖另一些Angular的特性和技术我们将会在本文档的其它章节学到。
你可以到<live-example></live-example>查看代码和下载它。
</div>
### Scenario: specialized providers
### 场景:专门的提供商
@ -359,13 +324,12 @@ Component (B) is the parent of another component (C) that defines its own, even
组件B是另一个组件C的父组件而组件C又定义了自己的*更特殊的*`CarService`提供商。
<figure>
<img src="generated/images/guide/dependency-injection/car-components.png" alt="car components">
</figure>
Behind the scenes, each component sets up its own injector with zero, one, or more providers defined for that component itself.
在幕后每个组件都有自己的注入器这个注入器带有为组件本身准备的0个、1个或多个提供商。
@ -376,22 +340,18 @@ its injector produces an instance of `Car` resolved by injector (C) with an `Eng
当我们在最深层的组件C解析`Car`的实例时它使用注入器C解析生成了一个`Car`的实例使用注入器B解析了`Engine`,而`Tires`则是由根注入器A解析的。
<figure>
<img src="generated/images/guide/dependency-injection/injector-tree.png" alt="car injector tree">
</figure>
<div class="l-sub-section">
The code for this _cars_ scenario is in the `car.components.ts` and `car.services.ts` files of the sample
which you can review and download from the <live-example></live-example>.
*车辆*场景下的代码位于`car.components.ts``car.services.ts`文件中,这个例子你可以在<live-example></live-example>查看和下载。
</div>

View File

@ -200,6 +200,7 @@ It's certainly a good idea to give the user some kind of feedback when data acce
But displaying the raw error object returned by `HttpClient` is far from the best way to do it.
{@a error-details}
### Getting error details
### 获取错误详情
@ -264,6 +265,7 @@ _Pipe_ it onto the `HttpClient` method result just before the error handler.
</code-example>
{@a rxjs}
## Observables and operators
The previous sections of this guide referred to RxJS `Observables` and operators such as `catchError` and `retry`.
@ -422,6 +424,7 @@ Merely calling `HeroService.deleteHero()` **does not initiate the DELETE request
</code-example>
{@a always-subscribe}
### Always _subscribe_!
An `HttpClient` method does not begin its HTTP request until you call `subscribe()` on the observable returned by that method. This is true for _all_ `HttpClient` _methods_.
@ -905,6 +908,7 @@ Data services, such as `PackageSearchService`, are unaware that
some of their `HttpClient` requests actually return cached responses.
{@a cache-refresh}
#### Return a multi-valued _Observable_
The `HttpClient.get()` method normally returns an _observable_

View File

@ -9,20 +9,25 @@ an AOT-compiled app, translated into French.
可以把这个翻译为法语版的 AOT 应用<live-example name="i18n">i18n 例子</live-example>作为一个简单的例子。
{@a angular-i18n}
## Angular and i18n
Angular simplifies the following aspects of internationalization:
* Displaying dates, number, percentages, and currencies in a local format.
* Translating text in component templates.
* Handling plural forms of words.
* Handling alternative text.
This document focuses on [**Angular CLI**](https://cli.angular.io/) projects, in which the Angular
CLI generates most of the boilerplate necessary to write your app in multiple languages.
{@a setting-up-locale}
## Setting up the locale of your app
A locale is an identifier (id) that refers to a set of user preferences that tend to be shared
@ -52,14 +57,16 @@ To set your app's locale to another value, use the CLI parameter `--locale` with
of the locale id that you want to use:
<code-example language="sh" class="code-shell">
ng serve --aot --locale fr
</code-example>
If you use JIT, you also need to define the `LOCALE_ID` provider in your main module:
<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
[CLDR core spec](http://cldr.unicode.org/core-spec#Unicode_Language_and_Locale_Identifiers).
@ -84,7 +91,6 @@ time of writing:
| Chinese Traditional | zh-tw, zh-Hant-TW | zh-Hant |
| Chinese Traditional Hong Kong | zh-hk | zh-Hant-HK |
## i18n pipes
Angular pipes can help you with internationalization: the `DatePipe`, `CurrencyPipe`, `DecimalPipe`
@ -98,6 +104,7 @@ The CLI imports the locale data for you when you use the parameter `--locale` wi
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>
The first parameter is an object containing the locale data imported from `@angular/common/locales`.
@ -113,6 +120,7 @@ need, but some advanced formatting options might only be available in the extra
import from `@angular/common/locales/extra`. An error message informs you when this is the case.
<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>
<div class="l-sub-section">
@ -122,7 +130,6 @@ import from `@angular/common/locales/extra`. An error message informs you when t
</div>
## Template translations
<div class="l-sub-section">
@ -148,6 +155,7 @@ in the target language.
You need to build and deploy a separate version of the app for each supported language.
{@a i18n-attribute}
### Mark text with the i18n attribute
The Angular `i18n` attribute marks translatable content. Place it on every element tag whose fixed
@ -156,16 +164,16 @@ text is to be translated.
In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!"
<code-example path="i18n/doc-files/app.component.html" region="greeting" title="src/app/app.component.html" linenums="false">
</code-example>
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
添加`i18n`属性到该标签上,把它标记为需要翻译的文本。
<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">
@ -174,8 +182,8 @@ To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag
</div>
{@a help-translator}
### Help the translator with a description and meaning
To translate a text message accurately, the translator may need additional information or context.
@ -184,6 +192,7 @@ You can add a description of the text message as the value of the `i18n` attribu
example below:
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false">
</code-example>
The translator may also need to know the meaning or intent of the text message within this particular
@ -197,6 +206,7 @@ separating it from the _description_ with the `|` character: `<meaning>|<descrip
在描述的前面,我们为指定的字符串添加一些上下文含义,用`|`将其与描述文字隔开(`<意图>|<描述>`)。
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false">
</code-example>
All occurrences of a text message that have the same meaning will have the same translation.
@ -212,8 +222,8 @@ text messages with different descriptions (not different meanings), then they ar
但是如果在某些地方它具有**不同含义**,那么它应该有不同的翻译。
Angular的提取工具在翻译源文件中保留**含义**和**描述**,以支持符合特定上下文的翻译。
{@a custom-id}
### Set a custom id for persistence and maintenance
### 设置一个自定义的`id`来提升可搜索性和可维护性
@ -224,6 +234,7 @@ attribute in a template. By default, it assigns each translation unit a unique i
Angular 的 `i18n` 提取工具会为模板中每个带有`i18n`属性的元素生成一个*翻译单元translation unit*条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的`id`,就像这样:
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id" linenums="false">
</code-example>
When you change the translatable text, the extractor tool generates a new id for that translation unit.
@ -236,6 +247,7 @@ Alternatively, you can specify a custom id in the `i18n` attribute by using the
The example below defines the custom 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>
When you specify a custom id, the extractor tool and compiler generate a translation unit with that
@ -244,6 +256,7 @@ custom id.
现在,提取工具和编译器就会用*你的自定义id`生成一个翻译单元,而不会再改变它。
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id" linenums="false">
</code-example>
The custom id is persistent. The extractor tool does not change it when the translatable text changes.
@ -256,6 +269,7 @@ You can use a custom id in combination with a description by including both in t
by the custom `id`:
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false">
</code-example>
You also can add a meaning, as shown in this example:
@ -263,6 +277,7 @@ You also can add a meaning, as shown in this example:
下面这个例子带有*含义*和*描述*,最后是`id`
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false">
</code-example>
#### Define unique custom ids
@ -275,32 +290,44 @@ only the first one is extracted, and its translation is used in place of both or
In the example below the custom id `myId` is used for two different messages:
```html
<h3 i18n="@@myId">Hello</h3>
<!-- ... -->
<p i18n="@@myId">Good bye</p>
```
Consider this translation to French:
```xml
<trans-unit id="myId" datatype="html">
<source>Hello</source>
<target state="new">Bonjour</target>
</trans-unit>
```
Because the custom id is the same, both of the elements in the resulting translation contain
the same text, `Bonjour`:
```html
<h3>Bonjour</h3>
<!-- ... -->
<p>Bonjour</p>
```
{@a no-element}
### Translate text without creating an element
### 翻译文本,而不必创建元素
@ -314,9 +341,11 @@ The `<ng-container>` is transformed into an html comment:
但如果由于某些原因比如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>
{@a translate-attributes}
## Add i18n translation attributes
## 添加 *i18n* 翻译属性
@ -328,6 +357,7 @@ For example, assume that your template has an image with a `title` attribute:
比如,假设我们的模板具有一个带`title`属性的图片:
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" title="src/app/app.component.html" linenums="false">
</code-example>
This `title` attribute needs to be translated.
@ -339,6 +369,7 @@ where `x` is the name of the attribute to translate. The following example shows
`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag:
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false">
</code-example>
This technique works for any attribute of any element.
@ -349,6 +380,7 @@ syntax.
我们也同样可以使用`i18n-x="<meaning>|<description>@@<id>"`语法来指定一个含义和描述。
{@a plural-ICU}
## Translate singular and plural
## 处理单数与复数
@ -370,9 +402,11 @@ The example below shows how to use a `plural` ICU expression to display one of t
based on when the update occurred:
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false">
</code-example>
* The first parameter is the key. It is bound to the component property (`minutes`), which determines the number of minutes.
* The first parameter is the key. It is bound to the component property (`minutes`), which determines
the number of minutes.
第一个参数是key。它绑定到了组件中表示狼的数量的`wolves`属性。
@ -440,6 +474,7 @@ for two, three, or any other number if the pluralization rules were different. F
</div>
{@a select-ICU}
## Select among alternative text messages
## 在候选文本中选择
@ -459,9 +494,11 @@ 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>
{@a nesting-ICUS}
## Nesting plural and select ICU expressions
## 把"复数"与"选择"表达式嵌套在一起
@ -471,9 +508,11 @@ You can also nest different ICU expressions together, as shown in this example:
我们也可以把不同的 ICU 表达式嵌套在一起,比如:
<code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html">
</code-example>
{@a ng-xi18n}
## Create a translation source file with _ng xi18n_
## 使用_ng-xi18n_工具创建翻译源文件
@ -488,9 +527,10 @@ Open a terminal window at the root of the app project and enter the `ng xi18n` c
在应用的项目根目录打开一个终端窗口,并输入`ng-xi18n`命令:
<code-example language="sh" class="code-shell">
ng xi18n
</code-example>
By default, the tool generates a translation file named `messages.xlf` in the
@ -500,8 +540,10 @@ By default, the tool generates a translation file named `messages.xlf` in the
<div class="l-sub-section">
If you don't use the CLI, you have two options:
* You can use the `ng-xi18n` tool directly from the `@angular/compiler-cli` package.
For more information, see [i18n in the CLI documentation](https://github.com/angular/angular-cli/wiki/xi18n).
* You can use the CLI Webpack plugin `AngularCompilerPlugin` from the `@ngtools/webpack` package.
Set the parameters `i18nOutFile` and `i18nOutFormat` to trigger the extraction.
For more information, see the [Angular Ahead-of-Time Webpack Plugin documentation](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack).
@ -509,13 +551,17 @@ For more information, see the [Angular Ahead-of-Time Webpack Plugin documentatio
</div>
{@a other-formats}
### Other translation formats
### 其它翻译格式
Angular i18n tooling supports three translation formats:
* XLIFF 1.2 (default)
* XLIFF 2
* <a href="http://cldr.unicode.org/development/development-process/design-proposals/xmb" >XML Message
Bundle (XMB)</a>
@ -525,9 +571,11 @@ these example commands:
我们可以使用`--i18nFormat`来明确指定想用的格式,范例如下:
<code-example language="sh" class="code-shell">
ng xi18n --i18nFormat=xlf
ng xi18n --i18nFormat=xlf2
ng xi18n --i18nFormat=xmb
</code-example>
The sample in this guide uses the default XLIFF 1.2 format.
@ -540,6 +588,7 @@ The sample in this guide uses the default XLIFF 1.2 format.
</div>
{@a ng-xi18n-options}
### Other options
### 其它选项
@ -576,14 +625,14 @@ You can specify the base locale of your app with the parameter `--locale`:
The extraction tool uses the locale to add the app locale information into your translation source
file. This information is not used by Angular, but external translation tools may need it.
{@a translate}
## Translate text messages
## 翻译文本信息
The `ng xi18n` command generates a translation source file
named `messages.xlf`in the project `src` folder .
The `ng xi18n` command generates a translation source file named `messages.xlf` in the project `src`
folder.
`ng xi18n`命令在项目根目录生成一个名为`messages.xlf`的翻译源文件。
@ -594,6 +643,7 @@ translation files. The example in this guide creates a French translation file.
这个例子中创建了一个法语翻译文件。
{@a localization-folder}
### Create a localization folder
### 新建一个本土化目录
@ -630,20 +680,23 @@ resulting translation.
For this example:
1. Make a copy of the `messages.xlf` file.
2. Put the copy in the `locale` folder.
3. Rename the copy to `messages.fr.xlf` for the French language translation.
If you were translating to other languages, you would repeat these steps for each target language.
{@a translate-text-nodes}
### Translate text nodes
### 翻译文本节点
In a large translation project, you wouldsend the `messages.fr.xlf` file to a French translator who would enter the translations
using an XLIFF file editor.
In a large translation project, you would send the `messages.fr.xlf` file to a French translator who
would enter the translations using an XLIFF file editor.
在现实世界中,`messages.es.xlf`文件会被发给西班牙语翻译,他们使用<a href="https://en.wikipedia.org/wiki/XLIFF#Editors" target="_blank">这些XLIFF文件编辑器</a>中的一种来翻译它。
在现实世界中,`messages.fr.xlf`文件会被发给法语翻译,他们使用<a href="https://en.wikipedia.org/wiki/XLIFF#Editors" target="_blank">这些XLIFF文件编辑器</a>中的一种来翻译它。
This sample file is easy to translate without a special editor or knowledge of French.
@ -661,7 +714,6 @@ This sample file is easy to translate without a special editor or knowledge of F
[custom `id`](#custom-id "Set a custom id") that you set earlier, but
without the `@@` prefix required in the source HTML.
2. Duplicate the `<source/>` tag, rename it `target`, and then replace its content with the French
greeting. If you were working with a more complex translation, you could use the the information
and context provided by the source, description, and meaning elements to guide your selection of
@ -685,6 +737,7 @@ This sample file is easy to translate without a special editor or knowledge of F
</div>
{@a translate-plural-select}
## Translate plural and select expressions
_Plural_ and _select_ ICU expressions are extracted separately, so they require special attention
@ -695,6 +748,7 @@ elsewhere in the source template. In this example, you know the translation unit
must be just below the translation unit for the logo.
{@a translate-plural}
### Translate _plural_
To translate a `plural`, translate its ICU format match values:
@ -702,12 +756,14 @@ To translate a `plural`, translate its ICU format match values:
要翻译一个复数就要翻译它的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>
You can add or remove plural cases, with each language having its own cardinality. (See
[CLDR plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).)
{@a translate-select}
### Translate _select_
### 翻译*选择*select
@ -715,6 +771,7 @@ You can add or remove plural cases, with each language having its own cardinalit
Below is the content of our example `select` ICU expression in the component template:
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
</code-example>
The extraction tool broke that into two translation units because ICU expressions are extracted
@ -732,6 +789,7 @@ the placeholder, the ICU expression will not be present in your translated app.
翻译这段文本,并把占位符放在那里。
<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>
The second translation unit, immediately below the first one, contains the `select` message.
@ -740,6 +798,7 @@ Translate that as well.
第一个翻译单元的紧下方就是第二个翻译单元,包含`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>
Here they are together, after translation:
@ -747,9 +806,11 @@ 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>
{@a translate-nested}
### Translate a nested expression
### 翻译嵌套的表达式
@ -760,6 +821,7 @@ 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>
The second unit contains the complete nested expression:
@ -767,6 +829,7 @@ 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>
And both together:
@ -774,12 +837,14 @@ 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>
The entire template translation is complete. The next section describes how to load that translation
into the app.
{@a app-pre-translation}
### The app and its translation file
### 应用及其翻译文件
@ -788,21 +853,32 @@ The sample app and its translation file are now as follows:
下面是例子应用及其翻译文件:
<code-tabs>
<code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html">
</code-pane>
<code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
</code-pane>
<code-pane title="src/app/app.module.ts" path="i18n/src/app/app.module.ts">
</code-pane>
<code-pane title="src/main.ts" path="i18n/doc-files/main.1.ts">
</code-pane>
<code-pane title="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html">
</code-pane>
</code-tabs>
{@a merge}
## Merge the completed translation file into the app
## 合并已经翻译的文件
@ -827,10 +903,11 @@ How you provide this information depends upon whether you compile with
the JIT compiler or the AOT compiler.
* With [AOT](guide/i18n#merge-aot), you pass the information as a CLI parameter.
* With [JIT](guide/i18n#merge-jit), you provide the information at bootstrap time.
{@a merge-aot}
### Merge with the AOT compiler
The AOT (_Ahead-of-Time_) compiler is part of a build process that produces a small, fast,
@ -843,19 +920,23 @@ detection or url parameters.
You also need to instruct the AOT compiler to use your translation file. To do so, you use three
options with the `ng serve` or `ng build` commands:
* `--i18nFile`: the path to the translation file.
* `--i18nFormat`: the format of the translation file.
* `--locale`: the locale id.
The example below shows how to serve the French language file created in previous sections of this
guide:
<code-example language="sh" class="code-shell">
ng serve --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr
</code-example>
{@a merge-jit}
### Merge with the JIT compiler
### 用JiT编译器合并
@ -900,32 +981,38 @@ behavior of the compiler. You can use it to provide the translation providers:
在下面的`src/app/i18n-providers.ts`文件的`getTranslationProviders()`函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商:
<code-example path="i18n/doc-files/main.2.ts" title="src/main.ts">
</code-example>
Then provide the `LOCALE_ID` in the main module:
<code-example path="i18n/doc-files/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example>
{@a missing-translation}
### Report missing translations
By default, when a translation is missing, the build succeeds but generates a warning such as
`Missing translation for message "foo"`. You can configure the level of warning that is generated by
the Angular compiler:
* Error: throw an error. If you are using AOT compilation, the build will fail. If you are using JIT
compilation, the app will fail to load.
* Warning (default): show a 'Missing translation' warning in the console or shell.
* Ignore: do nothing.
If you use the AOT compiler, specify the warning level by using the CLI parameter
`--missingTranslation`. The example below shows how to set the warning level to error:
<code-example language="sh" class="code-shell">
ng serve --aot --missingTranslation=error
</code-example>
If you use the JIT compiler, specify the warning level in the compiler config at bootstrap by adding
@ -933,4 +1020,6 @@ the 'MissingTranslationStrategy' property. The example below shows how to set th
error:
<code-example path="i18n/doc-files/main.3.ts" title="src/main.ts">
</code-example>

View File

@ -25,7 +25,9 @@ you can hit tab to complete.
自动完成可以在输入时为我们提供当前情境下的候选内容和提示从而提高开发速度。下面这个例子展示了插值表达式中的自动完成功能。当我们进行输入的时候就可以按tab键来自动完成。
<figure>
<img src="generated/images/guide/language-service/language-completion.gif" alt="autocompletion">
</figure>
There are also completions within
@ -44,7 +46,9 @@ In this example, Angular doesn't know what `orders` is or where it comes from.
Angular 语言服务还能对代码中存在的错误进行预警。在这个例子中Angular 不知道什么是`orders`或者它来自哪里。
<figure>
<img src="generated/images/guide/language-service/language-error.gif" alt="error checking">
</figure>
## Navigation
@ -58,9 +62,10 @@ click and press F12 to go directly to its definition.
导航可以让我们在鼠标悬浮时看到某个组件、指令、模块等来自哪里,然后可以点击并按 F12 直接跳转到它的定义处。
<figure>
<img src="generated/images/guide/language-service/language-navigation.gif" alt="navigation">
</figure>
<img src="generated/images/guide/language-service/language-navigation.gif" alt="navigation">
</figure>
## Angular Language Service in your editor
@ -140,7 +145,6 @@ yarn
yarn install
```
### Sublime Text
### Sublime Text 编辑器
@ -175,7 +179,6 @@ Next, in your user preferences (`Cmd+,` or `Ctrl+,`), add:
"typescript-tsdk": "<path to your folder>/node_modules/typescript/lib"
```
## Installing in your project
## 安装到工程中
@ -222,20 +225,14 @@ context, it can then determine what the children can be.
It's a little more involved if you are in an interpolation. If you have an interpolation of `{{data.---}}` inside a `div` and need the completion list after `data.---`, the compiler can't use the HTML AST to find the answer. The HTML AST can only tell the compiler that there is some text with the characters "`{{data.---}}`". That's when the template parser produces an expression AST, which resides within the template AST. The Angular Language Services then looks at `data.---` within its context and asks the TypeScript Language Service what the members of data are. TypeScript then returns the list of possibilities.
如果是在插值表达式中,还会牵扯到更多东西。如果我们在`div`元素中有一个插值表达式`{{data.---}}`,并且需要在输入了`data.`之后提供自动完成列表,编译器就没办法使用 HTML AST 来找出答案了。
HTML AST只能告诉编译器有一些具有 "`{{data.---}}`" 特征的文本。也就是说模板解析器会生成表达式的 AST ,并且放在模板的 AST 中。Angular 语言服务然后在这个情境下查找`data.---`,并向 TypeScript 语言服务询问这些数据都有哪些成员。然后 TypeScript 就会返回一个可能的列表。
For more in-depth information, see the
[Angular Language Service API](https://github.com/angular/angular/blob/master/packages/language-service/src/types.ts)
要了解更多更深入的信息,参见 [Angular 语言服务 API](https://github.com/angular/angular/blob/master/packages/language-service/src/types.ts)
<hr>
## More on Information
@ -246,3 +243,4 @@ For more information, see [Chuck Jazdzewski's presentation](https://www.youtube.
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 语言服务。

View File

@ -1,11 +1,17 @@
# Lazy Loading Feature Modules
#### Prerequisites
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Types of Feature Modules](guide/module-types).
* [Routing and Navigation](guide/router).
For the final sample app with two lazy loaded modules that this page describes, see the
@ -18,7 +24,9 @@ For the final sample app with two lazy loaded modules that this page describes,
There are three main steps to setting up a lazy loaded feature module:
1. Create the feature module.
1. Create the feature modules routing module.
1. Configure the routes.
## Set up an app
@ -73,7 +81,6 @@ about components, see [Components](). -->
Just like with the routing module, the CLI imports the
`CustomerListComponent` into the `CustomersModule`.
## Add another feature module
For another place to route to, create a second feature module with routing:
@ -97,13 +104,10 @@ is easier for the user and more common. Replace the default
placeholder markup in `app.component.html` with a custom nav
so you can easily navigate to your modules in the browser:
<code-example path="lazy-loading-ngmodules/src/app/app.component.html" region="app-component-template" title="src/app/app.component.html" linenums="false">
</code-example>
To see your app in the browser so far, enter the following command in the terminal window:
```sh
@ -113,9 +117,10 @@ ng serve
Then go to `localhost:4200` where you should see “app works!” and three buttons.
<figure>
<img src="generated/images/guide/lazy-loading-ngmodules/three-buttons.png" width="300" alt="three buttons in the browser">
</figure>
<img src="generated/images/guide/lazy-loading-ngmodules/three-buttons.png" width="300" alt="three buttons in the browser">
</figure>
To make the buttons work, you need to configure the routing modules.
@ -127,9 +132,10 @@ The two feature modules, `OrdersModule` and `CustomersModule`, have to be
wired up to the `AppRoutingModule` so the router knows about them. The structure is as follows:
<figure>
<img src="generated/images/guide/lazy-loading-ngmodules/lazy-load-relationship.jpg" width="400" alt="lazy loaded modules diagram">
</figure>
<img src="generated/images/guide/lazy-loading-ngmodules/lazy-load-relationship.jpg" width="400" alt="lazy loaded modules diagram">
</figure>
Each feature module acts as a doorway via the router. In the `AppRoutingModule`, you configure the routes to the feature modules, in this case `OrdersModule` and `CustomersModule`. This way, the router knows to go to the feature module. The feature module then connects the `AppRoutingModule` to the `CustomersRoutingModule` or the `OrdersRoutingModule`. Those routing modules tell the router where to go to load relevant components.
@ -137,28 +143,22 @@ Each feature module acts as a doorway via the router. In the `AppRoutingModule`,
In `AppRoutingModule`, update the `routes` array with the following:
<code-example path="lazy-loading-ngmodules/src/app/app-routing.module.ts" region="const-routes" title="src/app/app-routing.module.ts" linenums="false">
</code-example>
The import statements stay the same. The first two paths are the routes to the `CustomersModule` and the `OrdersModule` respectively. Notice that the lazy loading syntax uses `loadChildren` followed by a string that is the path to the module, a hash mark or `#`, and the modules class name.
### Inside the feature module
Next, take a look at `customers.module.ts`. If youre using the CLI and following the steps outlined in this page, you dont have to do anything here. The feature module is like a connector between the `AppRoutingModule` and the feature routing module. The `AppRoutingModule` imports the feature module, `CustomersModule`, and `CustomersModule` in turn imports the `CustomersRoutingModule`.
<code-example path="lazy-loading-ngmodules/src/app/customers/customers.module.ts" region="customers-module" title="src/app/customers/customers.module.ts" linenums="false">
</code-example>
The `customers.module.ts` file imports the `CustomersRoutingModule` and `CustomerListComponent` so the `CustomersModule` class can have access to them. `CustomersRoutingModule` is then listed in the `@NgModule` `imports` array giving `CustomersModule` access to its own routing module, and `CustomerListComponent` is in the `declarations` array, which means `CustomerListComponent` belongs to the `CustomersModule`.
### Configure the feature modules routes
The next step is in `customers-routing.module.ts`. First, import the component at the top of the file with the other JavaScript import statements. Then, add the route to `CustomerListComponent`.
@ -167,7 +167,6 @@ The next step is in `customers-routing.module.ts`. First, import the component a
</code-example>
Notice that the `path` is set to an empty string. This is because the path in `AppRoutingModule` is already set to `customers`, so this route in the `CustomersRoutingModule`, is already within the `customers` context. Every route in this routing module is a child route.
Repeat this last step of importing the `OrdersListComponent` and configuring the Routes array for the `orders-routing.module.ts`:
@ -183,24 +182,26 @@ Now, if you view the app in the browser, the three buttons take you to each modu
You can check to see that a module is indeed being lazy loaded with the Chrome developer tools. In Chrome, open the dev tools by pressing `Cmd+Option+i` on a Mac or `Ctrl+Alt+i` on a PC and go to the Network Tab.
<figure>
<img src="generated/images/guide/lazy-loading-ngmodules/network-tab.png" width="600" alt="lazy loaded modules diagram">
</figure>
<img src="generated/images/guide/lazy-loading-ngmodules/network-tab.png" width="600" alt="lazy loaded modules diagram">
</figure>
Click on the Orders or Customers button. If you see a chunk appear, youve wired everything up properly and the feature module is being lazy loaded. A chunk should appear for Orders and for Customers but will only appear once for each.
<figure>
<img src="generated/images/guide/lazy-loading-ngmodules/chunk-arrow.png" width="600" alt="lazy loaded modules diagram">
</figure>
<img src="generated/images/guide/lazy-loading-ngmodules/chunk-arrow.png" width="600" alt="lazy loaded modules diagram">
</figure>
To see it again, or to test after working in the project, clear everything out by clicking the circle with a line through it in the upper left of the Network Tab:
<figure>
<img src="generated/images/guide/lazy-loading-ngmodules/clear.gif" width="200" alt="lazy loaded modules diagram">
</figure>
<img src="generated/images/guide/lazy-loading-ngmodules/clear.gif" width="200" alt="lazy loaded modules diagram">
</figure>
Then reload with `Cmd+r` or `Ctrl+r`, depending on your platform.
@ -217,12 +218,14 @@ knows that the route list is only responsible for providing additional routes an
`forRoot()` contains injector configuration which is global; such as configuring the Router. `forChild()` has no injector configuration, only directives such as `RouterOutlet` and `RouterLink`.
<hr>
## More on NgModules and routing
You may also be interested in the following:
* [Routing and Navigation](guide/router).
* [Providers](guide/providers).
* [Types of Feature Modules](guide/module-types).

View File

@ -41,7 +41,6 @@ that Angular calls shortly after creating the component:
每个接口都有唯一的一个钩子方法,它们的名字是由接口名再加上`ng`前缀构成的。比如,`OnInit`接口的钩子方法叫做`ngOnInit`
Angular在创建组件后立刻调用它
<code-example path="lifecycle-hooks/src/app/peek-a-boo.component.ts" region="ngOnInit" title="peek-a-boo.component.ts (excerpt)" linenums="false"></code-example>
No directive or component will implement all of the lifecycle hooks.
@ -49,7 +48,6 @@ Angular only calls a directive/component hook method *if it is defined*.
没有指令或者组件会实现所有这些接口,并且有些钩子只对组件有意义。只有在指令/组件中*定义过的*那些钩子方法才会被Angular调用。
{@a hooks-purpose-timing}
## Lifecycle sequence
@ -61,34 +59,28 @@ calls the lifecycle hook methods in the following sequence at specific moments:
当Angular使用构造函数新建一个组件或指令后就会按下面的顺序在特定时刻调用这些生命周期钩子方法
<table width="100%">
<col width="20%"></col>
<col width="80%"></col>
<tr>
<th>
<p>Hook
</p>
<th>Hook</th>
<p>
钩子
</p>
<th>Purpose and Timing</th>
</th>
<th>
<p>Purpose and Timing
</p>
<p>
目的和时机
</p></th>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngOnChanges()</code>
</td>
<td>
Respond when Angular (re)sets data-bound input properties.
@ -102,11 +94,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在`ngOnInit()`之前。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngOnInit()</code>
</td>
<td>
Initialize the directive/component after Angular first displays the data-bound properties
@ -119,11 +117,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
在第一轮`ngOnChanges()`完成之后调用,只调用**一次**。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngDoCheck()</code>
</td>
<td>
Detect and act upon changes that Angular can't or won't detect on its own.
@ -135,11 +139,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
在每个Angular变更检测周期中调用`ngOnChanges()``ngOnInit()`之后。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngAfterContentInit()</code>
</td>
<td>
Respond after Angular projects external content into the component's view / the view that a directive is in.
@ -151,11 +161,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
第一次`ngDoCheck()`之后调用,只调用一次。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngAfterContentChecked()</code>
</td>
<td>
Respond after Angular checks the content projected into the directive/component.
@ -167,11 +183,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
`ngAfterContentInit()`和每次`ngDoCheck()`之后调用
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngAfterViewInit()</code>
</td>
<td>
Respond after Angular initializes the component's views and child views / the view that a directive is in.
@ -183,11 +205,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
第一次`ngAfterContentChecked()`之后调用,只调用一次。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngAfterViewChecked()</code>
</td>
<td>
Respond after Angular checks the component's views and child views / the view that a directive is in.
@ -199,11 +227,17 @@ calls the lifecycle hook methods in the following sequence at specific moments:
`ngAfterViewInit()`和每次`ngAfterContentChecked()`之后调用。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<code>ngOnDestroy()</code>
</td>
<td>
Cleanup just before Angular destroys the directive/component.
@ -217,7 +251,9 @@ calls the lifecycle hook methods in the following sequence at specific moments:
在Angular销毁指令/组件之前调用。
</td>
</tr>
</table>
{@a interface-optional}
@ -234,11 +270,9 @@ Angular can't see TypeScript interfaces at runtime because they disappear from t
Angular在运行时看不到TypeScript接口因为它们在编译为JavaScript的时候已经消失了。
Fortunately, they aren't necessary.
幸运的是,它们并不是必须的。
You don't have to add the lifecycle hook interfaces to directives and components to benefit from the hooks themselves.
幸运的是,它们并不是必须的。
我们并不需要在指令和组件上添加生命周期钩子接口就能获得钩子带来的好处。
Angular instead inspects directive and component classes and calls the hook methods *if they are defined*.
@ -252,7 +286,6 @@ in order to benefit from strong typing and editor tooling.
虽然如此我们还是强烈建议你在TypeScript指令类中添加接口以获得强类型和IDE等编辑器带来的好处。
{@a other-lifecycle-hooks}
## Other Angular lifecycle hooks
@ -263,7 +296,6 @@ Other Angular sub-systems may have their own lifecycle hooks apart from these co
Angular的其它子系统除了有这些组件钩子外还可能有它们自己的生命周期钩子。
3rd party libraries might implement their hooks as well in order to give developers more
control over how these libraries are used.
@ -291,32 +323,27 @@ Here's a brief description of each exercise:
下面是每个练习简短的描述:
<table width="100%">
<col width="20%"></col>
<col width="80%"></col>
<tr>
<th>
<p>Component
</p>
<th>Component</th>
<p>
组件
</p>
<th>Description</th>
</th>
<th>
<p>Description
</p>
<p>
描述
</p></th>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#peek-a-boo">Peek-a-boo</a>
</td>
<td>
Demonstrates every lifecycle hook.
@ -325,11 +352,17 @@ Here's a brief description of each exercise:
展示每个生命周期钩子,每个钩子方法都会在屏幕上显示一条日志。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#spy">Spy</a>
</td>
<td>
Directives have lifecycle hooks too.
@ -344,11 +377,17 @@ Here's a brief description of each exercise:
本例把`SpyDirective`应用到父组件里的`ngFor`*英雄*重复器(repeater)的`<div>`里面。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#onchanges">OnChanges</a>
</td>
<td>
See how Angular calls the `ngOnChanges()` hook with a `changes` object
@ -358,13 +397,18 @@ Here's a brief description of each exercise:
这里将会看到每当组件的输入属性发生变化时Angular会如何以`changes`对象作为参数去调用`ngOnChanges()`钩子。
展示了该如何理解和使用`changes`对象。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#docheck">DoCheck</a>
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#docheck">DoCheck</a>
</td>
<td>
Implements an `ngDoCheck()` method with custom change detection.
@ -373,13 +417,18 @@ Here's a brief description of each exercise:
实现了一个`ngDoCheck()`方法,通过它可以自定义变更检测逻辑。
这里将会看到Angular会用什么频度调用这个钩子监视它的变化并把这些变化输出成一条日志。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#afterview">AfterView</a>
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#afterview">AfterView</a>
</td>
<td>
Shows what Angular means by a *view*.
@ -389,11 +438,17 @@ Here's a brief description of each exercise:
演示了`ngAfterViewInit``ngAfterViewChecked`钩子。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<a href="#aftercontent">AfterContent</a>
</td>
<td>
Shows how to project external content into a component and
@ -404,19 +459,19 @@ Here's a brief description of each exercise:
演示了`ngAfterContentInit``ngAfterContentChecked`钩子。
</td>
</tr>
<tr style='vertical-align:top'>
<td>
<p>
Counter
</p>
<p>
计数器
</p>
</td>
<td>
Demonstrates a combination of a component and a directive
@ -433,14 +488,15 @@ Here's a brief description of each exercise:
同时,我们还把前一个例子中的`SpyDirective`用在`CounterComponent`上,来提供日志,可以同时观察到日志的创建和销毁过程。
</td>
</tr>
</table>
The remainder of this page discusses selected exercises in further detail.
接下来,我们将详细讨论这些练习。
{@a peek-a-boo}
## Peek-a-boo: all hooks
@ -461,9 +517,10 @@ This snapshot reflects the state of the log after the user clicked the *Create..
用户点击**Create...**按钮,然后点击**Destroy...**按钮后,日志的状态如下图所示:
<figure>
<img src="generated/images/guide/lifecycle-hooks/peek-a-boo.png" alt="Peek-a-boo">
</figure>
The sequence of log messages follows the prescribed hook calling order:
@ -474,7 +531,6 @@ The sequence of log messages follows the prescribed hook calling order:
`OnChanges``OnInit``DoCheck`&nbsp;(3x)、`AfterContentInit``AfterContentChecked`&nbsp;(3x)、
`AfterViewInit``AfterViewChecked`&nbsp;(3x)和`OnDestroy`
<div class="l-sub-section">
The constructor isn't an Angular hook *per se*.
@ -483,7 +539,6 @@ The sequence of log messages follows the prescribed hook calling order:
构造函数本质上不应该算作Angular的钩子。
记录确认了在创建期间那些输入属性(这里是`name`属性)没有被赋值。
</div>
Had the user clicked the *Update Hero* button, the log would show another `OnChanges` and two more triplets of
@ -497,7 +552,6 @@ The next examples focus on hook details.
下一个例子就聚焦于这些钩子的细节上。
{@a spy}
## Spying *OnInit* and *OnDestroy*
@ -513,7 +567,6 @@ The heroes will never know they're being watched.
指令是一种完美的渗透方式,我们的英雄永远不会知道该指令的存在。
<div class="l-sub-section">
Kidding aside, pay attention to two key points:
@ -522,7 +575,7 @@ The heroes will never know they're being watched.
1. Angular calls hook methods for *directives* as well as components.<br><br>
就像对组件一样Angular也会对*指令*调用这些钩子方法。
就像对组件一样Angular也会对*指令*调用这些钩子方法。<br><br>
2. A spy directive can provide insight into a DOM object that you cannot change directly.
Obviously you can't touch the implementation of a native `<div>`.
@ -534,19 +587,14 @@ But you can watch both with a directive.
你同样不能修改第三方组件。
但我们用一个指令就能监视它们了。
</div>
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
that log messages to the parent via an injected `LoggerService`.
我们这个鬼鬼祟祟的侦探指令很简单,几乎完全由`ngOnInit()``ngOnDestroy()`钩子组成,它通过一个注入进来的`LoggerService`来把消息记录到父组件中去。
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" title="src/app/spy.directive.ts" linenums="false">
</code-example>
<code-example path="lifecycle-hooks/src/app/spy.directive.ts" region="spy-directive" title="src/app/spy.directive.ts" linenums="false"></code-example>
You can apply the spy to any native or component element and it'll be initialized and destroyed
at the same time as that element.
@ -555,17 +603,17 @@ Here it is attached to the repeated hero `<div>`:
我们可以把这个侦探指令写到任何原生元素或组件元素上,它将与所在的组件同时初始化和销毁。
下面是把它附加到用来重复显示英雄数据的这个`<div>`上。
<code-example path="lifecycle-hooks/src/app/spy.component.html" region="template" title="src/app/spy.component.html" linenums="false"></code-example>
Each spy's birth and death marks the birth and death of the attached hero `<div>`
with an entry in the *Hook Log* as seen here:
每个“侦探”的出生和死亡也同时标记出了存放英雄的那个`<div>`的出生和死亡。*钩子记录*中的结构是这样的:
<figure>
<img src='generated/images/guide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive">
</figure>
Adding a hero results in a new hero `<div>`. The spy's `ngOnInit()` logs that event.
@ -584,7 +632,6 @@ The `ngOnInit()` and `ngOnDestroy()` methods have more vital roles to play in re
在真实的应用程序中,`ngOnInit()``ngOnDestroy()`方法扮演着更重要的角色。
{@a oninit}
### _OnInit()_
@ -607,7 +654,6 @@ Experienced developers agree that components should be cheap and safe to constru
有经验的开发者会认同组件的构建应该很便宜和安全。
<div class="l-sub-section">
Misko Hevery, Angular team lead,
@ -616,7 +662,6 @@ Experienced developers agree that components should be cheap and safe to constru
Misko HeveryAngular项目的组长在[这里解释](http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/)了你为什么应该避免复杂的构造函数逻辑。
</div>
Don't fetch data in a component constructor.
@ -641,7 +686,6 @@ They'll have been set when `ngOnInit()` runs.
如果我们需要基于这些属性的值来初始化这个指令,这种情况就会出问题。
而当`ngOnInit()`执行的时候,这些属性都已经被正确的赋值过了。
<div class="l-sub-section">
The `ngOnChanges()` method is your first opportunity to access those properties.
@ -651,7 +695,6 @@ They'll have been set when `ngOnInit()` runs.
我们访问这些属性的第一次机会,实际上是`ngOnChanges()`方法Angular会在`ngOnInit()`之前调用它。
但是在那之后Angular还会调用`ngOnChanges()`很多次。而`ngOnInit()`只会被调用一次。
</div>
You can count on Angular to call the `ngOnInit()` method _soon_ after creating the component.
@ -660,7 +703,6 @@ That's where the heavy initialization logic belongs.
你可以信任Angular会在创建组件后立刻调用`ngOnInit()`方法。
这里是放置复杂初始化逻辑的好地方。
{@a ondestroy}
### _OnDestroy()_
@ -684,8 +726,6 @@ You risk memory leaks if you neglect to do so.
取消那些对可观察对象和DOM事件的订阅。停止定时器。注销该指令曾注册到全局服务或应用级服务中的各种回调函数。
如果不这么做,就会有导致内存泄露的风险。
{@a onchanges}
## _OnChanges()_
@ -693,14 +733,11 @@ You risk memory leaks if you neglect to do so.
## _OnChanges()_ 钩子
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
一旦检测到该组件(或指令)的***输入属性***发生了变化Angular就会调用它的`ngOnChanges()`方法。
This example monitors the `OnChanges` hook.
一旦检测到该组件(或指令)的***输入属性***发生了变化Angular就会调用它的`ngOnChanges()`方法。
本例监控`OnChanges`钩子。
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="ng-on-changes" title="on-changes.component.ts (excerpt)" linenums="false"></code-example>
The `ngOnChanges()` method takes an object that maps each changed property name to a
@ -714,26 +751,22 @@ The example component, `OnChangesComponent`, has two input properties: `hero` an
这个例子中的`OnChangesComponent`组件有两个输入属性:`hero``power`
<code-example path="lifecycle-hooks/src/app/on-changes.component.ts" region="inputs" title="src/app/on-changes.component.ts" linenums="false"></code-example>
The host `OnChangesParentComponent` binds to them like this:
宿主`OnChangesParentComponent`绑定了它们,就像这样:
<code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" title="src/app/on-changes-parent.component.html">
</code-example>
<code-example path="lifecycle-hooks/src/app/on-changes-parent.component.html" region="on-changes" title="src/app/on-changes-parent.component.html"></code-example>
Here's the sample in action as the user makes changes.
下面是此例子中的当用户做出更改时的操作演示:
<figure>
<img src='generated/images/guide/lifecycle-hooks/on-changes-anim.gif' alt="OnChanges">
</figure>
The log entries appear as the string value of the *power* property changes.
@ -754,8 +787,6 @@ Angular只会在输入属性的值变化时调用这个钩子。
Angular不会关注这个英雄对象的`name`属性的变化。
这个英雄对象的*引用*没有发生变化于是从Angular的视角看来也就没有什么需要报告的变化了。
{@a docheck}
## _DoCheck()_
@ -766,34 +797,32 @@ Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch
使用`DoCheck`钩子来检测那些Angular自身无法捕获的变更并采取行动。
<div class="l-sub-section">
Use this method to detect a change that Angular overlooked.
用这个方法来检测那些被Angular忽略的更改。
</div>
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
*DoCheck*范例通过下面的`ngDoCheck()`实现扩展了*OnChanges*范例:
<code-example path="lifecycle-hooks/src/app/do-check.component.ts" region="ng-do-check" title="DoCheckComponent (ngDoCheck)" linenums="false"></code-example>
This code inspects certain _values of interest_, capturing and comparing their current state against previous values.
It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
so you can see how often `DoCheck` is called. The results are illuminating:
该代码检测一些**相关的值**,捕获当前值并与以前的值进行比较。
当英雄或它的超能力发生了非实质性改变时,我们就往日志中写一条特殊的消息。
这样你可以看到`DoCheck`被调用的频率。结果非常显眼:
<figure>
<img src='generated/images/guide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck">
</figure>
While the `ngDoCheck()` hook can detect when the hero's `name` has changed, it has a frightful cost.
@ -830,14 +859,12 @@ Here's a child view that displays a hero's name in an `<input>`:
下面是一个子视图,它用来把英雄的名字显示在一个`<input>`中:
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="child-view" title="ChildComponent" linenums="false"></code-example>
The `AfterViewComponent` displays this child view *within its template*:
`AfterViewComponent`把这个子视图显示*在它的模板中*
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="template" title="AfterViewComponent (template)" linenums="false"></code-example>
The following hooks take action based on changing values *within the child view*,
@ -846,7 +873,6 @@ which can only be reached by querying for the child view via the property decora
下列钩子基于*子视图中*的每一次数据变更采取行动,我们只能通过带[@ViewChild](api/core/ViewChild)装饰器的属性来访问子视图。
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="hooks" title="AfterViewComponent (class excerpts)" linenums="false"></code-example>
{@a wait-a-tick}
@ -859,9 +885,7 @@ The `doSomething()` method updates the screen when the hero name exceeds 10 char
当英雄的名字超过10个字符时`doSomething()`方法就会更新屏幕。
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" title="AfterViewComponent (doSomething)" linenums="false">
</code-example>
<code-example path="lifecycle-hooks/src/app/after-view.component.ts" region="do-something" title="AfterViewComponent (doSomething)" linenums="false"></code-example>
Why does the `doSomething()` method wait a tick before updating `comment`?
@ -880,14 +904,14 @@ for one turn of the browser's JavaScript cycle and that's just long enough.
如果我们立即更新组件中被绑定的`comment`属性Angular就会抛出一个错误(试试!)。
`LoggerService.tick_then()`方法延迟更新日志一个回合浏览器JavaScript周期回合这样就够了。
Here's *AfterView* in action:
这里是*AfterView*的操作演示:
<figure>
<img src='generated/images/guide/lifecycle-hooks/after-view-anim.gif' alt="AfterView">
</figure>
Notice that Angular frequently calls `AfterViewChecked()`, often when there are no changes of interest.
@ -896,8 +920,6 @@ Write lean hook methods to avoid performance problems.
注意Angular会频繁的调用`AfterViewChecked()`,甚至在并没有需要关注的更改时也会触发。
所以务必把这个钩子方法写得尽可能精简,以免出现性能问题。
{@a aftercontent}
## AfterContent
@ -909,7 +931,6 @@ The *AfterContent* sample explores the `AfterContentInit()` and `AfterContentChe
*AfterContent*例子展示了`AfterContentInit()``AfterContentChecked()`钩子Angular会在外来内容被投影到组件中*之后*调用它们。
{@a content-projection}
### Content projection
@ -921,14 +942,12 @@ into the component's template in a designated spot.
*内容投影*是从组件外部导入HTML内容并把它插入在组件模板中指定位置上的一种途径。
<div class="l-sub-section">
AngularJS developers know this technique as *transclusion*.
AngularJS的开发者大概知道一项叫做*transclusion*的技术,对,这就是它的马甲。
</div>
Consider this variation on the [previous _AfterView_](guide/lifecycle-hooks#afterview) example.
@ -938,7 +957,6 @@ the `AfterContentComponent`'s parent. Here's the parent's template:
对比[前一个](guide/lifecycle-hooks#afterview)例子考虑这个变化。
这次,我们不再通过模板来把子视图包含进来,而是改从`AfterContentComponent`的父组件中导入它。下面是父组件的模板:
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="parent-template" title="AfterContentParentComponent (template excerpt)" linenums="false"></code-example>
Notice that the `<my-child>` tag is tucked between the `<after-content>` tags.
@ -952,7 +970,6 @@ Now look at the component's template:
现在来看下`<after-content>`组件的模板:
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="template" title="AfterContentComponent (template)" linenums="false"></code-example>
The `<ng-content>` tag is a *placeholder* for the external content.
@ -963,9 +980,10 @@ In this case, the projected content is the `<my-child>` from the parent.
它告诉Angular在哪里插入这些外来内容。
在这里,被投影进去的内容就是来自父组件的`<my-child>`标签。
<figure>
<img src='generated/images/guide/lifecycle-hooks/projected-child-view.png' alt="Projected Content">
</figure>
<div class="l-sub-section">
@ -982,7 +1000,6 @@ In this case, the projected content is the `<my-child>` from the parent.
组件的模板中出现了`<ng-content>`标签
</div>
{@a aftercontent-hooks}
@ -1010,9 +1027,10 @@ The following *AfterContent* hooks take action based on changing values in a *co
which can only be reached by querying for them via the property decorated with
[@ContentChild](api/core/ContentChild).
下列*AfterContent*钩子基于*子级内容*中值的变化而采取相应的行动,这里我们只能通过带有[@ContentChild](api/core/ContentChild)装饰器的属性来查询到“子级内容”。
<code-example path="lifecycle-hooks/src/app/after-content.component.ts" region="hooks" title="AfterContentComponent (class excerpts)" linenums="false"></code-example>
{@a no-unidirectional-flow-worries}
### No unidirectional flow worries with _AfterContent_
@ -1029,6 +1047,7 @@ Recall that Angular calls both *AfterContent* hooks before calling either of the
Angular completes composition of the projected content *before* finishing the composition of this component's view.
There is a small window between the `AfterContent...` and `AfterView...` hooks to modify the host view.
回忆一下Angular在每次调用*AfterView*钩子之前也会同时调用*AfterContent*。
Angular在完成当前组件的视图合成之前就已经完成了被投影内容的合成。
所以我们仍然有机会去修改那个视图。

View File

@ -5,8 +5,13 @@
#### Prerequisites
A basic understanding of the following concepts:
对下列概念有基本的理解:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
<hr>
@ -15,9 +20,13 @@ There are five general categories of feature modules which
tend to fall into the following groups:
* Domain feature modules.
* Routed feature modules.
* Routing modules.
* Service feature modules.
* Widget feature modules.
While the following guidelines describe the use of each type and their
@ -26,18 +35,27 @@ typical characteristics, in real world apps, you may see hybrids.
<table>
<tr>
<th style="vertical-align: top">
Feature Module
</th>
<th style="vertical-align: top">
Guidelines
</th>
</tr>
<tr>
<td>Domain</td>
<td>
Domain feature modules deliver a user experience dedicated to a particular application domain like editing a customer or placing an order.
They typically have a top component that acts as the feature root and private, supporting sub-components descend from it.
@ -49,11 +67,17 @@ typical characteristics, in real world apps, you may see hybrids.
Domain feature modules are typically imported exactly once by a larger feature module.
They might be imported by the root `AppModule` of a small application that lacks routing.
</td>
</tr>
<tr>
<td>Routed</td>
<td>
Routed feature modules are domain feature modules whose top components are the targets of router navigation routes.
All lazy-loaded modules are routed feature modules by definition.
@ -63,11 +87,15 @@ typical characteristics, in real world apps, you may see hybrids.
A lazy-loaded routed feature module should not be imported by any module. Doing so would trigger an eager load, defeating the purpose of lazy loading.That means you wont see them mentioned among the `AppModule` imports. An eager loaded routed feature module must be imported by another module so that the compiler learns about its components.
Routed feature modules rarely have providers for reasons explained in [Lazy Loading Feature Modules](/guide/lazy-loading-ngmodules). When they do, the lifetime of the provided services should be the same as the lifetime of the module. Don't provide application-wide singleton services in a routed feature module or in a module that the routed module imports.
</td>
</tr>
<tr>
<td>Routing</td>
<td>
A routing module provides routing configuration for another module and separates routing concerns from its companion module.
@ -75,21 +103,31 @@ typical characteristics, in real world apps, you may see hybrids.
A routing module typically does the following:
<ul>
<li>Defines routes.</li>
<li>Adds router configuration to the module's imports.</li>
<li>Adds guard and resolver service providers to the module's providers.</li>
<li>The name of the routing module should parallel the name of its companion module, using the suffix "Routing". For example, <code>FooModule</code> in <code>foo.module.ts</code> has a routing module named <code>FooRoutingModule</code> in <code>foo-routing.module.ts</code>. If the companion module is the root <code>AppModule</code>, the <code>AppRoutingModule</code> adds router configuration to its imports with <code>RouterModule.forRoot(routes)</code>. All other routing modules are children that import <code>RouterModule.forChild(routes)</code>.</li>
<li>A routing module re-exports the <code>RouterModule</code> as a convenience so that components of the companion module have access to router directives such as <code>RouterLink</code> and <code>RouterOutlet</code>.</li>
<li>A routing module does not have its own declarations. Components, directives, and pipes are the responsibility of the feature module, not the routing module.</li>
</ul>
A routing module should only be imported by its companion module.
</td>
</tr>
<tr>
<td>Service</td>
<td>
Service modules provide utility services such as data access and messaging. Ideally, they consist entirely of providers and have no declarations. Angular's `HttpClientModule` is a good example of a service module.
@ -97,10 +135,13 @@ typical characteristics, in real world apps, you may see hybrids.
The root `AppModule` is the only module that should import service modules.
</td>
</tr>
<tr>
<td>Widget</td>
<td>
A widget module makes components, directives, and pipes available to external modules. Many third-party UI component libraries are widget modules.
@ -112,6 +153,7 @@ typical characteristics, in real world apps, you may see hybrids.
Import widget modules in any module whose component templates need the widgets.
</td>
</tr>
</table>
@ -119,67 +161,111 @@ typical characteristics, in real world apps, you may see hybrids.
The following table summarizes the key characteristics of each feature module group.
<table>
<tr>
<th style="vertical-align: top">
Feature Module
</th>
<th style="vertical-align: top">
Declarations
</th>
<th style="vertical-align: top">
Providers
</th>
<th style="vertical-align: top">
Exports
</th>
<th style="vertical-align: top">
Imported by
</th>
</tr>
<tr>
<td>Domain</td>
<td>Yes</td>
<td>Rare</td>
<td>Top component</td>
<td>Feature, AppModule</td>
</tr>
<tr>
<td>Routed</td>
<td>Yes</td>
<td>Rare</td>
<td>No</td>
<td>None</td>
</tr>
<tr>
<td>Routing</td>
<td>No</td>
<td>Yes (Guards)</td>
<td>RouterModule</td>
<td>Feature (for routing)</td>
</tr>
<tr>
<td>Service</td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>AppModule</td>
</tr>
<tr>
<td>Widget</td>
<td>Yes</td>
<td>Rare</td>
<td>Yes</td>
<td>Feature</td>
</tr>
</table>
<hr />
@ -187,5 +273,7 @@ The following table summarizes the key characteristics of each feature module gr
## More on NgModules
You may also be interested in the following:
* [Lazy Loading Modules with the Angular Router](guide/lazy-loading-ngmodules).
* [Providers](guide/providers).

View File

@ -3,7 +3,11 @@
#### Prerequisites
A basic understanding of the following concepts:
对下列概念有基本的理解:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr />
@ -16,7 +20,9 @@ decorator. The metadata falls
into three categories:
* **Static:** Compiler configuration which tells the compiler about directive selectors and where in templates the directives should be applied through selector matching. This is configured via the `declarations` array.
* **Runtime:** Injector configuration via the `providers` array.
* **Composability/Grouping:** Bringing NgModules together and making them available via the `imports` and `exports` arrays.
```typescript
@ -43,11 +49,19 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<th>
Property
属性
</th>
<th>
Description
描述
</th>
</tr>
@ -55,7 +69,9 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<td style="vertical-align: top">
<code>declarations</code>
</td>
<td>
@ -64,14 +80,23 @@ The following table summarizes the `@NgModule` metadata properties.
(*components*, *directives*, and *pipes*) that _belong to this module_.
<ol>
<li>When compiling a template, you need to determine a set of selectors which should be used for triggering their corresponding directives.</li>
<li>
The template is compiled within the context of an NgModule&mdash;the NgModule within which the template's component is declared&mdash;which determines the set of selectors using the following rules:
<ul>
<li>All selectors of directives listed in `declarations`.</li>
<li>All selectors of directives exported from imported NgModules.</li>
</ul>
</li>
</ol>
Components, directives, and pipes must belong to _exactly_ one module.
@ -86,7 +111,9 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<td style="vertical-align: top">
<code>providers</code>
</td>
<td>
@ -117,7 +144,9 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<td style="vertical-align: top">
<code>imports</code>
</td>
<td>
@ -145,7 +174,9 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<td style="vertical-align: top">
<code>exports</code>
</td>
<td>
@ -179,7 +210,9 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<td style="vertical-align: top">
<code>bootstrap</code>
</td>
<td>
@ -200,7 +233,9 @@ The following table summarizes the `@NgModule` metadata properties.
<tr>
<td style="vertical-align: top">
<code>entryComponents</code>
</td>
<td>
@ -224,19 +259,24 @@ The following table summarizes the `@NgModule` metadata properties.
For more information, see [Entry Components](guide/entry-components).
要了解更多,参见[入口组件](guide/entry-components)一章。
</td>
</tr>
</table>
<hr />
## More on NgModules
You may also be interested in the following:
* [Feature Modules](guide/feature-modules).
* [Entry Components](guide/entry-components).
* [Providers](guide/providers).
* [Types of Feature Modules](guide/module-types).

View File

@ -22,7 +22,6 @@ This page answers the questions many developers ask about NgModule design and im
这里回答的是开发者常问起的关于Angular模块的设计与实现问题。
## What classes should I add to the `declarations` array?
## 我应该把哪些类加到*declarations*中?
@ -51,7 +50,6 @@ They're the only classes that you can add to `declarations`.
*可声明的*就是组件、指令和管道等可以被加到模块的`declarations`列表中的类。它们也是*所有*能被加到`declarations`中的类。
<hr/>
## What classes should I _not_ add to `declarations`?
@ -88,10 +86,8 @@ strings, numbers, functions, entity models, configurations, business logic, and
非Angular的类和对象比如字符串、数字、函数、实体模型、配置、业务逻辑和辅助类。
<hr/>
## Why list the same component in multiple `NgModule` properties?
## 为什么要把同一个组件声明在不同的*NgModule*属性中?
@ -124,8 +120,6 @@ as well as dynamically loaded in a pop-up dialog.
`HeroComponent`可能被导入,以便用在外部组件的模板中,但也可能同时被一个弹出式对话框加载。
<hr/>
## What does "Can't bind to 'x' since it isn't a known property of 'y'" mean?
@ -178,7 +172,6 @@ Import only [BrowserModule](guide/ngmodule-faq#q-browser-vs-common-module) in th
只能在根模块`AppModule`中[导入_BrowserModule_](guide/ngmodule-faq#q-browser-vs-common-module)。
<hr/>
{@a q-browser-vs-common-module}
@ -214,7 +207,6 @@ Importing `CommonModule` also frees feature modules for use on _any_ target plat
特性模块中导入`CommonModule`可以让它能用在任何目标平台上,不仅是浏览器。那些跨平台库的作者应该喜欢这种方式的。
<hr/>
{@a q-reimport}
@ -260,9 +252,12 @@ declared in this NgModule.
You _can_ export any declarable class&mdash;components, directives, and pipes&mdash;whether
it's declared in this NgModule or in an imported NgModule.
你*可以*导出任何可声明类组件、指令和管道而不用管它是声明在当前模块中还是某个导入的模块中。You _can_ re-export entire imported NgModules, which effectively re-exports all of their exported classes.
你*可以*导出任何可声明类(组件、指令和管道),而不用管它是声明在当前模块中还是某个导入的模块中。
You _can_ re-export entire imported NgModules, which effectively re-exports all of their exported classes.
An NgModule can even export a module that it doesn't import.
你*可以*重新导出整个导入过的模块,这将导致重新导出它们导出的所有类。模块甚至还可以导出它未曾导入过的模块。
你*可以*重新导出整个导入过的模块,这将导致重新导出它们导出的所有类。重新导出的模块甚至不用先导入。
<hr/>
@ -299,11 +294,8 @@ Its only purpose is to add http service providers to the application as a whole.
例如,没必要重新导出`HttpClientModule`,因为它不导出任何东西。
它唯一的用途是一起把http的那些服务提供商添加到应用中。
<hr/>
## Can I re-export classes and modules?
## 我可以重新导出类和模块吗?
@ -341,10 +333,8 @@ Its only purpose is to add http service providers to the application as a whole.
例如,不用重新导出`HttpClientModule`,因为它没有导出任何东西。
它唯一的用途是把那些http服务提供商一起添加到应用中。
<hr/>
## What is the `forRoot()` method?
## *forRoot*方法是什么?
@ -388,10 +378,8 @@ Follow this convention when you write similar modules with configurable service
Angular并不识别这些名字但是Angular的开发人员可以。
当你写类似的需要可配置的服务提供商时,请遵循这个约定。
<hr/>
## Why is a service provided in a feature module visible everywhere?
## 为什么服务提供商在特性模块中的任何地方都是可见的?
@ -432,7 +420,6 @@ not just the classes declared in the `HeroModule`.
不过,如果你期望模块的服务只对那个特性模块内部声明的组件可见,那么这可能会带来一些不受欢迎的意外。
如果`HeroModule`提供了一个`HeroService`,并且根模块`AppModule`导入了`HeroModule`,那么任何知道`HeroService`*类型*的类都可能注入该服务,而不仅是在`HeroModule`中声明的那些类。
<hr/>
{@a q-lazy-loaded-module-provider-visibility}
@ -464,10 +451,8 @@ Angular prefers service instances created from these providers to the service in
这些提供商不会被拥有相同令牌的应用级别提供商的变化所影响。
当路由器在惰性加载环境中创建组件时Angular优先使用惰性加载模块中的服务实例而不是来自应用的根注入器的。
<hr/>
## What if two modules provide the same service?
## 如果两个模块提供了*同一个*服务会怎么样?
@ -498,10 +483,8 @@ The `AppModule` always wins.
由根`AppModule`提供的服务相对于所导入模块中提供的服务有优先权。换句话说:`AppModule`总会获胜。
<hr/>
## How do I restrict service scope to a module?
## 我们应该如何把服务的范围限制到模块中?
@ -587,12 +570,10 @@ Define child routes and let the router load module components into that outlet.
你可以把这些子组件都嵌在顶级组件的模板中。或者,给顶级组件一个`<router-outlet>`,让它作为路由的宿主。
定义子路由并让路由器把模块中的组件加载进该路由出口outlet中。
<hr/>
{@a q-root-component-or-module}
## Should I add application-wide providers to the root `AppModule` or the root `AppComponent`?
## 我应该把全应用级提供商添加到根模块`AppModule`中还是根组件`AppComponent`中?
@ -654,8 +635,6 @@ This means that lazy-loaded modules can't reach them.
{@a q-component-or-module}
## Should I add other providers to a module or a component?
## 我应该把其它提供商注册到模块中还是组件中?
@ -686,12 +665,10 @@ not the root `AppComponent`.
[总是在根模块`AppModule`中注册*全应用级*服务](guide/ngmodule-faq#q-root-component-or-module),而不要在根组件`AppComponent`中。
<hr/>
{@a q-why-bad}
## Why is it bad if a shared module provides a service to a lazy-loaded module?
## 为什么在共享模块中为惰性加载模块提供服务是个馊主意?
@ -790,7 +767,6 @@ Angular必须把这个惰性加载模块中的提供商添加到*某个*注入
但是它无法将它们添加到应用的根注入器中,因为根注入器已经不再接受新的提供商了。
于是Angular在惰性加载模块的上下文中创建了一个新的子注入器。
<hr/>
{@a q-is-it-loaded}
@ -817,8 +793,8 @@ Here is a custom constructor for an NgModule called `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>
<hr/>
@ -852,7 +828,6 @@ selector doesn't match an element in any component template.
而用于引导的根`AppComponent`则是一个*入口组件*。
虽然它的选择器匹配了`index.html`中的一个元素,但是`index.html`并不是组件模板,而且`AppComponent`选择器也不会在任何组件模板中出现。
Components in route definitions are also _entry components_.
A route definition refers to a component by its _type_.
The router ignores a routed component's selector, if it even has one, and
@ -890,7 +865,6 @@ although doing so is harmless.
不需要把组件同时列在`bootstrap``entryComponent`列表中 —— 虽然这样做也没坏处。
For more information, see [Entry Components](guide/entry-components).
要了解更多,参见[入口组件](guide/entry-components)一章。
@ -928,14 +902,12 @@ in the templates of other components.
虽然把组件加到这个列表中也没什么坏处,不过最好还是只添加真正的*入口组件*。
不要添加那些被其它组件的模板[引用过](guide/ngmodule-faq#q-template-reference)的组件。
For more information, see [Entry Components](guide/entry-components).
要了解更多,参见[入口组件](guide/entry-components)一章。
<hr/>
## Why does Angular need _entryComponents_?
## 为什么 Angular 需要*入口组件*
@ -975,7 +947,6 @@ the compiler omits it.
如果该组件不是*入口组件*或者没有在任何模板中发现过,编译器就会忽略它。
<hr/>
## What kinds of modules should I have and how should I use them?
@ -988,6 +959,7 @@ Some suggestions and guidelines appear to have wide appeal.
每个应用都不一样。根据不同程度的经验,开发者会做出不同的选择。下列建议和指导原则广受欢迎。
### `SharedModule`
`SharedModule` is a conventional name for an `NgModule` with the components, directives, and pipes that you use
everywhere in your app. This module should consist entirely of `declarations`,
most of them exported.
@ -1013,6 +985,7 @@ both those loaded when the app starts and those you lazy load later.
在任何特性模块中(无论是你在应用启动时主动加载的模块还是之后惰性加载的模块),你都可以随意导入这个`SharedModule`
### `CoreModule`
`CoreModule` is a conventional name for an `NgModule` with `providers` for
the singleton services you load when the application starts.
@ -1048,8 +1021,6 @@ would make up the search functionality.
For more information, see [Feature Modules](guide/feature-modules) and
[Module Types](guide/module-types)
## What's the difference between NgModules and JavaScript Modules?
In an Angular app, NgModules and JavaScript modules work together.
@ -1096,8 +1067,11 @@ Angular编译器通过在一个模板的HTML中匹配组件或指令的**选择
The compiler finds a pipe if the pipe's *name* appears within the pipe syntax of the template HTML.
编译器通过分析模板HTML中的管道语法中是否出现了特定的管道名来查找对应的管道。Angular only matches selectors and pipe names for classes that are declared by this module
编译器通过分析模板HTML中的管道语法中是否出现了特定的管道名来查找对应的管道。
Angular only matches selectors and pipe names for classes that are declared by this module
or exported by a module that this module imports.
Angular只查询两种组件、指令或管道1那些在当前模块中声明过的以及2那些被当前模块导入的模块所导出的。
<hr/>
@ -1140,4 +1114,5 @@ the Angular compiler incorporates them into compiled component code too.
`@NgModule` metadata tells the Angular compiler what components to compile for this module and
how to link this module with other modules.
`@NgModule`元数据告诉*Angular编译器*要为当前模块编译哪些组件,以及如何把当前模块和其它模块链接起来。

View File

@ -1,6 +1,7 @@
# JavaScript Modules vs. NgModules
#### Prerequisites
A basic understanding of [JavaScript/ECMAScript modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/).
<hr>
@ -52,15 +53,17 @@ import { AppComponent } from './app.component';
export class AppModule { }
```
The NgModule classes differ from JavaScript module in the following key ways:
* An NgModule bounds [declarable classes](guide/ngmodule-faq#q-declarable) only.
Declarables are the only classes that matter to the [Angular compiler](guide/ngmodule-faq#q-angular-compiler).
* Instead of defining all member classes in one giant file as in a JavaScript module,
you list the module's classes in the `@NgModule.declarations` list.
* An NgModule can only export the [declarable classes](guide/ngmodule-faq#q-declarable)
it owns or imports from other modules. It doesn't declare or export any other kind of class.
* Unlike JavaScript modules, an NgModule can extend the _entire_ application with services
by adding providers to the `@NgModule.providers` list.
@ -69,6 +72,9 @@ by adding providers to the `@NgModule.providers` list.
## More on NgModules
For more information on NgModules, see:
* [Bootstrapping](guide/bootstrapping).
* [Frequently used modules](guide/frequent-ngmodules).
* [Providers](guide/providers).

View File

@ -3,7 +3,11 @@
#### Prerequisites
A basic understanding of the following concepts:
对下列概念有基本的理解:
* [Bootstrapping](guide/bootstrapping).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
<hr>
@ -20,7 +24,6 @@ For an example app showcasing all the techniques that NgModules related pages
cover, see the <live-example></live-example>. For explanations on the individual techniques, visit the relevant NgModule pages under the NgModules
section.
## Angular modularity
Modules are a great way to organize an application and extend it with capabilities from external libraries.
@ -43,8 +46,11 @@ Modules can be loaded eagerly when the application starts or lazy loaded asynchr
NgModule metadata does the following:
* Declares which components, directives, and pipes belong to the module.
* Makes some of those components, directives, and pipes public so that other module's component templates can use them.
* Imports other modules with the components, directives, and pipes that components in the current module need.
* Provides services that the other application components can use.
Every Angular app has at least one module, the root module.
@ -60,6 +66,7 @@ You then import these modules into the root module.
The CLI generates the following basic app module when creating a new app.
<code-example path="bootstrapping/src/app/app.module.ts" region="whole-ngmodule" title="src/app/app.module.ts" linenums="false">
</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).
@ -69,7 +76,11 @@ At the top are the import statements. The next section is where you configure th
## More on NgModules
You may also be interested in the following:
* [Feature Modules](guide/feature-modules).
* [Entry Components](guide/entry-components).
* [Providers](guide/providers).
* [Types of NgModules](guide/module-types).

View File

@ -31,8 +31,8 @@ if they're not already installed on your machine.
by running the commands `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors.
通过在终端/控制台窗口中运行`node -v``npm -v`命令,来**验证下你是否正在使用node `v4.x.x`和npm `3.x.x`**。
过老的版本有可能出现问题
在终端/控制器窗口运行命令`node -v``npm -v`,来**确认你运行的 node 是`v4.x.x`或更高npm 为`3.x.x`或更高。**
老版本会产生错误
Consider using [nvm](https://github.com/creationix/nvm) for managing multiple
versions of node and npm. You may need [nvm](https://github.com/creationix/nvm) if
@ -187,7 +187,6 @@ which polyfills missing features for several popular browser.
**[rxjs](https://github.com/benlesh/RxJS)**:很多 Angular API 都会返回**可观察对象Observable**。RxJS 是个对[Observables规范](https://github.com/zenparsing/es-observable)的当前实现。[TC39](http://www.ecma-international.org/memento/TC39.htm)委员会将来会决定它是否成为 JavaScript 语言标准的一部分。
**[zone.js](https://github.com/angular/zone.js)**: Angular relies on zone.js to run Angular's change detection processes when native JavaScript operations raise events. Zone.js is an implementation of a [specification](https://gist.github.com/mhevery/63fdcdf7c65886051d55) currently before the
[TC39](http://www.ecma-international.org/memento/TC39.htm) committee that determines standards for the JavaScript language.
@ -226,6 +225,10 @@ For example, see the [Angular language service extension for VS Code](https://ma
**[codelyzer](https://www.npmjs.com/package/codelyzer)**:专用于 Angular 应用的 linter它的规则适用于 Angular 的[风格指南](guide/styleguide)。
**jasmine/... **: packages to support the [Jasmine](https://jasmine.github.io/) test library.
**jasmine/... **[Jasmine](https://jasmine.github.io/) 测试库的支持包。
**karma/... **: packages to support the [karma](https://www.npmjs.com/package/karma) test runner.
**karma/... **[karma](https://www.npmjs.com/package/karma) 测试运行器的支持包。
@ -278,4 +281,5 @@ The browser downloads this bundle, not the original package files.
See the [Deployment](guide/deployment) to learn more.
参见[部署](guide/deployment)一章了解详情。

View File

@ -3,7 +3,9 @@
Angular makes use of observables as an interface to handle a variety of common asynchronous operations. For example:
* The `EventEmitter` class extends `Observable`.
* The HTTP module uses observables to handle AJAX requests and responses.
* The Router and Forms modules use observables to listen for and respond to user-input events.
## Event emitter
@ -19,11 +21,15 @@ Here is the component definition:
<code-example path="observables-in-angular/src/main.ts" title="EventEmitter" region="eventemitter"></code-example>
## HTTP
Angulars `HttpClient` returns observables from HTTP method calls. For instance, `http.get(/api)` returns an observable. This provides several advantages over promise-based HTTP APIs:
* Observables do not mutate the server response (as can occur through chained `.then()` calls on promises). Instead, you can use a series of operators to transform values as needed.
* HTTP requests are cancellable through the `unsubscribe()` method.
* Requests can be configured to get progress event updates.
* Failed requests can be retried easily.
## Async pipe
@ -36,6 +42,8 @@ The following example binds the `time` observable to the component's view. The o
## Router
## 路由器 (router)
[`Router.events`](https://angular.io/api/router/Router#events) provides events as observables. You can use the `filter()` operator from RxJS to look for events of interest, and subscribe to them in order to make decisions based on the sequence of events in the navigation process. Here's an example:
<code-example path="observables-in-angular/src/main.ts" title="Router events" region="router"></code-example>
@ -46,6 +54,9 @@ The [ActivatedRoute](https://angular.io/api/router/ActivatedRoute) is an injecte
## Reactive forms
## 响应式表单 (reactive forms)
Reactive forms have properties that use observables to monitor form control values. The [`FormControl`](https://angular.io/api/forms/FormControl) properties `valueChanges` and `statusChanges` contain observables that raise change events. Subscribing to an observable form-control property is a way of triggering application logic within the component class. For example:
<code-example path="observables-in-angular/src/main.ts" title="Reactive forms" region="forms"></code-example>

View File

@ -39,6 +39,7 @@ An `Observable` instance begins publishing values only when someone subscribes t
In order to show how subscribing works, we need to create a new observable. There is a constructor that you use to create new instances, but for illustration, we can use some static methods on the `Observable` class that create simple observables of frequently used types:
* `Observable.of(...items)`&mdash;Returns an `Observable` instance that synchronously delivers the values provided as arguments.
* `Observable.from(iterable)`&mdash;Converts its argument to an `Observable` instance. This method is commonly used to convert an array to an observable.
</div>
@ -48,7 +49,9 @@ Here's an example of creating and subscribing to a simple observable, with an ob
<code-example
path="observables/src/subscribing.ts"
region="observer"
title="Subscribe using observer"></code-example>
title="Subscribe using observer">
</code-example>
Alternatively, the `subscribe()` method can accept callback function definitions in line, for `next`, `error`, and `complete` handlers. For example, the following `subscribe()` call is the same as the one that specifies the predefined observer:
@ -97,18 +100,24 @@ Notice that if you subscribe twice, there will be two separate streams, each emi
<code-example path="observables/src/multicasting.ts" region="multicast_sequence" title="Create a multicast subscriber"></code-example>
<div class="l-sub-section">
Multicasting observables take a bit more setup, but they can be useful for certain applications. Later we will look at tools that simplify the process of multicasting, allowing you to take any observable and make it multicasting.
</div>
## Error handling
## 错误处理
Because observables produce values asynchronously, try/catch will not effectively catch errors. Instead, you handle errors by specifying an `error` callback on the observer. Producing an error also causes the observable to clean up subscriptions and stop producing values. An observable can either produce values (calling the `next` callback), or it can complete, calling either the `complete` or `error` callback.
<code-example>
myObservable.subscribe({
next(num) { console.log('Next num: ' + num)},
error(err) { console.log('Received an errror: ' + err)}
});
</code-example>
Error handling (and specifically recovering from an error) is covered in more detail in a later section.

View File

@ -32,8 +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.
试试<live-example>在线例子</live-example>
运行<live-example></live-example>来试用本页的代码。
## Using pipes
@ -46,24 +45,18 @@ a human-friendly date.
管道把数据作为输入,然后转换它,给出期望的输出。
我们将把组件的`birthday`属性转换成对人类更友好的日期格式,来说明这一点:
<code-example path="pipes/src/app/hero-birthday1.component.ts" title="src/app/hero-birthday1.component.ts" linenums="false">
</code-example>
Focus on the component's template.
重点看下组件的模板。
<code-example path="pipes/src/app/app.component.html" region="hero-birthday-template" title="src/app/app.component.html" linenums="false">
</code-example>
Inside the interpolation expression, you flow the component's `birthday` value through the
[pipe operator](guide/template-syntax#pipe) ( | ) to the [Date pipe](api/common/DatePipe)
function on the right. All pipes work this way.
@ -82,11 +75,8 @@ They are all available for use in any template.
Angular内置了一些管道比如`DatePipe``UpperCasePipe``LowerCasePipe``CurrencyPipe``PercentPipe`
它们全都可以直接用在任何模板中。
<div class="l-sub-section">
Read more about these and many other built-in pipes in the [pipes topics](api?type=pipe) of the
[API Reference](api); filter for entries that include the word "pipe".
@ -96,12 +86,8 @@ Angular doesn't have a `FilterPipe` or an `OrderByPipe` for reasons explained in
Angular没有`FilterPipe``OrderByPipe`管道,原因在[后面的附录中](guide/pipes#no-filter-pipe)有解释。
</div>
## Parameterizing a pipe
## 对管道进行参数化
@ -120,13 +106,10 @@ After formatting the hero's April 15th birthday, it renders as **<samp>04/15/88<
我们将通过修改生日模板来给这个日期管道提供一个格式化参数。
当格式化完该英雄的4月15日生日之后它应该被渲染成**<samp>04/15/88</samp>**。
<code-example path="pipes/src/app/app.component.html" region="format-birthday" title="src/app/app.component.html" linenums="false">
</code-example>
The parameter value can be any valid template expression,
(see the [Template expressions](guide/template-syntax#template-expressions) section of the
[Template Syntax](guide/template-syntax) page)
@ -141,13 +124,10 @@ to the component's `format` property. Here's the template for that component:
我们来写第二个组件,它把管道的格式参数*绑定*到该组件的`format`属性。这里是新组件的模板:
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="template" title="src/app/hero-birthday2.component.ts (template)" linenums="false">
</code-example>
You also added a button to the template and bound its click event to the component's `toggleFormat()` method.
That method toggles the component's `format` property between a short form
(`'shortDate'`) and a longer form (`'fullDate'`).
@ -155,40 +135,31 @@ That method toggles the component's `format` property between a short form
我们还能在模板中添加一个按钮,并把它的点击事件绑定到组件的`toggleFormat()`方法。
此方法会在短日期格式(`'shortDate'`)和长日期格式(`'fullDate'`)之间切换组件的`format`属性。
<code-example path="pipes/src/app/hero-birthday2.component.ts" region="class" title="src/app/hero-birthday2.component.ts (class)" linenums="false">
</code-example>
As you click the button, the displayed date alternates between
"**<samp>04/15/1988</samp>**" and
"**<samp>Friday, April 15, 1988</samp>**".
当我们点击按钮的时候,显示的日志会在“**<samp>04/15/1988</samp>**”和“**<samp>Friday, April 15, 1988</samp>**”之间切换。
<figure>
<img src='generated/images/guide/pipes/date-format-toggle-anim.gif' alt="Date Format Toggle">
</figure>
<div class="l-sub-section">
Read more about the `DatePipe` format options in the [Date Pipe](api/common/DatePipe)
API Reference page.
要了解更多`DatePipes`的格式选项,请参阅[API文档](api/common/DatePipe)。
</div>
## Chaining pipes
## 链式管道
@ -202,26 +173,19 @@ The birthday displays as **<samp>APR 15, 1988</samp>**.
下面这个例子中,我们把`birthday`链到`DatePipe`管道,然后又链到`UpperCasePipe`,这样我们就可以把生日显示成大写形式了。
比如下面的代码就会把生日显示成**<samp>APR 15, 1988</samp>**
<code-example path="pipes/src/app/app.component.html" region="chained-birthday" title="src/app/app.component.html" linenums="false">
</code-example>
This example&mdash;which displays **<samp>FRIDAY, APRIL 15, 1988</samp>**&mdash;chains
the same pipes as above, but passes in a parameter to `date` as well.
下面这个显示**<samp>FRIDAY, APRIL 15, 1988</samp>**的例子用同样的方式链接了这两个管道,而且同时还给`date`管道传进去一个参数。
<code-example path="pipes/src/app/app.component.html" region="chained-parameter-birthday" title="src/app/app.component.html" linenums="false">
</code-example>
## Custom pipes
## 自定义管道
@ -232,13 +196,10 @@ Here's a custom pipe named `ExponentialStrengthPipe` that can boost a hero's pow
我们还可以写自己的自定义管道。
下面就是一个名叫`ExponentialStrengthPipe`的管道,它可以放大英雄的能力:
<code-example path="pipes/src/app/exponential-strength.pipe.ts" title="src/app/exponential-strength.pipe.ts" linenums="false">
</code-example>
This pipe definition reveals the following key points:
在这个管道的定义中体现了几个关键点:
@ -269,11 +230,8 @@ Your pipe has one such parameter: the `exponent`.
这个`@Pipe`装饰器允许我们定义管道的名字这个名字会被用在模板表达式中。它必须是一个有效的JavaScript标识符。
比如,我们这个管道的名字是`exponentialStrength`
<div class="l-sub-section">
## The *PipeTransform* interface
## *PipeTransform*接口
@ -286,23 +244,22 @@ Technically, it's optional; Angular looks for and executes the `transform` metho
`PipeTransform`*接口*中定义了它,并用它指导各种工具和编译器。
理论上说它是可选的。Angular不会管它而是直接查找并执行`transform`方法。
</div>
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>
<figure>
<img src='generated/images/guide/pipes/power-booster.png' alt="Power Booster">
</figure>
Note the following:
要注意的有两点:
@ -315,21 +272,16 @@ Note the following:
我们必须在`AppModule``declarations`数组中包含这个管道。
<div class="callout is-helpful">
<header>
Remember the declarations array
</header>
<header>
别忘了`declarations`数组
</header>
You must register custom pipes.
If you don't, Angular reports an error.
Angular CLI's generator registers the pipe automatically.
@ -337,11 +289,8 @@ Angular CLI's generator registers the pipe automatically.
我们必须手动注册自定义管道。如果忘了Angular就会报告一个错误。
在前一个例子中我们没有把`DatePipe`列进去这是因为Angular所有的内置管道都已经预注册过了。
</div>
To probe the behavior in the <live-example></live-example>,
change the value and optional exponent in the template.
@ -358,23 +307,18 @@ your pipe and two-way data binding with `ngModel`.
仅仅升级模板来测试这个自定义管道其实没多大意思。
我们干脆把这个例子升级为“能力倍增计算器”,它可以把该管道和使用`ngModel`的双向数据绑定组合起来。
<code-example path="pipes/src/app/power-boost-calculator.component.ts" title="src/app/power-boost-calculator.component.ts">
</code-example>
<figure>
<img src='generated/images/guide/pipes/power-boost-calculator-anim.gif' alt="Power Boost Calculator">
</figure>
{@a change-detection}
## Pipes and change detection
## 管道与变更检测
@ -397,24 +341,18 @@ its display of every hero in the `heroes` array. Here's the template:
我们下一个例子中的组件使用默认的、激进(昂贵)的变更检测策略来检测和更新`heroes`数组中的每个英雄。下面是它的模板:
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-1" title="src/app/flying-heroes.component.html (v1)" linenums="false">
</code-example>
The companion component class provides heroes, adds heroes into the array, and can reset the array.
和模板相伴的组件类可以提供英雄数组,能把新的英雄添加到数组中,还能重置英雄数组。
<code-example path="pipes/src/app/flying-heroes.component.ts" region="v1" title="src/app/flying-heroes.component.ts (v1)" linenums="false">
</code-example>
You can add heroes and Angular updates the display when you do.
If you click the `reset` button, Angular replaces `heroes` with a new array of the original heroes and updates the display.
If you added the ability to remove or change a hero, Angular would detect those changes and update the display as well.
@ -431,24 +369,18 @@ Add a `FlyingHeroesPipe` to the `*ngFor` repeater that filters the list of heroe
我们来往`*ngFor`重复器中添加一个`FlyingHeroesPipe`管道,这个管道能过滤出所有会飞的英雄。
<code-example path="pipes/src/app/flying-heroes.component.html" region="template-flying-heroes" title="src/app/flying-heroes.component.html (flyers)" linenums="false">
</code-example>
Here's the `FlyingHeroesPipe` implementation, which follows the pattern for custom pipes described earlier.
下面是`FlyingHeroesPipe`的实现,它遵循了我们以前见过的那些写自定义管道的模式。
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pure" title="src/app/flying-heroes.pipe.ts" linenums="false">
</code-example>
Notice the odd behavior in the <live-example></live-example>:
when you add flying heroes, none of them are displayed under "Heroes who fly."
@ -464,13 +396,10 @@ Notice how a hero is added:
来看看我们是如何添加新英雄的:
<code-example path="pipes/src/app/flying-heroes.component.ts" region="push" title="src/app/flying-heroes.component.ts" linenums="false">
</code-example>
You add the hero into the `heroes` array. The reference to the array hasn't changed.
It's the same array. That's all Angular cares about. From its perspective, *same array, no change, no display update*.
@ -493,13 +422,12 @@ code with checkbox switches and additional displays to help you experience these
如果我们**替换了**这个数组,管道就会被执行,显示也更新了。
这个*飞行英雄*的例子用检查框和其它显示内容扩展了原有代码,来帮我们体验这些效果。
<figure>
<img src='generated/images/guide/pipes/flying-heroes-anim.gif' alt="Flying Heroes">
</figure>
Replacing the array is an efficient way to signal Angular to update the display.
When do you replace the array? When the data change.
That's an easy rule to follow in *this* example
@ -525,8 +453,6 @@ For filtering flying heroes, consider an *impure pipe*.
为了过滤会飞的英雄,我们要使用*非纯(impure)管道*。
## Pure and impure pipes
## 纯(pure)管道与非纯(impure)管道
@ -540,13 +466,10 @@ impure like this:
默认情况下,管道都是纯的。我们以前见到的每个管道都是纯的。
通过把它的`pure`标志设置为`false`,我们可以制作一个非纯管道。我们可以像这样让`FlyingHeroesPipe`变成非纯的:
<code-example path="pipes/src/app/flying-heroes.pipe.ts" region="pipe-decorator" title="src/app/flying-heroes.pipe.ts" linenums="false">
</code-example>
Before doing that, understand the difference between pure and impure, starting with a pure pipe.
在继续往下走之前,我们先理解一下*纯*和*非纯*之间的区别,从*纯*管道开始。
@ -583,11 +506,8 @@ When you can't, you *can* use the impure pipe.
因此,如果我们要和变更检测策略打交道,就会更喜欢用纯管道。
如果不能,我们就*可以*转回到非纯管道。
<div class="l-sub-section">
Or you might not use a pipe at all.
It may be better to pursue the pipe's purpose with a property of the component,
a point that's discussed later in this page.
@ -598,8 +518,6 @@ a point that's discussed laterin this page.
</div>
<h3 class="no-toc">Impure pipes</h3>
### 非纯管道
@ -616,13 +534,11 @@ An expensive, long-running pipe could destroy the user experience.
要在脑子里绷着这根弦,我们必须小心翼翼的实现非纯管道。
一个昂贵、迟钝的管道将摧毁用户体验。
{@a impure-flying-heroes}
<h3 class="no-toc">An impure <i>FlyingHeroesPipe</i></h3>
### 非纯版本的*FlyingHeroesPipe*
<h3 class="no-toc">非纯管道 <i>FlyingHeroesPipe</i></h3>
A flip of the switch turns the `FlyingHeroesPipe` into a `FlyingHeroesImpurePipe`.
The complete implementation is as follows:
@ -630,7 +546,6 @@ The complete implementation is as follows:
我们把`FlyingHeroesPipe`换成了`FlyingHeroesImpurePipe`
下面是完整的实现:
<code-tabs>
<code-pane title="FlyingHeroesImpurePipe" path="pipes/src/app/flying-heroes.pipe.ts" region="impure">
@ -643,8 +558,6 @@ The complete implementation is as follows:
</code-tabs>
You inherit from `FlyingHeroesPipe` to prove the point that nothing changed internally.
The only difference is the `pure` flag in the pipe metadata.
@ -655,25 +568,18 @@ This is a good candidate for an impure pipe because the `transform` function is
这是一个很好地非纯管道候选者,因为它的`transform`函数又小又快。
<code-example path="pipes/src/app/flying-heroes.pipe.ts" linenums="false" title="src/app/flying-heroes.pipe.ts (filter)" region="filter">
</code-example>
You can derive a `FlyingHeroesImpureComponent` from `FlyingHeroesComponent`.
我们可以从`FlyingHeroesComponent`派生出一个`FlyingHeroesImpureComponent`
<code-example path="pipes/src/app/flying-heroes-impure.component.html" linenums="false" title="src/app/flying-heroes-impure.component.html (excerpt)" region="template-flying-heroes">
</code-example>
The only substantive change is the pipe in the template.
You can confirm in the <live-example></live-example> that the _flying heroes_
display updates as you add heroes, even when you mutate the `heroes` array.
@ -681,16 +587,11 @@ display updates as you add heroes, even when you mutate the `heroes` array.
唯一的重大改动就是管道。
我们可以在<live-example></live-example>中确认,当我们输入新的英雄甚至修改#[code heroes]数组时,这个#[i 会飞的英雄]的显示也跟着更新了。
{@a async-pipe}
<h3 class="no-toc">The impure <i>AsyncPipe</i></h3>
<h3 id='async-pipe'>
非纯 <i>AsyncPipe</i>
</h3>
<h3 class="no-toc">非纯管道 <i>AsyncPipe</i></h3>
The Angular `AsyncPipe` is an interesting example of an impure pipe.
The `AsyncPipe` accepts a `Promise` or `Observable` as input
@ -711,13 +612,10 @@ This next example binds an `Observable` of message strings
在下面例子中,我们使用该`async`管道把一个消息字符串(`message$`)的`Observable`绑定到视图中。
<code-example path="pipes/src/app/hero-async-message.component.ts" title="src/app/hero-async-message.component.ts">
</code-example>
The Async pipe saves boilerplate in the component code.
The component doesn't have to subscribe to the async data source,
extract the resolved values and expose them for binding,
@ -748,36 +646,29 @@ The code uses the [Angular http](guide/http) client to retrieve data:
这个管道只有当所请求的URL发生变化时才会向服务器发起请求。它会缓存服务器的响应。
代码如下,它使用[Angular http](guide/http)客户端来接收数据
<code-example path="pipes/src/app/fetch-json.pipe.ts" title="src/app/fetch-json.pipe.ts">
</code-example>
Now demonstrate it in a harness component whose template defines two bindings to this pipe,
both requesting the heroes from the `heroes.json` file.
接下来我们用一个测试台组件演示一下它,该组件的模板中定义了两个使用到此管道的绑定,他们都从`heroes.json`文件中取得英雄数据。
<code-example path="pipes/src/app/hero-list.component.ts" title="src/app/hero-list.component.ts">
</code-example>
The component renders as the following:
组件渲染起来是这样的:
<figure>
<img src='generated/images/guide/pipes/hero-list.png' alt="Hero List">
</figure>
A breakpoint on the pipe's request for data shows the following:
这个管道上的断点请求数据的过程显示:
@ -802,40 +693,29 @@ It displays the same hero data in JSON format by chaining through to the built-i
第二个绑定除了用到`FetchPipe`之外还链接了更多管道。
我们把获取数据的结果同时显示在第一个绑定和第二个绑定中。第二个绑定中,我们通过链接到一个内置管道`JsonPipe`把它转成了JSON格式。
<div class="callout is-helpful">
<header>
Debugging with the json pipe
</header>
<header>
借助json管道进行调试
</header>
The [JsonPipe](api/common/JsonPipe)
provides an easy way to diagnosis a mysteriously failing data binding or
inspect an object for future binding.
[JsonPipe](api/common/JsonPipe)为你诊断数据绑定的某些神秘错误或为做进一步绑定而探查数据时,提供了一个简单途径。
</div>
{@a pure-pipe-pure-fn}
<h3 class="no-toc">Pure pipes and pure functions</h3>
### 纯管道与纯函数
<h3 class="no-toc">纯管道与纯函数</h3>
A pure pipe uses pure functions.
Pure functions process inputs and return values without detectable side effects.
@ -861,8 +741,6 @@ Otherwise, you'll see many console errors regarding expressions that changed aft
但是一个*纯管道*必须总是用*纯函数*实现。忽略这个警告将导致失败并带来一大堆这样的控制台错误:表达式在被检查后被变更。
## Next steps
## 下一步
@ -880,11 +758,8 @@ Try writing a custom pipe and perhaps contributing it to the community.
要浏览Angular的所有内置管道请到[API参考手册](api?type=pipe)。
学着写写自定义管道,并贡献给开发社区。
{@a no-filter-pipe}
## Appendix: No *FilterPipe* or *OrderByPipe*
## 附录:没有*FilterPipe*或者*OrderByPipe*
@ -922,15 +797,13 @@ The list might be sorted by hero `name` and `planet` of origin properties in the
虽然不是很明显,但代码最小化方面也存在风险。想象一个用于英雄列表的排序管道。我们可能根据英雄原始属性中的`name``planet`进行排序,就像这样:
<code-example language="html">
&lt;!-- NOT REAL CODE! -->
&lt;div *ngFor="let hero of heroes | orderBy:'name,planet'">&lt;/div>
</code-example>
You identify the sort fields by text strings, expecting the pipe to reference a property value by indexing
(such as `hero['name']`).
Unfortunately, aggressive minification manipulates the `Hero` property names so that `Hero.name` and `Hero.planet`
@ -962,4 +835,5 @@ Angular开发组和一些有经验的Angular开发者强烈建议你把你的
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.
如果你不需要顾虑这些性能和最小化问题,也可以创建自己的管道来实现这些功能(参考[FlyingHeroesPipe](guide/pipes#impure-flying-heroes)中的写法)或到社区中去找找。

View File

@ -7,9 +7,13 @@ Here are some examples of domains in which observables are particularly useful.
Observables can simplify the implementation of type-ahead suggestions. Typically, a type-ahead has to do a series of separate tasks:
* Listen for data from an input.
* Trim the value (remove whitespace) and make sure its a minimum length.
* Debounce (so as not to send off API requests for every keystroke, but instead wait for a break in keystrokes).
* Dont send a request if the value stays the same (rapidly hit a character, then backspace, for instance).
* Cancel ongoing AJAX requests if their results will be invalidated by the updated results.
Writing this in full JavaScript can be quite involved. With observables, you can use a simple series of RxJS operators:
@ -21,3 +25,4 @@ Writing this in full JavaScript can be quite involved. With observables, you can
Exponential backoff is a technique in which you retry an API after failure, making the time in between retries longer after each consecutive failure, with a maximum number of retries after which the request is considered to have failed. This can be quite complex to implement with promises and other methods of tracking AJAX calls. With observables, it is very easy:
<code-example path="practical-observable-usage/src/backoff.ts" title="Exponential backoff"></code-example>

View File

@ -1,7 +1,11 @@
# Providers
#### Prerequisites:
#### 前提条件:
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Frequently Used Modules](guide/frequent-ngmodules).
For the final sample app using the provider that this page describes,
@ -10,6 +14,7 @@ see the <live-example></live-example>.
<hr>
## Create a service
You can provide services to your app by using the `providers` array in an NgModule.
Consider the default app generated by the CLI. In order to add a user service to it,
you can generate one by entering the following command in the terminal window:
@ -23,14 +28,13 @@ app's injector. Update `app.module.ts` by importing it with your other import st
of the file and adding it to the `providers` array:
<code-example path="providers/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example>
</code-example>
## Provider scope
When you add a service provider to the `providers` array of the root module, its available throughout the app. Additionally, when you import a module that has providers, those providers are also available to all the classes in the app as long they have the lookup token. For example, if you import the `HttpClientModule` into your `AppModule`, its providers are then available to the entire app and you can make HTTP requests from anywhere in your app.
## Limiting provider scope by lazy loading modules
In the basic CLI generated app, modules are eagerly loaded which means that they are all loaded when the app launches. Angular uses an injector system to make things available between modules. In an eagerly loaded app, the root application injector makes all of the providers in all of the modules available throughout the app.
@ -45,7 +49,6 @@ Any component created within a lazy loaded modules context, such as by router
Though you can provide services by lazy loading modules, not all services can be lazy loaded. For instance, some modules only work in the root module, such as the Router. The Router works with the global location object in the browser.
## Limiting provider scope with components
Another way to limit provider scope is by adding the service you want to limit to the components
@ -55,8 +58,8 @@ Providing a service in the component limits the service only to that component (
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>
</code-example>
## Providing services in modules vs. components
@ -67,12 +70,14 @@ The router works at the root level so if you put providers in a component, even
<!-- KW--Make a diagram here -->
Register a provider with a component when you must limit a service instance to a component and its component tree, that is, its child components. For example, a user editing component, `UserEditorComponent`, that needs a private copy of a caching `UserService` should register the `UserService` with the `UserEditorComponent`. Then each new instance of the `UserEditorComponent` gets its own cached service instance.
<hr>
## More on NgModules
You may also be interested in:
* [Singleton Services](guide/singleton-services), which elaborates on the concepts covered on this page.
* [Lazy Loading Modules](guide/lazy-loading-ngmodules).
* [NgModule FAQ](guide/ngmodule-faq).

View File

@ -30,17 +30,13 @@ And you can also <a href="generated/zips/cli-quickstart/cli-quickstart.zip" targ
你还可以 <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">下载这个例子。</a>
<h2 id='devenv'>
Step 1. Set up the Development Environment
</h2>
<h2 id='devenv'>
步骤1. 设置开发环境
</h2>
You need to set up your development environment before you can do anything.
在开始工作之前,我们必须设置好开发环境。
@ -48,13 +44,10 @@ You need to set up your development environment before you can do anything.
Install **[Node.js® and npm](https://nodejs.org/en/download/)**
if they are not already on your machine.
如果你的机器上还没有**[Node.js®和npm](https://nodejs.org/en/download/)**,请先安装它们。
如果你的电脑里没有Node.js®和npm请安装**[它们](https://nodejs.org/en/download/)**。
<div class="l-sub-section">
**Verify that you are running at least node `6.9.x` and npm `3.x.x`**
by running `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors, but newer versions are fine.
@ -63,90 +56,69 @@ Older versions produce errors, but newer versions are fine.
**来验证一下你正在运行 node `6.9.x` 和 npm `3.x.x` 以上的版本。**
更老的版本可能会出现错误,更新的版本则没问题。
</div>
Then **install the [Angular CLI](https://github.com/angular/angular-cli)** globally.
然后全局安装 **[Angular CLI](https://github.com/angular/angular-cli)** 。
<code-example language="sh" class="code-shell">
npm install -g @angular/cli
</code-example>
<h2 id='create-proj'>
Step 2. Create a new project
</h2>
<h2 id='create-proj'>
步骤2. 创建新项目
</h2>
Open a terminal window.
打开终端窗口。
Generate a new project and skeleton application by running the following commands:
运行下列命令来生成一个新项目以及应用的骨架代码:
<code-example language="sh" class="code-shell">
ng new my-app
</code-example>
<div class="l-sub-section">
Patience, please.
It takes time to set up a new project; most of it is spent installing npm packages.
请耐心等待。
创建新项目需要花费很多时间大多数时候都是在安装那些npm包。
</div>
<h2 id='serve'>
Step 3: Serve the application
</h2>
<h2 id='serve'>
步骤3. 启动开发服务器
</h2>
</h2>
Go to the project directory and launch the server.
进入项目目录,并启动服务器。
<code-example language="sh" class="code-shell">
cd my-app
ng serve --open
</code-example>
The `ng serve` command launches the server, watches your files,
and rebuilds the app as you make changes to those files.
@ -162,24 +134,19 @@ Your app greets you with a message:
本应用会用一条消息来跟你打招呼:
<figure>
<img src='generated/images/guide/cli-quickstart/app-works.png' alt="The app works!">
</figure>
<h2 id='first-component'>
Step 4: Edit your first Angular component
</h2>
<h2 id='first-component'>
步骤4. 编辑我们的第一个Angular组件
</h2>
The CLI created the first Angular component for you.
This is the _root component_ and it is named `app-root`.
You can find it in `./src/app/app.component.ts`.
@ -194,8 +161,6 @@ Open the component file and change the `title` property from _Welcome to app!!_
<code-example path="cli-quickstart/src/app/app.component.ts" region="title" title="src/app/app.component.ts" linenums="false"></code-example>
The browser reloads automatically with the revised title. That's nice, but it could look better.
浏览器会自动刷新,而我们会看到修改之后的标题。不错,不过它还可以更好看一点。
@ -206,20 +171,16 @@ Open `src/app/app.component.css` and give the component some style.
<code-example path="cli-quickstart/src/app/app.component.css" title="src/app/app.component.css" linenums="false"></code-example>
<figure>
<img src='generated/images/guide/cli-quickstart/my-first-app.png' alt="Output of QuickStart app">
</figure>
Looking good!
漂亮!
## What's next?
## 接下来呢?
@ -237,8 +198,6 @@ Or you can stick around a bit longer to learn about the files in your brand new
或者,你也可以稍等一会儿,学学在这个新项目中的文件都是干什么用的。
## Project file review
## 项目文件概览
@ -262,8 +221,6 @@ Some of the generated files might be unfamiliar to you.
有些生成的文件你可能觉得陌生。接下来我们就讲讲它们。
### The `src` folder
### `src`文件夹
@ -276,71 +233,110 @@ Any files outside of this folder are meant to support building your app.
所有的Angular组件、模板、样式、图片以及你的应用所需的任何东西都在那里。
这个文件夹之外的文件都是为构建应用提供支持用的。
<div class='filetree'>
<div class='file'>src</div>
<div class='children'>
<div class='file'>app</div>
<div class='children'>
<div class='file'>app.component.css</div>
<div class='file'>app.component.html</div>
<div class="file">app.component.spec.ts</div>
<div class="file">app.component.ts</div>
<div class="file">app.module.ts</div>
</div>
<div class="file">assets</div>
<div class='children'>
<div class="file">.gitkeep</div>
</div>
<div class="file">environments</div>
<div class='children'>
<div class="file">environment.prod.ts</div>
<div class="file">environment.ts</div>
</div>
<div class="file">favicon.ico</div>
<div class="file">index.html</div>
<div class="file">main.ts</div>
<div class="file">polyfills.ts</div>
<div class="file">styles.css</div>
<div class="file">test.ts</div>
<div class="file">tsconfig.app.json</div>
<div class="file">tsconfig.spec.json</div>
</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
文件
</th>
<th>
Purpose
用途
</th>
</tr>
<tr>
<td>
`app/app.component.{ts,html,css,spec.ts}`
</td>
<td>
Defines the `AppComponent` along with an HTML template, CSS stylesheet, and a unit test.
@ -351,45 +347,58 @@ Any files outside of this folder are meant to support building your app.
它是**根**组件,随着应用的成长它会成为一棵组件树的根节点。
</td>
</tr>
<tr>
<td>
`app/app.module.ts`
</td>
<td>
Defines `AppModule`, the [root module](guide/bootstrapping "AppModule: the root module") that tells Angular how to assemble the application.
Right now it declares only the `AppComponent`.
Soon there will be more components to declare.
定义`AppModule`这个[根模块](guide/bootstrapping "AppModule: 根模块")会告诉Angular如何组装该应用。
定义`AppModule`[根模块](guide/bootstrapping "AppModule: 根模块")为 Angular 描述如何组装应用。
目前,它只声明了`AppComponent`
稍后它还会声明更多组件。
不久,它将声明更多组件。
</td>
</tr>
<tr>
<td>
`assets/*`
</td>
<td>
A folder where you can put images and anything else to be copied wholesale
when you build your application.
这个文件夹下你可以放图片等任何东西,在构建应用时,它们全都会拷贝到发布包中。
</td>
</tr>
<tr>
<td>
`environments/*`
</td>
<td>
This folder contains one file for each of your destination environments,
@ -407,13 +416,17 @@ Any files outside of this folder are meant to support building your app.
所有这些CLI都替你考虑到了。
</td>
</tr>
<tr>
<td>
`favicon.ico`
</td>
<td>
Every site wants to look good on the bookmark bar.
@ -421,14 +434,19 @@ Any files outside of this folder are meant to support building your app.
每个网站都希望自己在书签栏中能好看一点。
请把它换成你自己的图标。
</td>
</tr>
<tr>
<td>
`index.html`
</td>
<td>
The main HTML page that is served when someone visits your site.
@ -441,13 +459,17 @@ Any files outside of this folder are meant to support building your app.
在构建应用时CLI会自动把所有`js``css`文件添加进去,所以你不必在这里手动添加任何 `<script>``<link>` 标签。
</td>
</tr>
<tr>
<td>
`main.ts`
</td>
<td>
The main entry point for your app.
@ -461,13 +483,17 @@ Any files outside of this folder are meant to support building your app.
你还可以使用[AOT compiler](guide/glossary#ahead-of-time-aot-compilation)编译器,而不用修改任何代码 —— 只要给`ng build``ng serve` 传入 `--aot` 参数就可以了。
</td>
</tr>
<tr>
<td>
`polyfills.ts`
</td>
<td>
Different browsers have different levels of support of the web standards.
@ -480,13 +506,17 @@ Any files outside of this folder are meant to support building your app.
你只要使用`core-js``zone.js`通常就够了,不过你也可以查看[浏览器支持指南](guide/browser-support)以了解更多信息。
</td>
</tr>
<tr>
<td>
`styles.css`
</td>
<td>
Your global styles go here.
@ -497,13 +527,17 @@ Any files outside of this folder are meant to support building your app.
大多数情况下,你会希望在组件中使用局部样式,以利于维护,不过那些会影响你整个应用的样式你还是需要集中存放在这里。
</td>
</tr>
<tr>
<td>
`test.ts`
</td>
<td>
This is the main entry point for your unit tests.
@ -514,12 +548,17 @@ Any files outside of this folder are meant to support building your app.
它有一些你不熟悉的自定义配置,不过你并不需要编辑这里的任何东西。
</td>
</tr>
<tr>
<td>
`tsconfig.{app|spec}.json`
</td>
<td>
TypeScript compiler configuration for the Angular app (`tsconfig.app.json`)
@ -528,7 +567,9 @@ Any files outside of this folder are meant to support building your app.
TypeScript编译器的配置文件。`tsconfig.app.json`是为Angular应用准备的`tsconfig.spec.json`是为单元测试准备的。
</td>
</tr>
</table>
### The root folder
@ -542,62 +583,94 @@ These files go in the root folder next to `src/`.
`src/`文件夹是项目的根文件夹之一。
其它文件是用来帮助你构建、测试、维护、文档化和发布应用的。它们放在根目录下,和`src/`平级。
<div class='filetree'>
<div class="file">my-app</div>
<div class='children'>
<div class="file">e2e</div>
<div class='children'>
<div class="file">app.e2e-spec.ts</div>
<div class="file">app.po.ts</div>
<div class="file">tsconfig.e2e.json</div>
</div>
<div class="file">node_modules/...</div>
<div class="file">src/...</div>
<div class="file">.angular-cli.json</div>
<div class="file">.editorconfig</div>
<div class="file">.gitignore</div>
<div class="file">karma.conf.js</div>
<div class="file">package.json</div>
<div class="file">protractor.conf.js</div>
<div class="file">README.md</div>
<div class="file">tsconfig.json</div>
<div class="file">tslint.json</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
文件
</th>
<th>
Purpose
用途
</th>
</tr>
<tr>
<td>
`e2e/`
</td>
<td>
Inside `e2e/` live the end-to-end tests.
@ -610,13 +683,17 @@ These files go in the root folder next to `src/`.
这也就是为什么它会拥有自己的`tsconfig.json`
</td>
</tr>
<tr>
<td>
`node_modules/`
</td>
<td>
`Node.js` creates this folder and puts all third party modules listed in
@ -625,13 +702,17 @@ These files go in the root folder next to `src/`.
`Node.js`创建了这个文件夹,并且把`package.json`中列举的所有第三方模块都放在其中。
</td>
</tr>
<tr>
<td>
`.angular-cli.json`
</td>
<td>
Configuration for Angular CLI.
@ -644,13 +725,17 @@ These files go in the root folder next to `src/`.
要了解更多,请参阅它的官方文档。
</td>
</tr>
<tr>
<td>
`.editorconfig`
</td>
<td>
Simple configuration for your editor to make sure everyone that uses your project
@ -662,13 +747,17 @@ These files go in the root folder next to `src/`.
大多数的编辑器都支持`.editorconfig`文件,详情参见 http://editorconfig.org 。
</td>
</tr>
<tr>
<td>
`.gitignore`
</td>
<td>
Git configuration to make sure autogenerated files are not commited to source control.
@ -676,13 +765,17 @@ These files go in the root folder next to `src/`.
一个Git的配置文件用来确保某些自动生成的文件不会被提交到源码控制系统中。
</td>
</tr>
<tr>
<td>
`karma.conf.js`
</td>
<td>
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
@ -691,13 +784,17 @@ These files go in the root folder next to `src/`.
给[Karma](https://karma-runner.github.io)的单元测试配置,当运行`ng test`时会用到它。
</td>
</tr>
<tr>
<td>
`package.json`
</td>
<td>
`npm` configuration listing the third party packages your project uses.
@ -707,13 +804,17 @@ These files go in the root folder next to `src/`.
你还可以在这里添加自己的[自定义脚本](https://docs.npmjs.com/misc/scripts)。
</td>
</tr>
<tr>
<td>
`protractor.conf.js`
</td>
<td>
End-to-end test configuration for [Protractor](http://www.protractortest.org/),
@ -722,13 +823,17 @@ These files go in the root folder next to `src/`.
给[Protractor](http://www.protractortest.org/)使用的端到端测试配置文件,当运行`ng e2e`的时候会用到它。
</td>
</tr>
<tr>
<td>
`README.md`
</td>
<td>
Basic documentation for your project, pre-filled with CLI command information.
@ -739,13 +844,17 @@ These files go in the root folder next to `src/`.
别忘了用项目文档改进它,以便每个查看此仓库的人都能据此构建出你的应用。
</td>
</tr>
<tr>
<td>
`tsconfig.json`
</td>
<td>
TypeScript compiler configuration for your IDE to pick up and give you helpful tooling.
@ -753,13 +862,17 @@ These files go in the root folder next to `src/`.
TypeScript编译器的配置你的IDE会借助它来给你提供更好的帮助。
</td>
</tr>
<tr>
<td>
`tslint.json`
</td>
<td>
Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with
@ -770,7 +883,9 @@ These files go in the root folder next to `src/`.
Lint功能可以帮你保持代码风格的统一。
</td>
</tr>
</table>
<div class="l-sub-section">
@ -787,3 +902,4 @@ You can skip the "Setup" step since you're already using the Angular CLI setup.
你可以跳过“环境设置”一章,因为你已经在使用 Angular-CLI 设置好环境了。
</div>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,16 +5,19 @@ Reactive programming is an asynchronous programming paradigm concerned with data
RxJS provides an implementation of the `Observable` type, which is needed until the type becomes part of the language and until browsers support it. The library also provides utility functions for creating and working with observables. These utility functions can be used for:
* Converting existing code for async operations into observables
* Iterating through the values in a stream
* Mapping values to different types
* Filtering streams
* Composing multiple streams
## Observable creation functions
RxJS offers a number of functions that can be used to create new observables. These functions can simplify the process of creating observables from things such as events, timers, promises, and so on. For example:
<code-example path="rx-library/src/simple-creation.ts" region="promise" title="Create an observable from a promise"></code-example>
<code-example path="rx-library/src/simple-creation.ts" region="interval" title="Create an observable from a counter"></code-example>
@ -48,7 +51,9 @@ The `pipe()` function is also a method on the RxJS `Observable`, so you use this
RxJS provides many operators (over 150 of them), but only a handful are used frequently. Here is a list of common operators; for usage examples, see [RxJS 5 Operators By Example](https://github.com/btroncone/learn-rxjs/blob/master/operators/complete.md) in RxJS documentation.
<div class="l-sub-section">
Note that, for Angular apps, we prefer combining operators with pipes, rather than chaining. Chaining is used in many RxJS examples.
</div>
| Area | Operators |
@ -62,6 +67,8 @@ RxJS provides many operators (over 150 of them), but only a handful are used fre
## Error handling
## 错误处理
In addition to the `error()` handler that you provide on subscription, RxJS provides the `catchError` operator that lets you handle known errors in the observable recipe.
For instance, suppose you have an observable that makes an API request and maps to the response from the server. If the server returns an error or the value doesnt exist, an error is produced. If you catch this error and supply a default value, your stream continues to process values rather than erroring out.

View File

@ -17,16 +17,13 @@ You can run the <live-example></live-example> in Stackblitz and download the cod
运行<live-example></live-example>来试用本页的代码。
<h2 id='report-issues'>
Reporting vulnerabilities
</h2>
<h2 id='report-issues'>
举报漏洞
</h2>
</h2>
To report vulnerabilities in Angular itself, email us at [security@angular.io](mailto:security@angular.io).
@ -37,16 +34,13 @@ philosophy](https://www.google.com/about/appsecurity/).
要了解关于“谷歌如何处理安全问题”的更多信息,参见[谷歌的安全哲学](https://www.google.com/about/appsecurity/)。
<h2 id='best-practices'>
Best practices
</h2>
<h2 id='best-practices'>
最佳实践
</h2>
</h2>
* **Keep current with the latest Angular library releases.**
We regularly update the Angular libraries, and these updates may fix security defects discovered in
@ -70,11 +64,13 @@ For more information, see the [Trusting safe values](guide/security#bypass-secur
**避免使用本文档中带“[_安全风险_](guide/security#bypass-security-apis)”标记的Angular API。**
要了解更多信息,请参阅本章的[信任那些安全的值](guide/security#bypass-security-apis)部分。
<a id="xss"></a>
<h2 id='xss'>
## Preventing cross-site scripting (XSS)
Preventing cross-site scripting (XSS)
## 防范跨站脚本(XSS)攻击
防范跨站脚本(XSS)攻击
</h2>
[Cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) enables attackers
to inject malicious code into web pages. Such code can then, for example, steal user data (in
@ -140,7 +136,7 @@ Angular定义了四个安全环境 - HTML样式URL和资源URL
**样式**值需要作为CSS绑定到`style`属性时使用。
* **URL** is used for URL properties such as `<a href>`.
* **URL** is used for URL properties, such as `<a href>`.
**URL**值需要被用作URL属性时使用比如`<a href>`
@ -164,13 +160,10 @@ content, and once by binding it to the `innerHTML` property of an element:
下面的例子绑定了`htmlSnippet`的值,一次把它放进插值表达式里,另一次把它绑定到元素的`innerHTML`属性上。
<code-example path="security/src/app/inner-html-binding.component.html" title="src/app/inner-html-binding.component.html">
</code-example>
Interpolated content is always escaped&mdash;the HTML isn't interpreted and the browser displays
angle brackets in the element's text content.
@ -183,25 +176,21 @@ vulnerability. For example, code contained in a `<script>` tag is executed:
如果希望这段HTML被正常解释就必须绑定到一个HTML属性上比如`innerHTML`。但是如果把一个可能被攻击者控制的值绑定到`innerHTML`就会导致XSS漏洞。
比如,包含在`<script>`标签的代码就会被执行:
<code-example path="security/src/app/inner-html-binding.component.ts" linenums="false" title="src/app/inner-html-binding.component.ts (class)" region="class">
</code-example>
Angular recognizes the value as unsafe and automatically sanitizes it, which removes the `<script>`
tag but keeps safe content such as the text content of the `<script>` tag and the `<b>` element.
Angular认为这些值是不安全的并自动进行无害化处理。它会移除`<script>`标签,但保留安全的内容,比如该片段中的文本内容或`<b>`元素。
<figure>
<img src='generated/images/guide/security/binding-inner-html.png' alt='A screenshot showing interpolated and bound HTML values'>
</figure>
### Avoid direct use of the DOM APIs
### 避免直接使用DOM API
@ -228,10 +217,8 @@ on the HTML5Rocks website.
要打开CSP请配置你的Web服务器让它返回合适的HTTP头`Content_Security_Policy`
要了解关于内容安全策略的更多信息请参阅HTML5Rocks上的[内容安全策略简介](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
{@a offline-template-compiler}
### Use the offline template compiler
### 使用离线模板编译器
@ -262,20 +249,14 @@ carries a high risk of introducing template-injection vulnerabilities.
务必使用一个能够自动进行无害化处理以防范XSS漏洞的后端模板语言。不要在服务器端使用模板语言生成Angular模板
这样会带来很高的“模板注入”风险。
<h2 id='bypass-security-apis'>
Trusting safe values
</h2>
<h2 id='bypass-security-apis'>
信任安全值
</h2>
Sometimes applications genuinely need to include executable code, display an `<iframe>` from some
URL, or construct potentially dangerous URLs. To prevent automatic sanitization in any of these
situations, you can tell Angular that you inspected a value, checked how it was generated, and made
@ -293,9 +274,13 @@ following methods:
注入`DomSanitizer`服务,然后调用下面的方法之一,你就可以把一个值标记为可信任的。
* `bypassSecurityTrustHtml`
* `bypassSecurityTrustScript`
* `bypassSecurityTrustStyle`
* `bypassSecurityTrustUrl`
* `bypassSecurityTrustResourceUrl`
Remember, whether a value is safe depends on context, so choose the right context for
@ -304,32 +289,26 @@ your intended use of the value. Imagine that the following template needs to bin
记住,一个值是否安全取决于它所在的环境,所以你要为这个值按预定的用法选择正确的环境。假设下面的模板需要把`javascript.alert(...)`方法绑定到URL。
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (URL)" region="URL">
</code-example>
Normally, Angular automatically sanitizes the URL, disables the dangerous code, and
in development mode, logs this action to the console. To prevent
this, mark the URL value as a trusted URL using the `bypassSecurityTrustUrl` call:
通常Angular会自动无害化这个URL并禁止危险的代码。为了防止这种行为我们可以调用`bypassSecurityTrustUrl`把这个URL值标记为一个可信任的URL
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-url)" region="trust-url">
</code-example>
<figure>
<img src='generated/images/guide/security/bypass-security-component.png' alt='A screenshot showing an alert box created from a trusted URL'>
</figure>
If you need to convert user input into a trusted value, use a
controller method. The following template allows users to enter a YouTube video ID and load the
corresponding video in an `<iframe>`. The `<iframe src>` attribute is a resource URL security
@ -341,32 +320,22 @@ Angular to allow binding into `<iframe src>`:
然后把相应的视频加载到`<iframe>`中。`<iframe src>`是一个“资源URL”的安全环境因为不可信的源码可能作为文件下载到本地被毫无防备的用户执行。
所以我们要调用一个控制器方法来构造一个新的、可信任的视频URL然后把它绑定到`<iframe src>`
<code-example path="security/src/app/bypass-security.component.html" linenums="false" title="src/app/bypass-security.component.html (iframe)" region="iframe">
</code-example>
<code-example path="security/src/app/bypass-security.component.ts" linenums="false" title="src/app/bypass-security.component.ts (trust-video-url)" region="trust-video-url">
</code-example>
<h2 id='http'>
HTTP-level vulnerabilities
</h2>
<h2 id='http'>
HTTP级别的漏洞
</h2>
Angular has built-in support to help prevent two common HTTP vulnerabilities, cross-site request
forgery (CSRF or XSRF) and cross-site script inclusion (XSSI). Both of these must be mitigated primarily
on the server side, but Angular provides helpers to make integration on the client side easier.
@ -374,19 +343,14 @@ on the server side, but Angular provides helpers to make integration on the clie
Angular内置了一些支持来防范两个常见的HTTP漏洞跨站请求伪造XSRF和跨站脚本包含XSSI
这两个漏洞主要在服务器端防范但是Angular也自带了一些辅助特性可以让客户端的集成变得更容易。
<h3 id='xsrf'>
Cross-site request forgery
</h3>
<h3 id='xsrf'>
跨站请求伪造XSRF
</h3>
In a cross-site request forgery (CSRF or XSRF), an attacker tricks the user into visiting
a different web page (such as `evil.com`) with malignant code that secretly sends a malicious request
to the application's web server (such as `example-bank.com`).
@ -453,19 +417,14 @@ See also Dave Smith's easy-to-understand
参见Dave Smith在<a href="https://www.youtube.com/watch?v=9inczw6qtpY" target="_blank" title="Cross Site Request Funkery Securing Your Angular Apps From Evil Doers">AngularConnect 2016关于XSRF的演讲</a>
<h3 id='xssi'>
Cross-site script inclusion (XSSI)
</h3>
<h3 id='xssi'>
跨站脚本包含(XSSI)
</h3>
Cross-site script inclusion, also known as JSON vulnerability, can allow an attacker's website to
read data from a JSON API. The attack works on older browsers by overriding native JavaScript
object constructors, and then including an API URL using a `<script>` tag.
@ -490,24 +449,19 @@ post](https://security.googleblog.com/2011/05/website-security-for-webmasters.ht
要学习更多这方面的知识,请参见[谷歌Web安全博客文章](https://security.googleblog.com/2011/05/website-security-for-webmasters.html)的XSSI小节。
<h2 id='code-review'>
Auditing Angular applications
</h2>
<h2 id='code-review'>
审计Angular应用程序
</h2>
Angular applications must follow the same security principles as regular web applications, and
must be audited as such. Angular-specific APIs that should be audited in a security review,
such as the [_bypassSecurityTrust_](guide/security#bypass-security-apis) methods, are marked in the documentation
as security sensitive.
Angular应用应该遵循和常规Web应用一样的安全原则并按照这些原则进行审计。Angular中某些应该在安全评审中被审计的API
比如[_bypassSecurityTrust_](guide/security#bypass-security-apis) API都在文档中被明确标记为安全性敏感的。

View File

@ -5,19 +5,23 @@ Importing `ServiceWorkerModule` into your `AppModule` doesn't just register the
#### Prerequisites
A basic understanding of the following:
* [Getting Started with Service Workers](guide/service-worker-getting-started).
<hr />
## `SwUpdate` service
The `SwUpdate` service gives you access to events that indicate when the service worker has discovered an available update for your app or when it has activated such an update&mdash;meaning it is now serving content from that update to your app.
The `SwUpdate` service supports four separate operations:
* Getting notified of *available* updates. These are new versions of the app to be loaded if the page is refreshed.
* Getting notified of update *activation*. This is when the service worker starts serving a new version of the app immediately.
* Asking the service worker to check the server for new updates.
* Asking the service worker to activate the latest version of the app for the current tab.
### Available and activated updates
@ -26,7 +30,6 @@ The two update events, `available` and `activated`, are `Observable` properties
<code-example path="service-worker-getting-started/src/app/log-update.service.ts" linenums="false" title="log-update.service.ts" region="sw-update"> </code-example>
You can use these events to notify the user of a pending update or to refresh their pages when the code they are running is out of date.
### Checking for updates
@ -37,7 +40,6 @@ Do this with the `checkForUpdate()` method:
<code-example path="service-worker-getting-started/src/app/check-for-update.service.ts" linenums="false" title="check-for-update.service.ts" region="sw-check-update"> </code-example>
This method returns a `Promise` which indicates that the update check has completed successfully, though it does not indicate whether an update was discovered as a result of the check. Even if one is found, the service worker must still successfully download the changed files, which can fail. If successful, the `available` event will indicate availability of a new version of the app.
### Forcing update activation
@ -51,4 +53,5 @@ Doing this could break lazy-loading into currently running apps, especially if t
## More on Angular service workers
You may also be interested in the following:
* [Service Worker in Production](guide/service-worker-devops).

View File

@ -5,6 +5,7 @@
#### Prerequisites
A basic understanding of the following:
* [Service Worker in Production](guide/service-worker-devops).
<hr />
@ -23,13 +24,17 @@ The configuration file uses the JSON format. All file paths must begin with `/`,
Patterns use a limited glob format:
* `**` matches 0 or more path segments.
* `*` matches exactly one path segment or filename segment.
* The `!` prefix marks the pattern as being negative, meaning that only files that don't match the pattern will be included.
Example patterns:
* `/**/*.html` specifies all HTML files.
* `/*.html` specifies only HTML files in the root.
* `!/**/*.map` exclude all sourcemaps.
Each section of the configuration file is described below.
@ -127,12 +132,15 @@ export interface DataGroup {
```
### `name`
Similar to `assetGroups`, every data group has a `name` which uniquely identifies it.
### `urls`
A list of URL patterns. URLs that match these patterns will be cached according to this data group's policy.
### `version`
Occasionally APIs change formats in a way that is not backward-compatible. A new version of the app may not be compatible with the old API format and thus may not be compatible with existing cached resources from that API.
`version` provides a mechanism to indicate that the resources being cached have been updated in a backwards-incompatible way, and that the old cache entries&mdash;those from previous versions&mdash;should be discarded.
@ -140,23 +148,31 @@ Occasionally APIs change formats in a way that is not backward-compatible. A new
`version` is an integer field and defaults to `0`.
### `cacheConfig`
This section defines the policy by which matching requests will be cached.
#### `maxSize`
(required) The maximum number of entries, or responses, in the cache. Open-ended caches can grow in unbounded ways and eventually exceed storage quotas, calling for eviction.
#### `maxAge`
(required) The `maxAge` parameter indicates how long responses are allowed to remain in the cache before being considered invalid and evicted. `maxAge` is a duration string, using the following unit suffixes:
* `d`: days
* `h`: hours
* `m`: minutes
* `s`: seconds
* `u`: milliseconds
For example, the string `3d12h` will cache content for up to three and a half days.
#### `timeout`
This duration string specifies the network timeout. The network timeout is how long the Angular service worker will wait for the network to respond before using a cached response, if configured to do so.
#### `strategy`

View File

@ -5,6 +5,7 @@ This page is a reference for deploying and supporting production apps that use t
#### Prerequisites
A basic understanding of the following:
* [Service Worker Communication](guide/service-worker-communications).
<hr />
@ -70,7 +71,9 @@ if the risk of serving invalid, broken, or outdated content is high.
Hash mismatches can occur for a variety of reasons:
* Caching layers in between the origin server and the end user could serve stale content.
* A non-atomic deployment could result in the Angular service worker having visibility of partially updated content.
* Errors during the build process could result in updated resources without `ngsw.json` being updated. The reverse could also happen resulting in an updated `ngsw.json` without updated resources.
#### Unhashed content
@ -119,6 +122,7 @@ might change the version of a running app. Some of them are
error conditions:
* The current version becomes invalid due to a failed hash.
* An unrelated error causes the service worker to enter safe mode; that is, temporary deactivation.
The Angular service worker is aware of which versions are in
@ -129,6 +133,7 @@ Other reasons the Angular service worker might change the version
of a running app are normal events:
* The page is reloaded/refreshed.
* The page requests an update be immediately activated via the `SwUpdate` service.
### Service worker updates
@ -147,7 +152,6 @@ normally. However, occasionally a bugfix or feature in the Angular
service worker requires the invalidation of old caches. In this case,
the app will be refreshed transparently from the network.
## Debugging the Angular service worker
Occasionally, it may be necessary to examine the Angular service
@ -177,6 +181,7 @@ Clients: 7b79a015-69af-4d3d-9ae6-95ba90c79486, 5bc08295-aaf2-42f3-a4cc-9e4ef9100
Last update tick: 1s496u
Last update run: never
Task queue:
* init post-load (update, cleanup)
Debug log:
@ -207,7 +212,6 @@ network, running as little service worker code as possible.
In both cases, the parenthetical annotation provides the
error that caused the service worker to enter the degraded state.
#### Latest manifest hash
```
@ -216,7 +220,6 @@ Latest manifest hash: eea7f5f464f90789b621170af5a569d6be077e5c
This is the SHA1 hash of the most up-to-date version of the app that the service worker knows about.
#### Last update check
```
@ -241,7 +244,6 @@ is the "latest manifest hash" listed above. Both clients are on the
latest version. Each client is listed by its ID from the `Clients`
API in the browser.
#### Idle task queue
```
@ -249,6 +251,7 @@ API in the browser.
Last update tick: 1s496u
Last update run: never
Task queue:
* init post-load (update, cleanup)
```
@ -264,7 +267,6 @@ counter shows the last time idle tasks were actually executed.
"Last update tick" shows the time since the last event after
which the queue might be processed.
#### Debug log
```
@ -273,7 +275,6 @@ Debug log:
Errors that occur within the service worker will be logged here.
### Developer Tools
Browsers such as Chrome provide developer tools for interacting
@ -329,5 +330,6 @@ the past on your site.
## More on Angular service workers
You may also be interested in the following:
* [Service Worker Configuration](guide/service-worker-config).

View File

@ -3,11 +3,11 @@
#### Prerequisites
A basic understanding of the following:
* [Introduction to Angular service workers](guide/service-worker-intro).
<hr />
Beginning in Angular 5.0.0, you can easily enable Angular service worker support in any CLI project. This document explains how to enable Angular service worker support in new and existing projects. It then uses a simple example to show you a service worker in action, demonstrating loading and basic caching.
## Adding a service worker to a new application
@ -25,16 +25,18 @@ For information on the details, see the following section
which covers the process in detail as it shows you how to add a
service worker manually to an existing app.
## Adding a service worker to an existing app
To add a service worker to an existing app:
1. Add the service worker package.
2. Enable service worker build support in the CLI.
3. Import and register the service worker.
4. Create the service worker configuration file, which specifies the caching behaviors and other settings.
5. Build the project.
### Step 1: Add the service worker package
@ -61,7 +63,6 @@ At the top of the root module, `src/app/app.module.ts`, import `ServiceWorkerMod
<code-example path="service-worker-getting-started/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts" region="sw-import"> </code-example>
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.
<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>
@ -89,7 +90,6 @@ ng build --prod
The CLI project is now set up to use the Angular service worker.
## Service worker in action: a tour
This section demonstrates a service worker in action,
@ -117,11 +117,15 @@ With the server running, you can point your browser at http://localhost:8080/. Y
To simulate a network issue, disable network interaction for your application. In Chrome:
1. Select **Tools** > **Developer Tools** (from the Chrome menu located at the top right corner).
2. Go to the **Network tab**.
3. Check the **Offline box**.
<figure>
<img src="generated/images/guide/service-worker/offline-checkbox.png" alt="The offline checkbox in the Network tab is checked">
</figure>
Now the app has no access to network interaction.
@ -133,19 +137,23 @@ With the addition of an Angular service worker, the application behavior changes
If you look at the Network tab, you can verify that the service worker is active.
<figure>
<img src="generated/images/guide/service-worker/sw-active.png" alt="Requests are marked as from ServiceWorker">
</figure>
Notice that under the "Size" column, the requests state is `(from ServiceWorker)`. This means that the resources are not being loaded from the network. Instead, they are being loaded from the service worker's cache.
### What's being cached?
Notice that all of the files the browser needs to render this application are cached. The `ngsw-config.json` boilerplate configuration is set up to cache the specific resources used by the CLI:
* `index.html`.
* `favicon.ico`.
* Build artifacts (JS and CSS bundles).
* Anything under `assets`.
### Making changes to your application
@ -180,7 +188,9 @@ Now look at how the browser and service worker handle the updated application.
1. Open http://localhost:8080 again in the same window. What happens?
<figure>
<img src="generated/images/guide/service-worker/welcome-msg-en.png" alt="It still says Welcome to Service Workers!">
</figure>
What went wrong? Nothing, actually. The Angular service worker is doing its job and serving the version of the application that it has **installed**, even though there is an update available. In the interest of speed, the service worker doesn't wait to check for updates before it serves the application that it has cached.
@ -190,7 +200,9 @@ If you look at the `http-server` logs, you can see the service worker requesting
2. Refresh the page.
<figure>
<img src="generated/images/guide/service-worker/welcome-msg-fr.png" alt="The text has changed to say Bienvenue à app!">
</figure>
The service worker installed the updated version of your app *in the background*, and the next time the page is loaded or reloaded, the service worker switches to the latest version.
@ -200,4 +212,5 @@ The service worker installed the updated version of your app *in the background*
## More on Angular service workers
You may also be interested in the following:
* [Communicating with service workers](guide/service-worker-communications).

View File

@ -10,7 +10,6 @@ Unlike the other scripts that make up an application, such as the Angular app bu
Even across a fast reliable network, round-trip delays can introduce significant latency when loading the application. Using a service worker to reduce dependency on the network can significantly improve the user experience.
## Service workers in Angular
Angular applications, as single-page applications, are in a prime position to benefit from the advantages of service workers. Starting with version 5.0.0, Angular ships with a service worker implementation. Angular developers can take advantage of this service worker and benefit from the increased reliability and performance it provides, without needing to code against low-level APIs.
@ -20,9 +19,13 @@ Angular's service worker is designed to optimize the end user experience of usin
The Angular service worker's behavior follows that design goal:
* Caching an application is like installing a native application. The application is cached as one unit, and all files update together.
* A running application continues to run with the same version of all files. It does not suddenly start receiving cached files from a newer version, which are likely incompatible.
* When users refresh the application, they see the latest fully cached version. New tabs load the latest cached code.
* Updates happen in the background, relatively quickly after changes are published. The previous version of the application is served until an update is installed and ready.
* The service worker conserves bandwidth when possible. Resources are only downloaded if they've changed.
To support these behaviors, the Angular service worker loads a *manifest* file from the server. The manifest describes the resources to cache and includes hashes of every file's contents. When an update to the application is deployed, the contents of the manifest change, informing the service worker that a new version of the application should be downloaded and cached. This manifest is generated from a user-provided configuration file called `ngsw-config.json`, by using a build tool such as the Angular CLI.
@ -34,6 +37,7 @@ Installing the Angular service worker is as simple as including an `NgModule`. I
To use Angular service workers, you must have the following Angular and CLI versions:
* Angular 5.0.0 or later.
* Angular CLI 1.6.0 or later.
Your application must run in a web browser that supports service workers. Currently, the latest versions of Chrome and Firefox are supported. To learn about other browsers that are service worker ready, see the [Can I Use](http://caniuse.com/#feat=serviceworkers) page.
@ -50,4 +54,5 @@ The remainder of this Angular documentation specifically addresses the Angular i
## More on Angular service workers
You may also be interested in the following:
* [Getting Started with service workers](guide/service-worker-getting-started).

View File

@ -11,7 +11,7 @@ This cookbook explains how to do it.
See the <live-example name="set-document-title"></live-example>.
参见<live-example name="set-document-title"></live-example>
参见<live-example name="set-document-title"></live-example>
## The problem with *&lt;title&gt;*
@ -21,8 +21,8 @@ The obvious approach is to bind a property of the component to the HTML `<title>
显而易见的方法是把组件的属性绑定到HTML的`<title>`标签上,像这样:
<code-example format=''>
&lt;title&gt;{{This_Does_Not_Work}}&lt;/title&gt;
</code-example>
@ -38,7 +38,6 @@ That's dirty and undermines your chances of running the app outside of a browser
可以从浏览器获得`document`对象,并且手动设置标题。但是这样看起来很脏,而且将无法在浏览器之外运行应用程序。
<div class="l-sub-section">
Running your app outside a browser means that you can take advantage of server-side
@ -50,7 +49,6 @@ That's dirty and undermines your chances of running the app outside of a browser
意味着你可以在一个Web Worker中运行你的应用程序通过多线程技术增强应用程序的响应性。
还意味着你可以在Electron.js或者Windows Universal里面运行发布到桌面环境。
</div>
## Use the `Title` service
@ -68,37 +66,38 @@ for getting and setting the current HTML document title:
`getTitle(): string` —— 获取当前HTML文档的标题。
* `setTitle( newTitle : string )`&mdash;Sets the title of the current HTML document.
`setTitle( newTitle: string)` —— 设置当前HTML文档的标题。
You can inject the `Title` service into the root `AppComponent` and expose a bindable `setTitle` method that calls it:
我们来把`Title`服务注入到根组件`AppComponent`,并暴露出可供绑定的`setTitle`方法让别人来调用该服务:
<code-example path="set-document-title/src/app/app.component.ts" region="class" title="src/app/app.component.ts (class)" linenums="false"></code-example>
Bind that method to three anchor tags and voilà!
我们把这个方法绑定到三个A标签瞧瞧
<figure>
<img src="generated/images/guide/set-document-title/set-title-anim.gif" alt="Set title">
</figure>
Here's the complete solution:
这里是完整的方案(代码)。
<code-tabs>
<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.component.ts" path="set-document-title/src/app/app.component.ts"></code-pane>
</code-tabs>
## Why provide the `Title` service in `bootstrap`
@ -122,3 +121,4 @@ the concept of a "document title" for that specific platform.
Ideally, the application itself neither knows nor cares about the runtime environment.
我们的做法正是如此。这里的`Title`服务是Angular*浏览器平台*的一部分。如果在其它平台上引导应用程序,就得提供另一个专为那个平台准备的`Title`服务。

View File

@ -18,13 +18,12 @@ If you do, this page can help you understand their purpose.
在这两个文件夹*之外*的文件为开发环境设定条件。
这些文件很少会需要变动,你可能永远都不需要阅览或者修改它们。
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="10%">
@ -39,18 +38,18 @@ If you do, this page can help you understand their purpose.
<th>
File
文件
</th>
<th>
Purpose
用途
</th>
</tr>
@ -58,12 +57,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>src/app/</code>
</td>
<td>
Angular application files go here.
你的 Angular 应用文件。
@ -87,12 +87,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>e2e/</code>
</td>
<td>
_End-to-end_ (e2e) tests of the application,
written in Jasmine and run by the
<a href="http://www.protractortest.org/" title="Protractor: end-to-end testing for Angular">protractor</a>
@ -111,12 +112,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>node_modules/</code>
</td>
<td>
The _npm_ packages installed with the `npm install` command.
`npm install` 命令安装的 *npm* 包。
@ -136,15 +138,12 @@ If you do, this page can help you understand their purpose.
<td>
Tooling configuration files and folders.
配置文件和文件夹的工具。
Ignore them until you have a compelling reason to do otherwise.
除非非常必要,否则可以忽略。
</td>
</tr>
@ -152,18 +151,17 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>CHANGELOG.md</code>
</td>
<td>
The history of changes to the _QuickStart_ repository.
*快速上手*库的更新历史。
Delete or ignore.
*快速上手*库的更新历史。
删除或忽略。
</td>
@ -173,12 +171,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>favicon.ico</code>
</td>
<td>
The application icon that appears in the browser tab.
出现在浏览器标签上的应用图标。
@ -190,12 +189,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>index.html</code>
</td>
<td>
The application host page.
It loads a few essential scripts in a prescribed order.
Then it boots the application, placing the root `AppComponent`
@ -216,12 +216,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>karma.conf.js</code>
</td>
<td>
Configuration for the <a href="https://karma-runner.github.io/1.0/index.html" title="Karma unit test runner">karma</a>
test runner described in the [Testing](guide/testing) guide.
@ -234,12 +235,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>karma-test-shim.js</code>
</td>
<td>
Script to run <a href="https://karma-runner.github.io/1.0/index.html" title="Karma unit test runner">karma</a>
with SystemJS as described in the [Testing](guide/testing) guide.
@ -252,12 +254,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>non-essential-files.txt</code>
</td>
<td>
A list of files that you can delete if you want to purge your setup of the
original QuickStart Seed testing and git maintenance artifacts.
See instructions in the optional
@ -267,6 +270,7 @@ If you do, this page can help you understand their purpose.
这个列表中的文件在清理时可以删除它是原始的“快速上手”种子工程中的测试和git维护文件。
步骤参见可选的[删除非必要文件](guide/setup#non-essential "Setup: Deleting non-essential files")部分。
*只在最初做这件事以免不小心删除了你自己的测试文件和git配置*
</td>
</tr>
@ -274,12 +278,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>LICENSE</code>
</td>
<td>
The open source MIT license to use this setup code in your application.
应用的搭建代码中用到的开源 MIT 许可证。
@ -291,12 +296,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>package.json</code>
</td>
<td>
Identifies `npm `package dependencies for the project.
为项目指定`npm`依赖包。
@ -309,6 +315,7 @@ If you do, this page can help you understand their purpose.
包含了一些命令脚本,用来运行应用、运行测试与其他。输入`npm run`来查看命令列表。
<a href="https://github.com/angular/quickstart/blob/master/README.md#npm-scripts"
target="_blank" title="Angular 文档例子的 npm 脚本">这里</a>阅读更多关于它们的说明。
</td>
</tr>
@ -316,17 +323,19 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>protractor.config.js</code>
</td>
<td>
Configuration for the
<a href="http://www.protractortest.org/" title="Protractor: end-to-end testing for Angular">protractor</a>
_end-to-end_ (e2e) test runner.
<a href="http://www.protractortest.org/" target="_blank" title="Protractor: Angular 的端对端测试">protractor</a> *端对端* (e2e) 测试器运行器的配置。
</td>
</tr>
@ -334,17 +343,19 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>README.md</code>
</td>
<td>
Instruction for using this git repository in your project.
Worth reading before deleting.
项目中使用这个 git 库的说明。
在删除前值得阅读。
</td>
</tr>
@ -352,12 +363,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>styles.css</code>
</td>
<td>
Global styles for the application. Initialized with an `<h1>` style for the QuickStart demo.
应用的全局样式。初始化后,有个为《快速上手》演示准备的`<h1>`样式。
@ -369,25 +381,28 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>systemjs<br>.config.js</code>
</td>
<td>
Tells the **SystemJS** module loader where to find modules
referenced in JavaScript `import` statements. For example:
**SystemJS** 模块加载器指定去哪儿查找在 JavaScript 的`import`语句中引用的模块。例如:
<code-example language="ts">
import { Component } from '@angular/core;
</code-example>
import { Component } from '@angular/core;
</code-example>
Don't touch this file unless you are fully versed in SystemJS configuration.
除非你完全理解 SystemJS 的配置,不要修改它。
</td>
</tr>
@ -395,12 +410,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>systemjs<br>.config.extras.js</code>
</td>
<td>
Optional extra SystemJS configuration.
A way to add SystemJS mappings, such as for application _barrels_,
without changing the original `system.config.js`.
@ -415,12 +431,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>tsconfig.json</code>
</td>
<td>
Tells the TypeScript compiler how to transpile TypeScript source files
into JavaScript files that run in all modern browsers.
@ -433,12 +450,13 @@ If you do, this page can help you understand their purpose.
<tr>
<td>
<code>tslint.json</code>
</td>
<td>
The `npm` installed TypeScript linter inspects your TypeScript code
and complains when you violate one of its rules.
@ -448,6 +466,7 @@ If you do, this page can help you understand their purpose.
[Angular style guide](guide/styleguide) and by the authors of the documentation.
该文件定义了 [Angular 风格指南](guide/styleguide)与本文档站作者喜爱的语法检查规则。
</td>
</tr>

View File

@ -17,14 +17,12 @@ maintained [on github](https://github.com/angular/quickstart "Install the github
利用 [github 上](https://github.com/angular/quickstart "安装 github 《快速上手》库")的**《快速上手》种子**在你的电脑上搭建一个新项目是很快很容易的。
Make sure you have [node and npm installed](guide/setup#install-prerequisites "What if you don't have node and npm?").
确定你已经安装了 [node和npm](guide/setup#install-prerequisites "如果你没有node和npm")。
{@a clone}
## Clone
## 克隆
@ -33,8 +31,8 @@ Perform the _clone-to-launch_ steps with these terminal commands.
运行下列命令来执行*克隆并启动*步骤。
<code-example language="sh" class="code-shell">
git clone https://github.com/angular/quickstart.git quickstart
cd quickstart
npm install
@ -42,24 +40,16 @@ Perform the _clone-to-launch_ steps with these terminal commands.
</code-example>
<div class="alert is-important">
`npm start` fails in _Bash for Windows_ in versions earlier than the Creator's Update (April 2017).
在*Bash for Windows*中`npm start`可能会失败因为到2017-04为止它还不支持访问网络上的服务器。
</div>
{@a download}
## Download
## 下载
@ -70,33 +60,24 @@ and unzip it into your project folder. Then perform the remaining steps with the
<a href="https://github.com/angular/quickstart/archive/master.zip" title="下载《快速上手》种子库">下载《快速上手》种子</a>
并解压到你的项目目录中。然后执行下面的命令完成剩余步骤。
<code-example language="sh" class="code-shell">
cd quickstart
npm install
npm start
</code-example>
<div class="alert is-important">
`npm start` fails in _Bash for Windows_ in versions earlier than the Creator's Update (April 2017).
在*Bash for Windows*中`npm start`可能会失败因为到2017-01为止它还不支持访问网络上的服务器。
</div>
{@a non-essential}
## Delete _non-essential_ files (optional)
## 删除*非必需*文件(可选)
@ -107,62 +88,44 @@ You can quickly delete the _non-essential_ files that concern testing and QuickS
你可以快速删除一些涉及到测试和维护快速开始版本库的 *非必需* 文件
***包括所有git相关的文件***如 `.git` 文件夹和 `.gitignore`!)。
<div class="alert is-important">
Do this only in the beginning to avoid accidentally deleting your own tests and git setup!
请只在开始时执行此删除操作以防你自己的测试和git文件被意外删除
</div>
Open a terminal window in the project folder and enter the following commands for your environment:
在项目目录下打开一个终端窗口,并根据你的操作系统执行以下命令:
### OS/X (bash)
### OS/X (bash) 命令
<code-example language="sh" class="code-shell">
xargs rm -rf &lt; non-essential-files.osx.txt
rm src/app/*.spec*.ts
rm non-essential-files.osx.txt
</code-example>
### Windows
### Windows 命令
<code-example language="sh" class="code-shell">
for /f %i in (non-essential-files.txt) do del %i /F /S /Q
rd .git /s /q
rd e2e /s /q
</code-example>
{@a seed}
## What's in the QuickStart seed?
## 《快速上手》种子库里都有什么?
The **QuickStart seed** contains the same application as the QuickStart playground.
But its true purpose is to provide a solid foundation for _local_ development.
Consequently, there are _many more files_ in the project folder on your machine,
@ -171,49 +134,53 @@ most of which you can [learn about later](guide/setup-systemjs-anatomy "Setup An
**《快速上手》种子** 包含了与《快速上手》游乐场一样的应用,但是,它真正的目的是提供坚实的*本地*开发基础。
所以你的电脑里的项目目录里面有*更多文件*,参见[搭建剖析](guide/setup-systemjs-anatomy "Setup Anatomy")。
{@a app-files}
Focus on the following three TypeScript (`.ts`) files in the **`/src`** folder.
注意**`/src`**目录中以下三个 TypeScript (`.ts`) 文件:
<div class='filetree'>
<div class='file'>
src
</div>
<div class='children'>
<div class='file'>
app
</div>
<div class='children'>
<div class='file'>
app.component.ts
</div>
<div class='file'>
app.module.ts
</div>
</div>
<div class='file'>
main.ts
</div>
</div>
</div>
</div>
<code-tabs>
@ -231,8 +198,6 @@ Focus on the following three TypeScript (`.ts`) files in the **`/src`** folder.
</code-tabs>
All guides and cookbooks have _at least these core files_.
Each file has a distinct purpose and evolves independently as the application grows.
@ -255,13 +220,12 @@ The following are all in `src/`
`src/`目录文件详情如下:
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
@ -276,25 +240,17 @@ The following are all in `src/`
<th>
<p>
File
</p>
<p>
文件
</p>
</th>
<th>
<p>
Purpose
</p>
<p>
用途
</p>
</th>
@ -303,16 +259,20 @@ The following are all in `src/`
<tr>
<td>
<code>app/app.component.ts</code>
</td>
<td>
Defines the same `AppComponent` as the one in the QuickStart playground.
It is the **root** component of what will become a tree of nested components
as the application evolves. 定义与《快速上手》游乐场同样的`AppComponent`
as the application evolves.
定义与《快速上手》游乐场同样的`AppComponent`
它是**根**组件,随着应用的演变,它将变成一颗嵌套组件树。
</td>
</tr>
@ -320,12 +280,13 @@ The following are all in `src/`
<tr>
<td>
<code>app/app.module.ts</code>
</td>
<td>
Defines `AppModule`, the [root module](guide/bootstrapping "AppModule: the root module") that tells Angular how to assemble the application.
Right now it declares only the `AppComponent`.
Soon there will be more components to declare.
@ -333,6 +294,7 @@ The following are all in `src/`
定义`AppModule`[根模块](guide/bootstrapping "AppModule: 根模块")为 Angular 描述如何组装应用。
目前,它只声明了`AppComponent`
不久,它将声明更多组件。
</td>
</tr>
@ -340,12 +302,13 @@ The following are all in `src/`
<tr>
<td>
<code>main.ts</code>
</td>
<td>
Compiles the application with the [JIT compiler](guide/glossary#jit) and
[bootstraps](guide/bootstrapping)
the application's main module (`AppModule`) to run in the browser.
@ -363,12 +326,8 @@ The following are all in `src/`
</table>
<div class="l-sub-section">
### Next Step
### 下一步
@ -377,13 +336,12 @@ If you're new to Angular, we recommend you follow the [tutorial](tutorial "Tour
如果你是 Angular 初学者,建议跟着[教程](tutorial "《英雄指南》教程")学习。
</div>
<br></br><br></br>
{@a install-prerequisites}
## Appendix: node and npm
## 附录node 与 npm
@ -397,7 +355,7 @@ Node 驱动客户端开发和构建工具。
*npm* 包管理器本身是 *node* 应用,用于安装 JavaScript 库。
<a href="https://docs.npmjs.com/getting-started/installing-node" target="_blank" title="Installing Node.js and updating npm">
</a> if they're not already installed on your machine.
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="安装 Node.js 和更新 npm">
立刻安装它们</a>
@ -416,11 +374,8 @@ use other versions of node and npm.
我们推荐使用 [nvm](https://github.com/creationix/nvm) 来管理多版本 node 和 npm。
如果你的电脑上已经有使用其他版本 node 和 npm 的项目,你可能需要 nvm。
{@a why-locally}
## Appendix: Why develop locally
## 附录:为何在本地开发

View File

@ -1,13 +1,18 @@
# Sharing Modules
#### Prerequisites
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Routing and Navigation](guide/router).
* [Lazy loading modules](guide/lazy-loading-ngmodules).
A basic understanding of the following:
* [Feature Modules](guide/feature-modules).
* [JavaScript Modules vs. NgModules](guide/ngmodule-vs-jsmodule).
* [Frequently Used Modules](guide/frequent-ngmodules).
* [Routing and Navigation](guide/router).
* [Lazy loading modules](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.-->
@ -19,7 +24,6 @@ you need it in other parts of your app.
Consider the following module from an imaginary app:
```typescript
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
@ -39,8 +43,12 @@ export class SharedModule { }
Note the following:
请注意以下几点:
* It imports the `CommonModule` because the module's component needs common directives.
* It declares and exports the utility pipe, directive, and component classes.
* It re-exports the `CommonModule` and `FormsModule`.
By re-exporting `CommonModule` and `FormsModule`, any other module that imports this
@ -65,11 +73,12 @@ The most common way to get a hold of shared services is through Angular
To read about sharing services, see [Providers](guide/providers).
<hr />
## More on NgModules
You may also be interested in the following:
* [Providers](guide/providers).
* [Types of Feature Modules](guide/module-types).

View File

@ -2,7 +2,10 @@
#### Prerequisites:
#### 前提条件:
* A basic understanding of [Bootstrapping](guide/bootstrapping).
* Familiarity with [Providers](guide/providers).
For a sample app using the app-wide singleton service that this page describes, see the
@ -24,6 +27,7 @@ The following example module is called, as a convention, `CoreModule`. This use
a way of providing services from a designated 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>
Here, `CoreModule` provides the `UserService`, and because `AppModule`
@ -51,15 +55,18 @@ As a general rule, import modules with providers _exactly once_,
preferably in the application's _root module_.
That's also usually the best place to configure, wrap, and override them.
作为一个通用的规则,应该*只导入一次*带提供商的模块,最好在应用的*根模块*中。
那里也是配置、包装和改写这些服务的最佳位置。
For more detailed information on services, see the [Services](tutorial/toh-pt4) chapter of the
[Tour of Heroes tutorial](tutorial).
## `forRoot()`
If a module provides both providers and declarations (components, directives, pipes) then loading it in a child injector such as a route, would duplicate the provider instances. The duplication of providers would cause issues as they would shadow the root instances, which are probably meant to be singletons. For this reason Angular provides a way to separate providers out of the module so that same module can be imported into the root module with `providers` and child modules without `providers`.
1. Create a static method `forRoot()` (by convention) on the module.
2. Place the providers into the `forRoot` method as follows.
<!-- MH: show a simple example how to do that without going to deep into it. -->
@ -79,6 +86,7 @@ facility for configuring those providers as well through the
a simple object with the following properties:
* `ngModule`: in this example, the `CoreModule` class.
* `providers`: the configured providers.
In the <live-example name="ngmodules">live example</live-example>
@ -158,23 +166,30 @@ Now `parentModule` exists and the constructor throws the error.
Here are the two files in their entirety for reference:
<code-tabs linenums="false">
<code-pane
title="app.module.ts"
path="ngmodules/src/app/app.module.ts">
</code-pane>
<code-pane
title="core.module.ts"
region="whole-core-module"
path="ngmodules/src/app/core/core.module.ts">
</code-pane>
</code-tabs>
</code-pane>
</code-tabs>
<hr>
## More on NgModules
You may also be interested in:
* [Sharing Modules](guide/sharing-ngmodules), which elaborates on the concepts covered on this page.
* [Lazy Loading Modules](guide/lazy-loading-ngmodules).
* [NgModule FAQ](guide/ngmodule-faq).

View File

@ -3,13 +3,12 @@
# 结构型指令
<style>
h4 {font-size: 17px !important; text-transform: none !important;}
.syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; }
</style>
This guide looks at how Angular manipulates the DOM with **structural directives** and
how you can write your own structural directives to do the same thing.
@ -19,11 +18,8 @@ Try the <live-example></live-example>.
试试<live-example></live-example>
{@a definition}
## What are structural directives?
## 什么是结构型指令?
@ -47,13 +43,10 @@ An asterisk (*) precedes the directive attribute name as in this example.
结构型指令非常容易识别。
在这个例子中,星号(*)被放在指令的属性名之前。
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif)" region="ngif">
</code-example>
No brackets. No parentheses. Just `*ngIf` set to a string.
没有方括号,没有圆括号,只是把`*ngIf`设置为一个字符串。
@ -77,35 +70,25 @@ Here's an example of them in a template:
三个常用的内置结构型指令 —— [NgIf](guide/template-syntax#ngIf)、[NgFor](guide/template-syntax#ngFor)和[NgSwitch...](guide/template-syntax#ngSwitch)。
我们在[*模板语法*](guide/template-syntax)一章中讲过它并且在Angular文档的例子中到处都在用它。下面是模板中的例子
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (built-in)" region="built-in">
</code-example>
This guide won't repeat how to _use_ them. But it does explain _how they work_
and how to [write your own](guide/structural-directives#unless) structural directive.
本章不会重复讲如何*使用*它们,而是解释它们的*工作原理*以及如何[写自己的结构型指令](guide/structural-directives#unless)。
<div class="callout is-helpful">
<header>
Directive spelling
</header>
<header>
指令的拼写形式
</header>
Throughout this guide, you'll see a directive spelled in both _UpperCamelCase_ and _lowerCamelCase_.
Already you've seen `NgIf` and `ngIf`.
There's a reason. `NgIf` refers to the directive _class_;
@ -123,15 +106,10 @@ you apply the directive to an element in the HTML template.
指令的*类名*拼写成*大驼峰形式*`NgIf`),而它的*属性名*则拼写成*小驼峰形式*`ngIf`)。
本章会在谈论指令的属性和工作原理时引用指令的*类名*在描述如何在HTML模板中把该指令应用到元素时引用指令的*属性名*。
</div>
<div class="l-sub-section">
There are two other kinds of Angular directives, described extensively elsewhere:
(1)&nbsp;components and (2)&nbsp;attribute directives.
@ -155,15 +133,10 @@ You can [only apply one](guide/structural-directives#one-per-element) _structura
我们可以在一个宿主元素上应用多个*属性型*指令,但[只能应用一个](guide/structural-directives#one-per-element)*结构型*指令。
</div>
{@a ngIf}
## NgIf case study
## NgIf案例分析
@ -173,26 +146,22 @@ It takes a boolean expression and makes an entire chunk of the DOM appear or dis
我们重点看下`ngIf`。它是一个很好的结构型指令案例它接受一个布尔值并据此让一整块DOM树出现或消失。
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-true)" region="ngif-true">
</code-example>
The `ngIf` directive doesn't hide elements with CSS. It adds and removes them physically from the DOM.
Confirm that fact using browser developer tools to inspect the DOM.
`ngIf`指令并不是使用CSS来隐藏元素的。它会把这些元素从DOM中物理删除。
使用浏览器的开发者工具就可以确认这一点。
<figure>
<img src='generated/images/guide/structural-directives/element-not-in-dom.png' alt="ngIf=false element not in DOM">
</figure>
The top paragraph is in the DOM. The bottom, disused paragraph is not;
in its place is a comment about "bindings" (more about that [later](guide/structural-directives#asterisk)).
@ -214,24 +183,20 @@ A directive could hide the unwanted paragraph instead by setting its `display` s
指令也可以通过把它的`display`风格设置为`none`而隐藏不需要的段落。
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (display-none)" region="display-none">
</code-example>
While invisible, the element remains in the DOM.
当不可见时这个元素仍然留在DOM中。
<figure>
<img src='generated/images/guide/structural-directives/element-display-in-dom.png' alt="hidden element still in DOM">
</figure>
The difference between hiding and removing doesn't matter for a simple paragraph.
It does matter when the host element is attached to a resource intensive component.
Such a component's behavior continues even when hidden.
@ -272,11 +237,8 @@ to consider the consequences of adding and removing elements and of creating and
**同样的考量也适用于每一个结构型指令,无论是内置的还是自定义的。**
我们应该提醒自己以及我们指令的使用者,来仔细考虑添加元素、移除元素以及创建和销毁组件的后果。
{@a asterisk}
## The asterisk (*) prefix
## 星号(*)前缀
@ -290,26 +252,20 @@ Here is `*ngIf` displaying the hero's name if `hero` exists.
这里的`*ngIf`会在`hero`存在时显示英雄的名字。
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (asterisk)" region="asterisk">
</code-example>
The asterisk is "syntactic sugar" for something a bit more complicated.
Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
星号是一个用来简化更复杂语法的“语法糖”。
从内部实现来说Angular把`*ngIf` *属性* 翻译成一个`<ng-template>` *元素* 并用它来包裹宿主元素,代码如下:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template">
</code-example>
* The `*ngIf` directive moved to the `<ng-template>` element where it became a property binding,`[ngIf]`.
`*ngIf`指令被移到了`<ng-template>`元素上。在那里它变成了一个属性绑定`[ngIf]`
@ -323,13 +279,12 @@ The first form is not actually rendered, only the finished product ends up in th
第一种形态永远不会真的渲染出来。
只有最终产出的结果才会出现在DOM中。
<figure>
<img src='generated/images/guide/structural-directives/hero-div-in-dom.png' alt="hero div in DOM">
</figure>
Angular consumed the `<ng-template>` content during its actual rendering and
replaced the `<ng-template>` with a diagnostic comment.
@ -339,11 +294,8 @@ The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/struc
[`NgFor`](guide/structural-directives#ngFor)和[`NgSwitch...`](guide/structural-directives#ngSwitch)指令也都遵循同样的模式。
{@a ngFor}
## Inside _*ngFor_
## `*ngFor`内幕
@ -356,13 +308,10 @@ Here's a full-featured application of `NgFor`, written both ways:
这里有一个`NgFor`的全特性应用,同时用了这三种写法:
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (inside-ngfor)" region="inside-ngfor">
</code-example>
This is manifestly more complicated than `ngIf` and rightly so.
The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide.
At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`).
@ -375,11 +324,8 @@ You enable these features in the string assigned to `ngFor`, which you write in
我们可以通过把一个字符串赋值给`ngFor`来启用这些特性这个字符串使用Angular的[微语法](guide/structural-directives#microsyntax)。
<div class="alert is-helpful">
Everything _outside_ the `ngFor` string stays with the host element
(the `<div>`) as it moves inside the `<ng-template>`.
In this example, the `[ngClass]="odd"` stays on the `<div>`.
@ -387,14 +333,10 @@ In this example, the `[ngClass]="odd"` stays on the `<div>`.
`ngFor`字符串*之外*的每一样东西都会留在宿主元素(`<div>`)上,也就是说它移到了`<ng-template>`内部。
在这个例子中,`[ngClass]="odd"`留在了`<div>`上。
</div>
{@a microsyntax}
### Microsyntax
### 微语法
@ -460,13 +402,10 @@ is a great way to learn more.
这些微语法机制在你写自己的结构型指令时也同样有效,参考[`NgIf`的源码](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf")
和[`NgFor`的源码](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgFor") 可以学到更多。
{@a template-input-variable}
{@a template-input-variables}
### Template input variable
### 模板输入变量
@ -507,7 +446,6 @@ variable as the `hero` declared as `#hero`.
{@a one-per-element}
### One structural directive per host element
### 每个宿主元素上只能有一个结构型指令
@ -537,8 +475,6 @@ One or both elements can be an [`ng-container`](guide/structural-directives#ngco
{@a ngSwitch}
## Inside _NgSwitch_ directives
## `NgSwitch` 内幕
@ -555,8 +491,6 @@ Here's an example.
</code-example>
The switch value assigned to `NgSwitch` (`hero.emotion`) determines which
(if any) of the switch cases are displayed.
@ -581,18 +515,16 @@ The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` m
<div class="l-sub-section">
The element to which you apply a directive is its _host_ element.
The `<happy-hero>` is the host element for the happy `*ngSwitchCase`.
The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
*Design thought*: minimize initialization effort and consider caching state in a
companion service.
*设计思路*:要最小化初始化的成本,并考虑把状态缓存在一个伴生的服务中。
指令所在的元素就是它的**宿主**元素。
`<happy-hero>``*ngSwitchCase` 的宿主元素。
`<unknown-hero>``*ngSwitchDefault` 的宿主元素。
</div>
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
can be desugared into the `<ng-template>` element form.
@ -602,11 +534,8 @@ can be desugared into the `<ng-template>` element form.
</code-example>
{@a prefer-asterisk}
## Prefer the asterisk (*) syntax.
## 优先使用星号(`*`)语法
@ -627,8 +556,6 @@ You'll refer to the `<ng-template>` when you [write your own structural directiv
{@a template}
## The *&lt;ng-template&gt;*
## *&lt;ng-template&gt;*指令
@ -652,18 +579,16 @@ That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!".
</code-example>
Angular erases the middle "Hip!", leaving the cheer a bit less enthusiastic.
Angular 抹掉了中间的那个 "Hip!" ,让欢呼声显得不再那么热烈了。
<figure>
<img src='generated/images/guide/structural-directives/template-rendering.png' alt="template tag rendering">
</figure>
A structural directive puts a `<ng-template>` to work
as you'll see when you [write your own structural directive](guide/structural-directives#unless).
@ -671,11 +596,8 @@ as you'll see when you [write your own structural directive](guide/structural-di
{@a ngcontainer}
{@a ng-container}
## Group sibling elements with &lt;ng-container&gt;
## 使用&lt;ng-container&gt;把一些兄弟元素归为一组
@ -690,8 +612,6 @@ The list element (`<li>`) is a typical host element of an `NgFor` repeater.
</code-example>
When there isn't a host element, you can usually wrap the content in a native HTML container element,
such as a `<div>`, and attach the directive to that wrapper.
@ -701,8 +621,6 @@ such as a `<div>`, and attach the directive to that wrapper.
</code-example>
Introducing another container element&mdash;typically a `<span>` or `<div>`&mdash;to
group the elements under a single _root_ is usually harmless.
_Usually_ ... but not _always_.
@ -720,8 +638,6 @@ For example, suppose you have the following paragraph layout.
</code-example>
You also have a CSS style rule that happens to apply to a `<span>` within a `<p>`aragraph.
而我们的CSS样式规则是应用于`<p>`元素下的`<span>`的。
@ -730,18 +646,16 @@ You also have a CSS style rule that happens to apply to a `<span>` within a `<p>
</code-example>
The constructed paragraph renders strangely.
这样渲染出来的段落就会非常奇怪。
<figure>
<img src='generated/images/guide/structural-directives/bad-paragraph.png' alt="spanned paragraph with bad style">
</figure>
The `p span` style, intended for use elsewhere, was inadvertently applied here.
本来为其它地方准备的`p span`样式,被意外的应用到了这里。
@ -761,18 +675,16 @@ When you try this,
</code-example>
the drop down is empty.
下拉列表就是空的。
<figure>
<img src='generated/images/guide/structural-directives/bad-select.png' alt="spanned options don't work">
</figure>
The browser won't display an `<option>` within a `<span>`.
浏览器不会显示`<span>`中的`<option>`
@ -794,18 +706,16 @@ Here's the conditional paragraph again, this time using `<ng-container>`.
</code-example>
It renders properly.
这次就渲染对了。
<figure>
<img src='generated/images/guide/structural-directives/good-paragraph.png' alt="ngcontainer paragraph with proper style">
</figure>
Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
我们再用`<ng-container>`来根据条件排除选择框中的某个`<option>`
@ -814,18 +724,16 @@ Now conditionally exclude a _select_ `<option>` with `<ng-container>`.
</code-example>
The drop down works properly.
下拉框也工作正常。
<figure>
<img src='generated/images/guide/structural-directives/select-ngcontainer-anim.gif' alt="ngcontainer options work properly">
</figure>
The `<ng-container>` is a syntax element recognized by the Angular parser.
It's not a directive, component, class, or interface.
It's more like the curly braces in a JavaScript `if`-block:
@ -834,6 +742,7 @@ It's more like the curly braces in a JavaScript `if`-block:
它不是一个指令、组件、类或接口,更像是 JavaScript 中 `if` 块中的花括号。
<code-example language="javascript">
if (someCondition) {
statement1;
statement2;
@ -842,8 +751,6 @@ It's more like the curly braces in a JavaScript `if`-block:
</code-example>
Without those braces, JavaScript would only execute the first statement
when you intend to conditionally execute all of them as a single block.
The `<ng-container>` satisfies a similar need in Angular templates.
@ -853,8 +760,6 @@ The `<ng-container>` satisfies a similar need in Angular templates.
{@a unless}
## Write a structural directive
## 写一个结构型指令
@ -871,8 +776,6 @@ that does the opposite of `NgIf`.
</code-example>
Creating a directive is similar to creating a component.
创建指令很像创建组件。
@ -901,8 +804,6 @@ Here's how you might begin:
</code-example>
The directive's _selector_ is typically the directive's **attribute name** in square brackets, `[appUnless]`.
The brackets define a CSS
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors" title="MDN: Attribute selectors">attribute selector</a>.
@ -915,7 +816,6 @@ Don't use `ng`. That prefix belongs to Angular.
Pick something short that fits you or your company.
In this example, the prefix is `app`.
该指令的*属性名*应该拼写成*小驼峰*形式,并且带有一个前缀。
但是,这个前缀不能用`ng`,因为它只属于 Angular 本身。
请选择一些简短的,适合你自己或公司的前缀。
@ -954,8 +854,6 @@ You inject both in the directive constructor as private variables of the class.
</code-example>
### The _appUnless_ property
### *myUnless* 属性
@ -968,22 +866,16 @@ That means the directive needs an `appUnless` property, decorated with `@Input`
<div class="l-sub-section">
Read about `@Input` in the [_Template Syntax_](guide/template-syntax#inputs-outputs) guide.
要了解关于`@Input`的更多知识,参见[*模板语法*](guide/template-syntax#inputs-outputs)一章。
</div>
<code-example path="structural-directives/src/app/unless.directive.ts" linenums="false" title="src/app/unless.directive.ts (set)" region="set">
</code-example>
Angular sets the `appUnless` property whenever the value of the condition changes.
Because the `appUnless` property does work, it needs a setter.
@ -1011,8 +903,6 @@ The completed directive code looks like this:
</code-example>
Add this directive to the `declarations` array of the AppModule.
把这个指令添加到AppModule的`declarations`数组中。
@ -1025,28 +915,23 @@ Then create some HTML to try it.
</code-example>
When the `condition` is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears.
When the `condition` is truthy, the top (A) paragraph is removed and the bottom (B) paragraph appears.
`condition``false`时,顶部的段落就会显示出来,而底部的段落消失了。
`condition``true`时,顶部的段落被移除了,而底部的段落显示了出来。
<figure>
<img src='generated/images/guide/structural-directives/unless-anim.gif' alt="UnlessDirective in action">
</figure>
{@a summary}
## Summary
##
##
You can both try and download the source code for this guide in the <live-example></live-example>.
@ -1056,7 +941,6 @@ Here is the source from the `src/app/` folder.
本章相关的代码如下:
<code-tabs>
<code-pane title="app.component.ts" path="structural-directives/src/app/app.component.ts">
@ -1089,8 +973,6 @@ Here is the source from the `src/app/` folder.
</code-tabs>
You learned
我们学到了
@ -1117,4 +999,5 @@ You learned
* to write a [custom structural directive](guide/structural-directives#unless), `UnlessDirective`.
写了一个[自定义结构型指令](guide/structural-directives#unless) —— `UnlessDirective`

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ It is a superset of JavaScript with design-time support for type safety and tool
TypeScript是Angular应用开发中使用的主语言。
它是JavaScript的“方言”之一为类型安全和工具化而做了设计期支持。
Browsers can't execute TypeScript directly. Typescript must be "transpiled" into JavaScript using the *tsc* compiler
Browsers can't execute TypeScript directly. Typescript must be "transpiled" into JavaScript using the *tsc* compiler,
which requires some configuration.
浏览器不能直接执行TypeScript。它得先用*tsc*编译器转译(transpile)成JavaScript而且编译器需要进行一些配置。
@ -29,8 +29,6 @@ that are important to Angular developers, including details about the following
{@a tsconfig}
## *tsconfig.json*
## *tsconfig.json* 文件
@ -40,37 +38,28 @@ guide the compiler as it generates JavaScript files.
我们通常会往项目中加入一个TypeScript配置文件(`tsconfig.json`)来指导编译器如何生成JavaScript文件。
<div class="l-sub-section">
For details about `tsconfig.json`, see the official
[TypeScript wiki](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html).
要了解关于`tsconfig.json`的详情,请参阅官方提供的
[TypeScript wiki](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html)。
</div>
The [Setup](guide/setup) guide uses the following `tsconfig.json`:
我们在[搭建本地开发环境](guide/setup)中创建过如下的`tsconfig.json`
<code-example path="quickstart/src/tsconfig.1.json" title="tsconfig.json" linenums="false"></code-example>
This file contains options and flags that are essential for Angular applications.
该文件中的选项和标志是写Angular应用程序的基础。
{@a noImplicitAny}
### *noImplicitAny* and *suppressImplicitAnyIndexErrors*
### *noImplicitAny*与*suppressImplicitAnyIndexErrors*
@ -91,14 +80,12 @@ the compiler silently defaults the type to `any`. That's what is meant by *impli
如果编译器无法根据变量的用途推断出变量的类型,它就会悄悄的把变量类型默认为`any`。这就是*隐式`any`*的含义。
The documentation setup sets the `noImplicitAny` flag to `true`.
本文档在环境搭建时将`noImplicitAny`标志设置为`true`
When the `noImplicitAny` flag is `true` and the TypeScript compiler cannot infer
the type, it still generates the JavaScript files, but it also **reports an error**.
Many seasoned developers prefer this stricter setting because type checking catches more
unintentional errors at compile time.
本文档在环境搭建时将`noImplicitAny`标志设置为`true`
`noImplicitAny`标志是`true`并且TypeScript编译器无法推断出类型时它仍然会生成JavaScript文件。
但是它也会**报告一个错误**。
很多饱经沧桑的程序员更喜欢这种严格的设置,因为类型检查能在编译期间捕获更多意外错误。
@ -115,23 +102,18 @@ You can suppress them with the following additional flag:
大多数程序员可能觉得*这种错误*是个烦恼而不是助力。
我们可以使用另一个标志来禁止它们。
<code-example format=".">
"suppressImplicitAnyIndexErrors":true
</code-example>
The documentation setup sets this flag to `true` as well.
本文档在环境搭建时将`noImplicitAny`标志设置为`true`
{@a typings}
## TypeScript Typings
## TypeScript类型定义(typings)
@ -161,7 +143,8 @@ The `node_modules/@angular/core/` folder of any Angular application contains sev
很多库在自己的npm包中都包含了它们的类型定义文件TypeScript编译器和编辑器都能找到它们。Angular库也是这样的。
任何Angular应用程序的`node_modules/@angular/core/`目录下,都包含几个`d.ts`文件它们描述了Angular的各个部分。
**You need do nothing to get *typings* files for library packages that include `d.ts` files. Angular packages include them already.**
**You need do nothing to get *typings* files for library packages that include `d.ts` files.
Angular packages include them already.**
**我们不需要为那些包含了`d.ts`文件的库获取*类型定义*文件 —— Angular的所有包都是如此。**
@ -183,14 +166,12 @@ list of declaration files to be included:
因为《快速上手》的目标为`es5`,所以我们可以重写声明文件列表来包含:
<code-example format=".">
"lib": ["es2015", "dom"]
</code-example>
Thanks to that, you have all the `es6` typings even when targeting `es5`.
得益于这项设置,即使编译目标设置为`es5`,我们也能获得所有的`es6`类型信息。
@ -217,7 +198,6 @@ For instance, to install typings for `jasmine` you could do `npm install @types/
比如,要安装`jasmine`的类型信息,我们可以执行`npm install @types/jasmine --save-dev`
QuickStart identifies two *typings*, or `d.ts`, files:
我们在“快速上手”中指定过两个*类型定义*文件(`d.ts`
@ -235,10 +215,8 @@ QuickStart doesn't require these typings but many of the samples do.
“快速上手”本身不需要这些类型定义,但是文档中的很多例子都需要。
{@a target}
### *target*
By default, the target is `es5`, you can configure the target to `es6` if you only want to deploy the application to

View File

@ -27,11 +27,14 @@ which runs in a [node express](https://expressjs.com/) server.
There are three main reasons to create a Universal version of your app.
1. Facilitate web crawlers (SEO)
1. Improve performance on mobile and low-powered devices
1. Show the first page quickly
{@a seo}
{@a web-crawlers}
#### Facilitate web crawlers
Google, Bing, Facebook, Twitter and other social media sites rely on web crawlers to index your application content and make that content searchable on the web.
@ -72,6 +75,7 @@ The user perceives near-instant performance from the landing page
and gets the full interactive experience after the full app loads.
{@a how-does-it-work}
### How it works
To make a Universal app, you install the `platform-server` package.
@ -128,28 +132,72 @@ A node/express web server turns client requests into the HTML pages rendered by
You will create:
* a server-side app module, `app.server.module.ts`
* an entry point for the server-side, `main.server.ts`
* an express web server to handle requests, `server.ts`
* a TypeScript config file, `tsconfig.server.json`
* a Webpack config file for the server, `webpack.server.config.js`
When you're done, the folder structure will look like this:
<code-example format="." language="none" linenums="false">
src/
index.html <i>app web page</i>
main.ts <i>bootstrapper for client app</i>
main.server.ts <i>* bootstrapper for server app</i>
tsconfig.app.json <i>TypeScript client configuration</i>
tsconfig.server.json <i>* TypeScript server configuration</i>
tsconfig.spec.json <i>TypeScript spec configuration</i>
style.css <i>styles for the app</i>
app/ ... <i>application code</i>
app.server.module.ts <i>* server-side application module</i>
server.ts <i>* express web server</i>
tsconfig.json <i>TypeScript client configuration</i>
package.json <i>npm configuration</i>
webpack.server.config.js <i>* Webpack server configuration</i>
index.html
<i>app web page</i>
main.ts
<i>bootstrapper for client app</i>
main.server.ts
<i>* bootstrapper for server app</i>
tsconfig.app.json
<i>TypeScript client configuration</i>
tsconfig.server.json
<i>* TypeScript server configuration</i>
tsconfig.spec.json
<i>TypeScript spec configuration</i>
style.css
<i>styles for the app</i>
app/ ...
<i>application code</i>
app.server.module.ts
<i>* server-side application module</i>
server.ts
<i>* express web server</i>
tsconfig.json
<i>TypeScript client configuration</i>
package.json
<i>npm configuration</i>
webpack.server.config.js
<i>* Webpack server configuration</i>
</code-example>
The files marked with `*` are new and not in the original tutorial sample.
@ -159,6 +207,8 @@ This guide covers them in the sections below.
## Preparation
## 准备工作
Download the [Tour of Heroes](generated/zips/toh-pt6/toh-pt6.zip) project and install the dependencies from it.
{@a install-the-tools}
@ -168,14 +218,19 @@ Download the [Tour of Heroes](generated/zips/toh-pt6/toh-pt6.zip) project and in
To get started, install these packages.
* `@angular/platform-server` - Universal server-side components.
* `@nguniversal/module-map-ngfactory-loader` - For handling lazy-loading in the context of a server-render.
* `@nguniversal/express-engine` - An express engine for Universal applications.
* `ts-loader` - To transpile the server application
Install them with the following commands:
<code-example format="." language="bash">
npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader @nguniversal/express-engine
</code-example>
{@a transition}
@ -196,6 +251,7 @@ Open file `src/app/app.module.ts` and find the `BrowserModule` import in the `Ng
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>
Angular adds the `appId` value (which can be _any_ string) to the style-names of the server-rendered pages,
@ -204,6 +260,7 @@ so that they can be identified and removed when the client app starts.
You can get runtime information about the current platform and the `appId` by injection.
<code-example path="universal/src/app/app.module.ts" region="platform-detection" title="src/app/app.module.ts (platform detection)">
</code-example>
{@a http-urls}
@ -225,6 +282,7 @@ inject it into the service, and prepend the origin to the request URL.
Start by changing the `HeroService` constructor to take a second `origin` parameter that is optionally injected via the `APP_BASE_HREF` token.
<code-example path="universal/src/app/hero.service.ts" region="ctor" title="src/app/hero.service.ts (constructor with optional origin)">
</code-example>
Note how the constructor prepends the origin (if it exists) to the `heroesUrl`.
@ -254,6 +312,7 @@ The app server module class (conventionally named `AppServerModule`) is an Angul
Create an `app.server.module.ts` file in the `src/app/` directory with the following `AppServerModule` code:
<code-example path="universal/src/app/app.server.module.ts" title="src/app/app.server.module.ts">
</code-example>
Notice that it imports first the client app's `AppModule`, the Angular Universal's `ServerModule` and the `ModuleMapLoaderModule`.
@ -284,6 +343,7 @@ The sample web server for _this_ guide is based on the popular [Express](https:/
Create a `server.ts` file in the root directory and add the following code:
<code-example path="universal/server.ts" title="server.ts">
</code-example>
<div class="alert is-critical">
@ -295,11 +355,13 @@ Create a `server.ts` file in the root directory and add the following code:
</div>
{@a universal-engine}
#### Universal template engine
The important bit in this file is the `ngExpressEngine` function:
<code-example path="universal/server.ts" title="server.ts" region="ngExpressEngine">
</code-example>
The `ngExpressEngine` is a wrapper around the universal's `renderModuleFactory` function that turns a client's requests into server-rendered HTML pages.
@ -347,7 +409,9 @@ All static asset requests have a file extension (e.g., `main.js` or `/node_modul
So we can easily recognize the three types of requests and handle them differently.
1. data request - request URL that begins `/api`
2. app navigation - request URL with no file extension
3. static asset - all other requests.
An Express server is a pipeline of middleware that filters and processes URL requests one after the other.
@ -355,6 +419,7 @@ An Express server is a pipeline of middleware that filters and processes URL req
You configure the Express server pipeline with calls to `app.get()` like this one for data requests.
<code-example path="universal/server.ts" title="server.ts (data URL)" region="data-request" linenums="false">
</code-example>
<div class="l-sub-section">
@ -384,6 +449,7 @@ If your server handles HTTP requests, you'll have to add your own security plumb
The following code filters for request URLs with no extensions and treats them as navigation requests.
<code-example path="universal/server.ts" title="server.ts (navigation)" region="navigation-request" linenums="false">
</code-example>
#### Serve static files safely
@ -397,6 +463,7 @@ and will only honor requests for files from the `/dist` folder.
The following express code routes all remaining requests to `/dist`; it returns a `404 - NOT FOUND` if the file is not found.
<code-example path="universal/server.ts" title="server.ts (static files)" region="static" linenums="false">
</code-example>
{@a universal-configuration}
@ -412,6 +479,7 @@ The server application requires its own build configuration.
Create a `tsconfig.server.json` file in the project root directory to configure TypeScript and AOT compilation of the universal app.
<code-example path="universal/src/tsconfig.server.json" title="src/tsconfig.server.json">
</code-example>
This config extends from the root's `tsconfig.json` file. Certain settings are noteworthy for their differences.
@ -419,6 +487,7 @@ This config extends from the root's `tsconfig.json` file. Certain settings are n
* The `module` property must be **commonjs** which can be require()'d into our server application.
* The `angularCompilerOptions` section guides the AOT compiler:
* `entryModule` - the root module of the server application, expressed as `path/to/file#ClassName`.
### Universal Webpack configuration
@ -429,6 +498,7 @@ but since the server is a typescript application, you will use Webpack to transp
Create a `webpack.server.config.js` file in the project root directory with the following code.
<code-example path="universal/webpack.server.config.js" title="webpack.server.config.js">
</code-example>
**Webpack configuration** is a rich topic beyond the scope of this guide.
@ -440,6 +510,7 @@ Now that you've created the TypeScript and Webpack config files, you can build a
First add the _build_ and _serve_ commands to the `scripts` section of the `package.json`:
<code-example format="." language="ts">
"scripts": {
...
"build:universal": "npm run build:client-and-server-bundles && npm run webpack:server",
@ -448,6 +519,7 @@ First add the _build_ and _serve_ commands to the `scripts` section of the `pack
"webpack:server": "webpack --config webpack.server.config.js --progress --colors"
...
}
</code-example>
{@a build}
@ -457,7 +529,9 @@ First add the _build_ and _serve_ commands to the `scripts` section of the `pack
From the command prompt, type
<code-example format="." language="bash">
npm run build:universal
</code-example>
The Angular CLI compiles and bundles the universal app into two different folders, `browser` and `server`.
@ -466,16 +540,21 @@ Webpack transpiles the `server.ts` file into Javascript.
{@a serve}
#### Serve
After building the application, start the server.
<code-example format="." language="bash">
npm run serve:universal
</code-example>
The console window should say
<code-example format="." language="bash">
Node server listening on http://localhost:4000
</code-example>
## Universal in action
@ -490,8 +569,11 @@ You can click on a hero on the Dashboard page to display its Details page.
But clicks, mouse-moves, and keyboard entries are inert.
* Clicking a hero on the Heroes page does nothing.
* You can't add or delete a hero.
* The search box on the Dashboard page is ignored.
* The _back_ and _save_ buttons on the Details page don't work.
User events other than `routerLink` clicks aren't supported.
@ -514,13 +596,18 @@ Try one of the "3G" speeds.
The server-rendered app still launches quickly but the full client app may take seconds to load.
{@a summary}
## Summary
## 小结
This guide showed you how to take an existing Angular application and make it into a Universal app that does server-side rendering.
It also explained some of the key reasons for doing so.
- Facilitate web crawlers (SEO)
- Support low-bandwidth or low-power devices
- Fast first page load
Angular Universal can greatly improve the perceived startup performance of your app.

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,6 @@ Run the <live-example></live-example>.
运行<live-example></live-example>
## Binding to user input events
## 绑定到用户输入事件
@ -37,7 +35,6 @@ The following example shows an event binding that implements a click handler:
下例展示了一个事件绑定,它实现了一个点击事件处理器:
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-button" title="src/app/click-me.component.ts" linenums="false">
</code-example>
@ -46,7 +43,7 @@ The following example shows an event binding that implements a click handler:
The `(click)` to the left of the equals sign identifies the button's click event as the **target of the binding**.
The text in quotes to the right of the equals sign
is the **template statement**, which reponds
is the **template statement**, which responds
to the click event by calling the component's `onClickMe` method.
等号左边的`(click)`表示把按钮的点击事件作为**绑定目标**。
@ -62,18 +59,14 @@ The example above shows a single line of HTML, but that HTML belongs to a larger
这个对象通常都是控制此模板的 Angular 组件。
上例中只显示了一行 HTML那段 HTML 片段属于下面这个组件:
<code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" title="src/app/click-me.component.ts" linenums="false">
</code-example>
When the user clicks the button, Angular calls the `onClickMe` method from `ClickMeComponent`.
当用户点击按钮时Angular 调用`ClickMeComponent``onClickMe`方法。
## Get user input from the $event object
## 通过 $event 对象取得用户输入
@ -88,26 +81,20 @@ The following code listens to the `keyup` event and passes the entire event payl
下面的代码监听`keyup`事件,并将整个事件载荷 (`$event`) 传递给组件的事件处理器。
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-template" title="src/app/keyup.components.ts (template v.1)" linenums="false">
</code-example>
When a user presses and releases a key, the `keyup` event occurs, and Angular provides a corresponding
DOM event object in the `$event` variable which this code passes as a parameter to the component's `onKey()` method.
当用户按下并释放一个按键时,触发`keyup`事件Angular 在`$event`变量提供一个相应的 DOM
事件对象,上面的代码将它作为参数传递给`onKey()`方法。
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-1-class-no-type" title="src/app/keyup.components.ts (class v.1)" linenums="false">
</code-example>
The properties of an `$event` object vary depending on the type of DOM event. For example,
a mouse event includes different information than a input box editing event.
@ -138,40 +125,34 @@ Here's what the UI displays:
用户界面将显示:
<code-example>
a | ab | abc | ab | a | |
</code-example>
<figure>
<img src='generated/images/guide/user-input/keyup1-anim.gif' alt="key up 1">
</figure>
<div class="l-sub-section">
Alternatively, you could accumulate the individual keys themselves by substituting `event.key`
for `event.target.value` in which case the same user input would produce:
或者,你可以用`event.key`替代`event.target.value`,积累各个按键本身,这样同样的用户输入可以产生:
<code-example>
a | b | c | backspace | backspace | backspace |
</code-example>
</div>
{@a keyup1}
### Type the _$event_
### *$event*的类型
@ -193,8 +174,6 @@ The following example rewrites the method with types:
</code-example>
The `$event` is now a specific `KeyboardEvent`.
Not all elements have a `value` property so it casts `target` to an input element.
The `OnKey` method more clearly expresses what it expects from the template and how it interprets the event.
@ -221,8 +200,6 @@ The next section shows how to use template reference variables to address this p
下面将介绍如何用模板引用变量来解决这个问题。
## Get user input from a template reference variable
## 从一个模板引用变量中获得用户输入
@ -245,8 +222,6 @@ to implement a keystroke loopback in a simple template.
</code-example>
The template reference variable named `box`, declared on the `<input>` element,
refers to the `<input>` element itself.
The code uses the `box` variable to get the input element's `value` and display it
@ -264,38 +239,31 @@ Type something in the input box, and watch the display update with each keystrok
在输入框中输入,就会看到每次按键时,显示也随之更新了。
<figure>
<img src='generated/images/guide/user-input/keyup-loop-back-anim.gif' alt="反馈">
<img src='generated/images/guide/user-input/keyup-loop-back-anim.gif' alt="loop back">
</figure>
<div class="l-sub-section">
**This won't work at all unless you bind to an event**.
**除非你绑定一个事件,否则这将完全无法工作。**
Angular updates the bindings (and therefore the screen)
only if the app does something in response to asynchronous events, such as keystrokes.
只有在应用做了些异步事件如击键Angular 才更新绑定(并最终影响到屏幕)。
This example code binds the `keyup` event
to the number 0, the shortest template statement possible.
While the statement does nothing useful,
it satisfies Angular's requirement so that Angular will update the screen.
本例代码将`keyup`事件绑定到了数字0这是可能是最短的模板语句。
只有在应用做了些异步事件如击键Angular 才更新绑定(并最终影响到屏幕)。
本例代码将`keyup`事件绑定到了数字0这可能是最短的模板语句了。
虽然这个语句不做什么,但它满足 Angular 的要求,所以 Angular 将更新屏幕。
</div>
It's easier to get to the input box with the template reference
variable than to go through the `$event` object. Here's a rewrite of the previous
`keyup` example that uses a template reference variable to get the user's input.
@ -307,14 +275,12 @@ variable than to go through the `$event` object. Here's a rewrite of the previou
</code-example>
A nice aspect of this approach is that the component gets clean data values from the view.
It no longer requires knowledge of the `$event` and its structure.
这个方法最漂亮的一点是:组件代码从视图中获得了干净的数据值。再也不用了解`$event`变量及其结构了。
{@a key-event}
{@a key-event}
## Key event filtering (with `key.enter`)
@ -338,19 +304,16 @@ Then Angular calls the event handler only when the user presses _Enter_.
</code-example>
Here's how it works.
下面展示了它是如何工作的。
<figure>
<img src='generated/images/guide/user-input/keyup3-anim.gif' alt="key up 3">
</figure>
## On blur
## 失去焦点事件 (blur)
@ -367,14 +330,10 @@ To fix this issue, listen to both the _Enter_ key and the _blur_ event.
下面通过同时监听输入框的回车键和失去焦点事件来修正这个问题。
<code-example path="user-input/src/app/keyup.components.ts" region="key-up-component-4" title="src/app/keyup.components.ts (v4)" linenums="false">
</code-example>
## Put it all together
## 把它们放在一起
@ -393,18 +352,16 @@ clicking **Add**.
现在,在一个微型应用中一起使用它们,应用能显示一个英雄列表,并把新的英雄加到列表中。
用户可以通过输入英雄名和点击“添加”按钮来添加英雄。
<figure>
<img src='generated/images/guide/user-input/little-tour-anim.gif' alt="简版英雄指南">
<img src='generated/images/guide/user-input/little-tour-anim.gif' alt="Little Tour of Heroes">
</figure>
Below is the "Little Tour of Heroes" component.
下面就是“简版英雄指南”组件。
<code-example path="user-input/src/app/little-tour.component.ts" region="little-tour" title="src/app/little-tour.component.ts" linenums="false">
</code-example>
@ -436,8 +393,6 @@ clears the input box after a new hero is added to the list.
`(blur)`事件被绑定到两个 JavaScript 语句。
第一句调用`addHero`。第二句`newHero.value=''`在添加新英雄到列表中后清除输入框。
## Source code
## 源代码
@ -466,9 +421,6 @@ Following is all the code discussed in this page.
</code-tabs>
## Summary
## 小结
@ -484,6 +436,7 @@ values between data entry fields and model properties.
The next page, `Forms`, explains how to write
two-way bindings with `NgModel`.
这些技术对小规模演示很实用,但是在处理大量用户输入时,很容易变得累赘和笨拙。
要在数据录入字段和模型属性之间传递数据,双向数据绑定是更加优雅和简洁的方式。
下一章`表单`解释了如何用`NgModel`来进行双向绑定。

View File

@ -13,20 +13,15 @@ Angular QuickStart files in **Visual Studio 2015 within an ASP.NET 4.x project**
本烹饪宝典介绍了在**Visual Studio 2015的ASP.NET 4.x项目中**用Angular实现“快速上手”所需的步骤。
<div class="l-sub-section">
There is no *live example* for this cookbook because it describes Visual Studio, not
the QuickStart application itself.
本烹饪宝典中没有*在线例子*因为它介绍的是Visual Studio而不是《快速上手》应用程序本身。
</div>
{@a asp-net-4}
## ASP.NET 4.x Project
@ -40,8 +35,6 @@ Visual Studio 2015, follow these steps:
<div class="l-sub-section">
If you prefer a `File | New Project` experience and are using **ASP.NET Core**,
then consider the _experimental_
<a href="http://blog.stevensanderson.com/2016/10/04/angular2-template-for-visual-studio/">ASP.NET Core + Angular template for Visual Studio 2015</a>.
@ -51,32 +44,23 @@ Note that the resulting code does not map to the docs. Adjust accordingly.
参见_预览版_<a href="http://blog.stevensanderson.com/2016/10/04/angular2-template-for-visual-studio/" target="_blank">ASP.NET Core + Angular template for Visual Studio 2015</a>
注意,最终代码与本文不对应,请适当调节。
</div>
<h2 id='prereq1'>
Prerequisite: Node.js
</h2>
<h2 id='prereq1'>
前提条件: Node.js
</h2>
Install **[Node.js® and npm](https://nodejs.org/en/download/)**
if they are not already on your machine.
如果你的电脑里没有Node.js®和npm请安装**[它们](https://nodejs.org/en/download/)**。
<div class="l-sub-section">
**Verify that you are running node version `4.6.x` or greater, and npm `3.x.x` or greater**
by running `node -v` and `npm -v` in a terminal window.
Older versions produce errors.
@ -85,19 +69,14 @@ Older versions produce errors.
</div>
<h2 id='prereq2'>
Prerequisite: Visual Studio 2015 Update 3
</h2>
<h2 id='prereq2'>
前提条件: Visual Studio 2015 Update 3
</h2>
The minimum requirement for developing Angular applications with Visual Studio is Update 3.
Earlier versions do not follow the best practices for developing applications with TypeScript.
To view your version of Visual Studio 2015, go to `Help | About Visual Studio`.
@ -111,18 +90,14 @@ Or use `Tools | Extensions and Updates` to update to Update 3 directly from Visu
如果还没有,安装**[Visual Studio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs)**。或者使用`Tools | Extensions and Updates`来直接在Visual Studio 2015中更新到Update 3。
<h2 id='prereq3'>
Prerequisite: Configure External Web tools
</h2>
<h2 id='prereq3'>
前提条件: 配置External Web tools
</h2>
Configure Visual Studio to use the global external web tools instead of the tools that ship with Visual Studio:
配置Visual Studio来使用全局External Web Tools而非Visual Studio默认的工具
@ -131,26 +106,22 @@ Configure Visual Studio to use the global external web tools instead of the tool
`Tools` | `Options`打开**Options**对话框
* In the tree on the left, select `Projects and Solutions` | `External Web Tools`.
在左边树型项目中,选择`Projects and Solutions` | `External Web Tools`
* On the right, move the `$(PATH)` entry above the `$(DevEnvDir`) entries. This tells Visual Studio to
use the external tools (such as npm) found in the global path before using its own version of the external tools.
* 在右侧,将`$(PATH)`移动到 `$(DevEnvDir`)上面。这样Visual Stuio就会在使用自带的外部工具时优先使用全局路径中的外部工具比如npm
Click OK to close the dialog.
* Click OK to close the dialog.
点击OK关闭对话框。
* 点击OK关闭对话框。
* Restart Visual Studio for this change to take effect.
Restart Visual Studio for this change to take effect.
* 重启Visual Studio以让设置变化生效。
重启Visual Studio以让设置变化生效。
Visual Studio now looks first for external tools in the current workspace and
if it doesn't find them, it looks in the global path. If Visual Studio doesn't
@ -158,18 +129,14 @@ find them in either location, it will use its own versions of the tools.
Visual Studio将优先在当前的工作区查找外部工具如果没有找到便查找全局路径如果还没有找到Visual Studio就使用自带的工具版本。
<h2 id='prereq4'>
Prerequisite: Install TypeScript 2.2 for Visual Studio 2015
</h2>
<h2 id='prereq4'>
前提条件: 安装TypeScript 2.2 for Visual Studio 2015
</h2>
While Visual Studio Update 3 ships with TypeScript support out of the box, it currently doesnt ship with TypeScript 2.2,
which you need to develop Angular applications.
@ -196,35 +163,27 @@ restart it to make sure everything is clean.
至此Visual Studio准备好了。重新启动Visual Stuido这样我们可以有一个崭新的开始。
<h2 id='download'>
Step 1: Download the QuickStart files
</h2>
<h2 id='download'>
第一步: 现在“快速上手”文件
</h2>
[Download the QuickStart source](https://github.com/angular/quickstart)
from GitHub. If you downloaded as a zip file, extract the files.
从GitHub[下载“快速上手”的源代码](https://github.com/angular/quickstart)。如果下载的是一个压缩的zip文件解压它。
<h2 id='create-project'>
Step 2: Create the Visual Studio ASP.NET project
</h2>
<h2 id='create-project'>
第二步创建Visual Studio ASP.net项目
</h2>
Create the ASP.NET 4.x project in the usual way as follows:
按照下列步骤创建ASP.NET 4.x项目
@ -233,50 +192,35 @@ Create the ASP.NET 4.x project in the usual way as follows:
在Visual Studio中选择`File` | `New` | `Project`菜单。
* In the template tree, select `Templates` | `Visual C#` (or `Visual Basic`) | `Web`.
在模板树中,选择`Templates` | `Visual C#`(或`Visual Basic`) | `Web`菜单。
* Select the `ASP.NET Web Application` template, give the project a name, and click OK.
选择`ASP.NET Web Application`模板输入项目名点击“OK”按钮。
* Select the desired ASP.NET 4.5.2 template and click OK.
选择自己喜欢的ASP.NET 4.5.2模板点击OK。
<div class="l-sub-section">
This cookbook uses the `Empty` template with no added folders,
no authentication, and no hosting. Pick the template and options appropriate for your project.
本烹饪宝典选择了`Empty`模板,它没有添加过任何目录,没有身份验证,没有服务器托管。为你的项目选择合适的模板和选项。
</div>
<h2 id='copy'>
Step 3: Copy the QuickStart files into the ASP.NET project folder
</h2>
<h2 id='copy'>
第三步: 把“快速上手”的文件复制到ASP.NET项目所在的目录
</h2>
Copy the QuickStart files you downloaded from GitHub into the folder containing the `.csproj` file.
Include the files in the Visual Studio project as follows:
@ -286,7 +230,6 @@ Include the files in the Visual Studio project as follows:
在Solution Explorer中点击`Show All Files`按钮,显示项目中所有隐藏文件。
* Right-click on each folder/file to be included in the project and select `Include in Project`.
Minimally, include the following folder/files:
@ -305,13 +248,13 @@ Include the files in the Visual Studio project as follows:
* src/tsconfig.json
* typings.json
<h2 id='restore'>
Step 4: Restore the required packages
<h2 id='restore'> Step 4: Restore the required packages </h2>
<h2 id='restore'> 第四步: 恢复需要的包 </h2>
第四步: 恢复需要的包
</h2>
Restore the packages required for an Angular application as follows:
@ -346,21 +289,14 @@ Restore the packages required for an Angular application as follows:
**不要**将`node_modules`目录添加到项目中,让它隐藏。
<h2 id='build-and-run'>
Step 5: Build and run the app
</h2>
<h2 id='build-and-run'>
第五步:构建和运行应用
</h2>
First, ensure that `src/index.html` is set as the start page.
Right-click `index.html` in Solution Explorer and select option `Set As Start Page`.
@ -393,8 +329,6 @@ change the npm `path` to `/node_modules/` with a slash.
<div class="alert is-important">
After these changes, `npm start` no longer works.
You must choose to configure _either_ for F5 with IIS _or_ for `npm start` with the lite-server.
@ -402,8 +336,6 @@ You must choose to configure _either_ for F5 with IIS _or_ for `npm start` with
</div>
### For apps that use routing
### 为了使用路由的应用
@ -452,6 +384,7 @@ rewrite rules near the bottom of the `web.config`:
通过把下列重写规则添加到`web.config`的底部,就可以告诉 Visual Studio如何处理到应用页面的请求。
<code-example format='.'>
&lt;system.webServer&gt;
&lt;rewrite&gt;
&lt;rules&gt;
@ -469,12 +402,8 @@ rewrite rules near the bottom of the `web.config`:
</code-example>
<div class="l-sub-section">
The match url, `<match url=".*" />`, will rewrite every request. You'll have to adjust this if
you want some requests to get through, such as web API requests.
@ -487,26 +416,18 @@ match the base href in `index.html`.
</div>
Build and launch the app with debugger by clicking the **Run** button or by pressing `F5`.
点击**Run**按钮或者按`F5`键,用调试器构建和启动应用。
<div class="l-sub-section">
It's faster to run without the debugger by pressing `Ctrl-F5`.
`Ctrl-F5`不带调试器的运行应用,速度会更快。
</div>
The default browser opens and displays the QuickStart sample application.
默认浏览器打开并显示《快速上手》例子应用。
@ -514,4 +435,5 @@ The default browser opens and displays the QuickStart sample application.
Try editing any of the project files. Save and refresh the browser to
see the changes.
尝试编辑任何项目文件,*保存*并刷新浏览器来查看效果。

View File

@ -3,13 +3,12 @@
# Webpack简介
<style>
h4 {font-size: 17px !important; text-transform: none !important;}
.syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; }
</style>
[**Webpack**](https://webpack.github.io/) is a popular module bundler,
a tool for bundling application source code in convenient _chunks_
and for loading that code from a server into a browser.
@ -22,12 +21,10 @@ This guide offers a taste of Webpack and explains how to use it with Angular app
它是我们在文档中到处使用的*SystemJS*的一个优秀替代品。这篇指南会带我们尝尝Webpack的滋味并解释如何在Angular程序中使用它。
{@a top}
<!--
# Contents
# 目录
@ -144,11 +141,8 @@ You determine what Webpack does and how it does it with a JavaScript configurati
我们通过一个JavaScript配置文件`webpack.config.js`来决定Webpack做什么以及如何做。
{@a entries-outputs}
### Entries and outputs
### 入口与输出
@ -159,24 +153,18 @@ The one entry point file in this example is the application's root file, `src/ma
我们给Webpack提供一个或多个*入口*文件,来让它查找与合并那些从这些入口点发散出去的依赖。
在下面这个例子中,我们的入口点是该应用的根文件`src/app.ts`
<code-example path="webpack/config/webpack.common.js" region="one-entry" title="webpack.config.js (single entry)" linenums="false">
</code-example>
Webpack inspects that file and traverses its `import` dependencies recursively.
Webpack探查那个文件并且递归遍历它的`import`依赖。
<code-example path="webpack/src/app/app.component.ts" region="component" title="src/main.ts" linenums="false">
</code-example>
It sees that you're importing `@angular/core` so it adds that to its dependency list for potential inclusion in the bundle.
It opens the `@angular/core` file and follows _its_ network of `import` statements until it has built the complete dependency graph from `main.ts` down.
@ -188,6 +176,7 @@ Then it **outputs** these files to the `app.js` _bundle file_ designated in conf
然后它把这些文件**输出**到当前配置所指定的_包文件_`app.js`中:
<code-example name="webpack.config.js (single output)" language="javascript">
output: {
filename: 'app.js'
}
@ -200,10 +189,8 @@ You'll load it later with a `<script>` tag in the `index.html`.
这个`app.js`输出包是个单一的JavaScript文件它包含程序的源码及其所有依赖。
后面我们将在`index.html`中用`<script>`标签来加载它。
{@a multiple-bundles}
#### Multiple bundles
#### 多重包
@ -217,8 +204,8 @@ Change the configuration so that it has two entry points, `main.ts` and `vendor.
所以要修改配置,以获得两个入口点:`main.ts``vendor.ts`
<code-example language="javascript">
entry: {
app: 'src/app.ts',
vendor: 'src/vendor.ts'
@ -230,44 +217,32 @@ Change the configuration so that it has two entry points, `main.ts` and `vendor.
</code-example>
Webpack constructs two separate dependency graphs
and emits *two* bundle files, one called `app.js` containing only the application code and
another called `vendor.js` with all the vendor dependencies.
Webpack会构造出两个独立的依赖图谱并产出*两个*包文件:一个叫做`app.js`,它只包含我们的应用代码;另一个叫做`vendor.js`,它包含所有的提供商依赖。
<div class="l-sub-section">
The `[name]` in the output name is a *placeholder* that a Webpack plugin replaces with the entry names,
`app` and `vendor`. Plugins are [covered later](guide/webpack#commons-chunk-plugin) in the guide.
在输出文件名中出现的`[name]`是一个Webpack的*占位符*它将被一个Webpack插件替换为入口点的名字分别是`app``vendor`。插件在本章的[稍后部分](guide/webpack#commons-chunk-plugin)讲解。
</div>
To tell Webpack what belongs in the vendor bundle,
add a `vendor.ts` file that only imports the application's third-party modules:
要想告诉Webpack哪些文件属于vendor包可以添加一个`vendor.ts`文件,它只导入该应用的第三方模块:
<code-example path="webpack/src/vendor.ts" title="src/vendor.ts" linenums="false">
</code-example>
{@a loaders}
### Loaders
### 加载器(Loader)
@ -282,8 +257,8 @@ Webpack可以打包任何类型的文件JavaScript、TypeScript、CSS、SASS
我们要通过*加载器*来告诉它如何把这些文件处理成JavaScript文件。
在这里我们为TypeScript和CSS文件配置了加载器。
<code-example language="javascript">
rules: [
{
test: /\.ts$/,
@ -297,23 +272,19 @@ Webpack可以打包任何类型的文件JavaScript、TypeScript、CSS、SASS
</code-example>
When Webpack encounters `import` statements like the following,
it applies the `test` RegEx patterns.
当Webpack遇到如下所示的`import`语句时,它就会调用正则表达式的`test`方法。
<code-example language="typescript">
import { AppComponent } from './app.component.ts';
import 'uiframework/dist/uiframework.css';
</code-example>
When a pattern matches the filename, Webpack processes the file with the associated loader.
如果一个模式匹配上文件名Webpack就用它所关联的加载器处理这个文件。
@ -333,11 +304,8 @@ the `css` loader first to flatten CSS `@import` and `url(...)` statements.
Webpack会*从右到左*逐个应用串联的加载器,于是它先应用了`css`加载器(用来平面化CSS的`@import``url(...)`语句)
然后应用了`style`加载器(用来把css追加到页面上的*&lt;style&gt;*元素中)。
{@a plugins}
### Plugins
### 插件
@ -349,18 +317,15 @@ Webpack有一条构建流水线它被划分成多个经过精心定义的阶
我们可以把插件(比如`uglify`代码最小化插件)挂到流水线上:
<code-example language="javascript">
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
</code-example>
{@a configure-webpack}
## Configuring Webpack
## 配置Webpack
@ -377,19 +342,16 @@ Create a new project folder.
创建一个新的项目文件夹。
<code-example language="sh" class="code-shell">
mkdir angular-webpack
cd angular-webpack
</code-example>
Add these files:
把下列文件添加到根目录下:
添加下列文件:
<code-tabs>
@ -415,12 +377,8 @@ Add these files :
</code-tabs>
<div class="l-sub-section">
Many of these files should be familiar from other Angular documentation guides,
especially the [Typescript configuration](guide/typescript-configuration) and
[npm packages](guide/npm-packages) guides.
@ -432,27 +390,20 @@ They are listed in the updated `packages.json`.
Webpack包括它的插件以及加载器也是以npm包的形式安装的它们也列在了修改后的 package.json 中。
</div>
Open a terminal window and install the npm packages.
打开命令行窗口并安装这些*npm*包
<code-example language="sh" class="code-shell">
npm install
</code-example>
{@a polyfills}
### Polyfills
### Polyfills 腻子脚本
@ -467,42 +418,31 @@ Add a `polyfills.ts` like this one to the `src/` folder.
Polyfills最好跟应用代码和vendor代码区分开来单独打包所以我们需要在`src/`文件夹里添加一个`polyfills.ts`文件,代码如下:
<code-example path="webpack/src/polyfills.ts" title="src/polyfills.ts" linenums="false">
</code-example>
<div class="callout is-critical">
<header>
Loading polyfills
</header>
Load `zone.js` early within `polyfills.ts`, immediately after the other ES6 and metadata shims.
`polyfills.ts`文件里,`zone.js`库须尽早引入紧跟在ES6 shims和metadata shims之后。
</div>
Because this bundle file will load first, `polyfills.ts` is also a good place to configure the browser environment
for production or development.
由于这个包最先加载,所以`polyfills.ts`非常适合用来配置浏览器环境,如生产环境配置或是开发环境。
{@a common-configuration}
### Common configuration
### 通用配置
@ -516,16 +456,12 @@ Gather the common configuration in a file called `webpack.common.js`.
我们可以把这些通用的配置收归到一个文件,命名为`webpack.common.js`
<code-example path="webpack/config/webpack.common.js" title="config/webpack.common.js" linenums="false">
</code-example>
{@a inside-webpack-commonjs}
### Inside _webpack.common.js_
### webpack.common.js解读
@ -555,10 +491,8 @@ and exports several objects as properties of a `module.exports` object.
[`plugins`](guide/webpack#common-plugins) - 创建插件的实例。
{@a common-entries}
#### _entry_
#### _entry_ 入口
@ -567,13 +501,10 @@ The first export is the `entry` object:
如上所述,第一个导出的对象是*entries*
<code-example path="webpack/config/webpack.common.js" region="entries" title="config/webpack.common.js" linenums="false">
</code-example>
This `entry` object defines the three bundles:
`entry`对象定义了三个包:
@ -590,10 +521,8 @@ This `entry` object defines the three bundles:
`app` - 应用代码。
{@a common-resolves}
#### _resolve_ extension-less imports
#### _resolve_ 无扩展名的文件导入
@ -604,43 +533,32 @@ You could write `import` statements with explicit extensions like this example:
如果你的应用程序只须`import`几十个JavaScript或TypeScript文件而不是几百个你可以在`import`语句里完整写上扩展名,如:
<code-example language="typescript">
import { AppComponent } from './app.component.ts';
</code-example>
But most `import` statements don't mention the extension at all.
Tell Webpack to resolve extension-less file requests by looking for matching files with
`.ts` extension or `.js` extension (for regular JavaScript files and pre-compiled TypeScript files).
但实际上大部分`import`语句都不带扩展名我们可以告诉Webpack在查找这些没有扩展名的文件时自动加上`.ts`或者`.js`扩展名来匹配。
<code-example path="webpack/config/webpack.common.js" region="resolve" title="config/webpack.common.js" linenums="false">
</code-example>
<div class="l-sub-section">
If Webpack should resolve extension-less files for styles and HTML,
add `.css` and `.html` to the list.
如果我们希望Webapck也能解析不带扩展名的样式和HTML文件在列表里追加`.css``.html`即可。
</div>
{@a common-rules}
#### _module.rules_
#### _module.rules_ 规则
@ -649,13 +567,10 @@ Rules tell Webpack which loaders to use for each file, or module:
Rules用来告诉Webpack加载不同文件或模块时该用哪个加载器。
<code-example path="webpack/config/webpack.common.js" region="loaders" title="config/webpack.common.js" linenums="false">
</code-example>
* `awesome-typescript-loader`&mdash;a loader to transpile the Typescript code to ES5, guided by the `tsconfig.json` file.
`awesome-typescript-loader` - 一个用于把TypeScript代码转译成ES5的加载器它会由`tsconfig.json`文件提供指导
@ -677,11 +592,8 @@ component-scoped styles (the ones specified in a component's `styleUrls` metadat
CSS - 第一个模式匹配应用级样式,第二个模式匹配组件局部样式(就是在组件元数据的`styleUrls`属性中指定的那些)。
<div class="l-sub-section">
The first pattern is for the application-wide styles. It excludes `.css` files within the `src/app` directory
where the component-scoped styles sit. The `ExtractTextPlugin` (described below) applies the `style` and `css`
loaders to these files.
@ -695,29 +607,18 @@ which is what Angular expects to do with styles specified in a `styleUrls` metad
第二个模式过滤器是给组件局部样式的,并通过`raw`加载器把它们加载成字符串 —— 那是Angular期望通过元数据的`styleUrls`属性来指定样式的形式。
</div>
<div class="l-sub-section">
Multiple loaders can be chained using the array notation.
多重加载器也能使用数组形式串联起来。
</div>
{@a common-plugins}
#### _plugins_
#### _插件_
@ -726,16 +627,12 @@ Finally, create instances of three plugins:
最后,创建三个插件实例:
<code-example path="webpack/config/webpack.common.js" region="plugins" title="config/webpack.common.js" linenums="false">
</code-example>
{@a commons-chunk-plugin}
#### *CommonsChunkPlugin*
#### *CommonsChunkPlugin* 插件
@ -752,11 +649,8 @@ The `CommonsChunkPlugin` does that job.
Webpack还没有智能到自动把提供商代码排除在`app.js`包之外的程度。
`CommonsChunkPlugin`插件能完成此工作。
<div class="l-sub-section">
The `CommonsChunkPlugin` identifies the hierarchy among three _chunks_: `app` -> `vendor` -> `polyfills`.
Where Webpack finds that `app` has shared dependencies with `vendor`, it removes them from `app`.
It would remove `polyfills` from `vendor` if they shared dependencies, which they don't.
@ -765,14 +659,10 @@ It would remove `polyfills` from `vendor` if they shared dependencies, which the
当Webpack发现`app``vendor`有共享依赖时,就把它们从`app`中移除。
`vendor``polyfills`之间有共享依赖时也同样如此(虽然它们没啥可共享的)。
</div>
{@a html-webpack-plugin}
#### _HtmlWebpackPlugin_
#### _HtmlWebpackPlugin_ 插件
@ -785,11 +675,8 @@ Webpack生成了一些js和css文件。
虽然我们_可以手动_把它们插入到`index.html`中,但那样既枯燥又容易出错。
Webpack可以通过`HtmlWebpackPlugin`自动为我们注入那些`script``link`标签。
{@a environment-configuration}
### Environment-specific configuration
### 环境相关的配置
@ -805,11 +692,8 @@ These files tend to be short and simple.
这些文件越小越简单越好。
{@a development-configuration}
### Development configuration
### 开发环境配置
@ -818,13 +702,10 @@ Here is the `webpack.dev.js` development configuration file.
下面是开发环境的而配置文件`webpack.dev.js`
<code-example path="webpack/config/webpack.dev.js" title="config/webpack.dev.js" linenums="false">
</code-example>
The development build relies on the Webpack development server, configured near the bottom of the file.
开发环境下的构建依赖于Webpack的开发服务器我们在靠近文件底部的地方配置了它。
@ -849,22 +730,23 @@ external `.css` files that the `HtmlWebpackPlugin` inscribes as `<link>` tags in
这样`HtmlWebpackPlugin`插件就会转而把一个&lt;link&gt;标签写进`index.html`了。Refer to the [Webpack documentation](https://webpack.github.io/docs/) for details on these and
other configuration options in this file.要了解本文件中这些以及其它配置项的详情,请参阅[Webpack文档](https://webpack.github.io/docs/)。
Refer to the [Webpack documentation](https://webpack.github.io/docs/) for details on these and
other configuration options in this file.
要想了解本文件中的这些配置项和其它配置项的详情,请参阅 [Webpack 官方文档](https://webpack.github.io/docs/)。
Grab the app code at the end of this guide and try:
抓取本指南底部的应用代码,并试一试:
<code-example language="sh" class="code-shell">
npm start
</code-example>
{@a production-configuration}
### Production configuration
### 产品环境配置
@ -873,13 +755,10 @@ Configuration of a *production* build resembles *development* configuration wit
*产品环境*下的配置和*开发环境*下的配置很相似……除了一些关键的改动。
<code-example path="webpack/config/webpack.prod.js" title="config/webpack.prod.js" linenums="false">
</code-example>
You'll deploy the application and its dependencies to a real production server.
You won't deploy the artifacts needed only in development.
@ -904,9 +783,9 @@ There are additional plugins:
*`NoEmitOnErrorsPlugin`* - 如果出错就停止构建。*
*`UglifyJsPlugin`&mdash; minifies the bundles.
* *`UglifyJsPlugin`&mdash;minifies the bundles.
`UglifyJsPlugin` - 最小化(minify)生成的包。
*`UglifyJsPlugin`* - 最小化(minify)生成的包。
* *`ExtractTextPlugin`&mdash;extracts embedded css as external files, adding cache-busting hash to the filename.
@ -924,29 +803,22 @@ Thanks to the `DefinePlugin` and the `ENV` variable defined at top, you can enab
感谢*DefinePlugin*和顶部定义的`ENV`变量我们就可以像这样启用Angular的产品模式了
<code-example path="webpack/src/main.ts" region="enable-prod" title="src/main.ts" linenums="false">
</code-example>
Grab the app code at the end of this guide and try:
抓取本指南底部的应用代码,并试一试:
<code-example language="sh" class="code-shell">
npm run build
</code-example>
{@a test-configuration}
### Test configuration
### 测试环境配置
@ -966,24 +838,18 @@ But it might be simpler to start over with a completely fresh configuration.
我们可以把测试环境的配置合并到`webpack.common`配置中,并且改写不想要或不需要的部分。
但是从一个全新的配置开始可能更简单。
<code-example path="webpack/config/webpack.test.js" title="config/webpack.test.js" linenums="false">
</code-example>
Reconfigure [Karma](https://karma-runner.github.io/1.0/index.html) to use Webpack to run the tests:
重新配置[Karma](https://karma-runner.github.io/1.0/index.html)让它使用webpack来运行这些测试
<code-example path="webpack/config/karma.conf.js" title="config/karma.conf.js" linenums="false">
</code-example>
You don't precompile the TypeScript; Webpack transpiles the Typescript files on the fly, in memory, and feeds the emitted JS directly to Karma.
There are no temporary files on disk.
@ -995,13 +861,10 @@ primes the Angular test framework with test versions of the providers that every
`karma-test-shim`告诉Karma哪些文件需要预加载首要的是带有“测试版提供商”的Angular测试框架是每个应用都希望预加载的。
<code-example path="webpack/config/karma-test-shim.js" title="config/karma-test-shim.js" linenums="false">
</code-example>
Notice that you do _not_ load the application code explicitly.
You tell Webpack to find and load the test files (the files ending in `.spec.ts`).
Each spec file imports all&mdash;and only&mdash;the application source code that it tests.
@ -1012,13 +875,12 @@ Webpack loads just _those_ specific application files and ignores the other file
每个规约(spec)文件都导入了所有(也只有)它测试所需的应用源码。
Webpack只加载_那些_特定的应用文件而忽略所有其它我们不会测试到的。
Grab the app code at the end of this guide and try:
抓取本指南底部的应用代码,并试一试:
<code-example language="sh" class="code-shell">
npm test
</code-example>
@ -1034,7 +896,6 @@ Webpack techniques covered in this guide.
这里是一个小型应用的全部源码我们可以用本章中学到的Webpack技术打包它们。
<code-tabs>
<code-pane title="src/index.html" path="webpack/src/index.html">
@ -1051,8 +912,6 @@ Webpack techniques covered in this guide.
</code-tabs>
<code-tabs>
<code-pane title="src/app/app.component.ts" path="webpack/src/app/app.component.ts">
@ -1077,8 +936,6 @@ Webpack techniques covered in this guide.
</code-tabs>
The <code>app.component.html</code> displays this downloadable Angular logo
<a href="assets/images/logos/angular/angular.png">
<img src="assets/images/logos/angular/angular.png" height="40px" title="download Angular logo"></a>.
@ -1090,15 +947,12 @@ on the image and download it to that folder.
<img src="assets/images/logos/angular/angular.png" height="40px" title="download Angular logo"></a>
在项目的`assets`目录下创建一个名叫`images`的文件夹然后右键点击Mac上是Cmd+点击)本图片,并把它下载到`images`文件夹中。
{@a bundle-ts}
Here again are the TypeScript entry-point files that define the `polyfills` and `vendor` bundles.
这里又是TypeScript的入口点文件它定义了`polyfills``vendor`这两个包。
<code-tabs>
<code-pane title="src/polyfills.ts" path="webpack/src/polyfills.ts">
@ -1115,7 +969,7 @@ Here again are the TypeScript entry-point files that define the `polyfills` and
<h3 class="no-toc">Highlights</h3>
### 重点:
<h3 class="no-toc">重点</h3>
* There are no `<script>` or `<link>` tags in the `index.html`.
The `HtmlWebpackPlugin` inserts them dynamically at runtime.
@ -1159,4 +1013,5 @@ _但我们还能做得更多_。搜索互联网来获得专家的建议并扩
[Back to top](guide/webpack#top)
[回到顶部](guide/webpack#top)

View File

@ -1,5 +1,6 @@
<h1 class="no-toc">What is Angular?</h1>
<h1 class="no-toc">什么是 Angular</h1>
Angular is a platform that makes it easy to build applications with the web. Angular combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular empowers developers to build applications that live on the web, mobile, or the desktop
@ -8,23 +9,53 @@ Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angu
<div class="card-container">
<a href="generated/live-examples/toh-pt1/stackblitz.html" target="_blank" class="docs-card"
title="通过线上编程环境体验 Angular">
title="Experience Angular in a live coding environment">
<section>Get a Glimpse of Angular</section>
<section>Angular 走马观花</section>
<p>A quick look at an Angular "hello world" application.</p>
<p>快速体验 Angular 的 "hello world" 应用。</p>
<p class="card-footer">Angular in Action</p>
<p class="card-footer">体验 Angular</p>
</a>
<a href="guide/quickstart" class="docs-card" title="Angular 快速上手">
<a href="guide/quickstart" class="docs-card" title="Angular Quickstart">
<section>Get Going with Angular</section>
<section>开始使用 Angular</section>
<p>Get going on your own environment with the Quickstart.</p>
<p>跟随"快速上手"构建你的开发环境</p>
<p class="card-footer">Quickstart</p>
<p class="card-footer">快速上手</p>
</a>
<a href="guide/architecture" class="docs-card" title="Angular 架构">
<a href="guide/architecture" class="docs-card" title="Angular Architecture">
<section>Fundamentals</section>
<section>基本原理</section>
<p>Learn Angular application fundamentals, starting with an architecture overview.</p>
<p>学习 Angular 应用的基本原理。<br/>从架构概览开始。</p>
<p class="card-footer">Architecture</p>
<p class="card-footer">架构</p>
</a>
</div>
## Assumptions
@ -63,6 +94,7 @@ Our community values respectful, supportive communication.
Please consult and adhere to the
[code of conduct](https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md "contributor code of conduct").
你可以到 Angular 在 Github 上的仓库中提出文档方面的[问题](https://github.com/angular/angular/issues "Angular Github issues"),并创建[Pull Requests](https://github.com/angular/angular/pulls "Angular Github pull requests")。
[贡献者指南](https://github.com/angular/angular/blob/master/CONTRIBUTING.md "贡献者指南")将会帮助你更好的为社区做贡献。
我们社区的价值观是互相尊重、互相支持。参见[社区行为规范](https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md "contributor code of conduct")。

View File

@ -1,13 +1,19 @@
# Contributing to resources.json
## About this list
We maintain a small list of some of the top Angular resources from across the community, stored in `resources.json`. This list is not intended to be comprehensive, but to act as a starting point to connect Angular developers to the rest of the community.
## How do I get listed?
While we can't accept all contributions, qualifying contributions can be submitted via a PR adding yourself to the `resources.json` file. All contributions should be in the appropriate section and must meet the following criteria:
1. Your contribution must be valid, and contain a link to a page talking specifically about using Angular
1. Your contribution should have a clear and concise title and description
1. Your resource should follow our brand guidelines (see our [Presskit](https://angular.io/presskit))
1. Your resource should have significant benefit to Angular developers
1. Your resource should already have traction and praise from Angular developers

View File

@ -1,3 +1,5 @@
<h1 class="no-toc">Tutorial: Tour of Heroes</h1>
<h1 class="no-toc">教程:英雄指南</h1>
@ -71,9 +73,10 @@ view and the most heroic heroes:
下面是本教程关于界面的构想开始是“Dashboard仪表盘”视图来展示我们最勇敢的英雄。
<figure>
<img src='generated/images/guide/toh/heroes-dashboard-1.png' alt="英雄仪表盘的输出">
<img src='generated/images/guide/toh/heroes-dashboard-1.png' alt="Output of heroes dashboard">
</figure>
You can click the two links above the dashboard ("Dashboard" and "Heroes")
@ -87,9 +90,10 @@ where you can change the hero's name.
当我们点击仪表盘上名叫“Magneta”的英雄时路由将把我们带到这个英雄的详情页在这里我们可以修改英雄的名字。
<figure>
<img src='generated/images/guide/toh/hero-details-1.png' alt="英雄详情的输出">
<img src='generated/images/guide/toh/hero-details-1.png' alt="Details of hero in app">
</figure>
Clicking the "Back" button returns you to the Dashboard.
@ -100,9 +104,10 @@ If you click "Heroes," the app displays the "Heroes" master list view.
顶部的链接可以把我们带到任何一个主视图。
如果我们点击“Heroes英雄列表”链接应用将把我们带到“英雄”主列表视图。
<figure>
<img src='generated/images/guide/toh/heroes-list-2.png' alt="英雄列表的输出">
<img src='generated/images/guide/toh/heroes-list-2.png' alt="Output of heroes list app">
</figure>
When you click a different hero name, the read-only mini detail beneath the list reflects the new choice.
@ -118,16 +123,19 @@ The following diagram captures all of the navigation options.
下面这张图汇总了我们所有可能的导航路径。
<figure>
<img src='generated/images/guide/toh/nav-diagram.png' alt="查看导航">
<img src='generated/images/guide/toh/nav-diagram.png' alt="View navigations">
</figure>
Here's the app in action:
下图演示了我们应用中的所有操作。
<figure>
<img src='generated/images/guide/toh/toh-anim.gif' alt="英雄指南的所有动作">
<img src='generated/images/guide/toh/toh-anim.gif' alt="Tour of Heroes in Action">
</figure>

View File

@ -5,7 +5,9 @@
Install the [Angular CLI](https://github.com/angular/angular-cli), if you haven't already done so.
<code-example language="sh" class="code-shell">
npm install -g @angular/cli
</code-example>
## Create a new application
@ -13,7 +15,9 @@
Create a new project named `angular-tour-of-heroes` with this CLI command.
<code-example language="sh" class="code-shell">
ng new angular-tour-of-heroes
</code-example>
The Angular CLI generated a new project with a default application and supporting files.
@ -23,8 +27,10 @@ The Angular CLI generated a new project with a default application and supportin
Go to the project directory and launch the application.
<code-example language="sh" class="code-shell">
cd angular-tour-of-heroes
ng serve --open
</code-example>
<div class="l-sub-section">
@ -53,13 +59,15 @@ Open the project in your favorite editor or IDE and navigate to the `src/app` fo
You'll find the implementation of the shell `AppComponent` distributed over three files:
1. `app.component.ts`&mdash; the component class code, written in TypeScript.
1. `app.component.html`&mdash; the component template, written in HTML.
1. `app.component.css`&mdash; the component's private CSS styles.
1. `app.component.html`&mdash; the component template, written in HTML.
1. `app.component.css`&mdash; the component's private CSS styles.
Open the component class file (`app.component.ts`) and change the value of the `title` property to '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>
Open the component template file (`app.component.html`) and
@ -68,6 +76,7 @@ Replace it with the following line of HTML.
<code-example path="toh-pt0/src/app/app.component.html"
title="app.component.html (template)" linenums="false">
</code-example>
The double curly braces are Angular's *interpolation binding* syntax.
@ -87,6 +96,7 @@ Put your application-wide styles there.
Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app.
<code-example path="toh-pt0/src/styles.1.css" title="src/styles.css (excerpt)">
</code-example>
## Final code review
@ -99,19 +109,27 @@ Here are the code files discussed on this page.
<code-tabs>
<code-pane title="src/app/app.component.ts" path="toh-pt0/src/app/app.component.ts">
</code-pane>
<code-pane title="src/app/app.component.html" path="toh-pt0/src/app/app.component.html">
</code-pane>
<code-pane
title="src/styles.css (excerpt)"
path="toh-pt0/src/styles.1.css">
</code-pane>
</code-tabs>
## Summary
## 小结
* You created the initial application structure using the Angular CLI.
* You learned that Angular components display data.
* You used the double curly braces of interpolation to display the app title.

View File

@ -16,7 +16,9 @@ and place that component in the application shell.
Using the Angular CLI, generate a new component named `heroes`.
<code-example language="sh" class="code-shell">
ng generate component heroes
</code-example>
The CLI creates a new folder, `src/app/heroes/` and generates
@ -27,6 +29,7 @@ The `HeroesComponent` class file is as follows:
<code-example
path="toh-pt1/src/app/heroes/heroes.component.ts" region="v1"
title="app/heroes/heroes.component.ts (initial version)" linenums="false">
</code-example>
You always import the `Component` symbol from the Angular core library
@ -37,7 +40,9 @@ and annotate the component class with `@Component`.
The CLI generated three metadata properties:
1. `selector`&mdash; the component's CSS element selector
1. `templateUrl`&mdash; the location of the component's template file.
1. `styleUrls`&mdash; the location of the component's private CSS styles.
{@a selector}
@ -56,6 +61,7 @@ Always `export` the component class so you can `import` it elsewhere ... like in
Add a `hero` property to the `HeroesComponent` for a hero named "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>
### Show the hero
@ -65,6 +71,7 @@ Delete the default text generated by the Angular CLI and
replace it with a data binding to the new `hero` property.
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" title="heroes.component.html" region="show-hero-1" linenums="false">
</code-example>
## Show the _HeroesComponent_ view
@ -75,6 +82,7 @@ Remember that `app-heroes` is the [element selector](#selector) for the `HeroesC
So add an `<app-heroes>` element to the `AppComponent` template file, just below the title.
<code-example path="toh-pt1/src/app/app.component.html" title="src/app/app.component.html" linenums="false">
</code-example>
Assuming that the CLI `ng serve` command is still running,
@ -88,8 +96,8 @@ Create a `Hero` class in its own file in the `src/app` folder.
Give it `id` and `name` properties.
<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.
@ -105,6 +113,7 @@ The revised `HeroesComponent` class file should look like this:
<code-example path="toh-pt1/src/app/heroes/heroes.component.ts" linenums="false"
title= "src/app/heroes/heroes.component.ts">
</code-example>
The page no longer displays properly because you changed the hero from a string to an object.
@ -118,6 +127,7 @@ and show both `id` and `name` in a details layout like this:
path="toh-pt1/src/app/heroes/heroes.component.1.html"
region="show-hero-2"
title="heroes.component.html (HeroesComponent's template)" linenums="false">
</code-example>
The browser refreshes and display's the hero's information.
@ -130,6 +140,7 @@ Modify the `hero.name` binding like this.
<code-example
path="toh-pt1/src/app/heroes/heroes.component.html"
region="pipe">
</code-example>
The browser refreshes and now the hero's name is displayed in capital letters.
@ -169,7 +180,6 @@ Refactor the details area in the `HeroesComponent` template so it looks like thi
把模板中的英雄名字重构成这样:
<code-example path="toh-pt1/src/app/heroes/heroes.component.1.html" region="name-input" title="src/app/heroes/heroes.component.html (HeroesComponent's template)" linenums="false">
</code-example>
@ -196,8 +206,10 @@ for a message like
打开浏览器的开发工具,就会在控制台中看到如下信息:
<code-example language="sh" class="code-shell">
Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'input'.
</code-example>
Although `ngModel` is a valid Angular directive, it isn't available by default.
@ -224,12 +236,14 @@ 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)"
region="formsmodule-js-import">
</code-example>
Then add `FormsModule` to the `@NgModule` metadata's `imports` array, which contains a list of external modules that the app needs.
<code-example path="toh-pt1/src/app/app.module.ts" title="app.module.ts ( @NgModule imports)"
region="ng-imports">
</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.
@ -244,16 +258,19 @@ So why did the application work?
It worked because the Angular CLI declared `HeroesComponent` in the `AppModule` when it generated that component.
Open `src/app/app.module.ts` and find `HeroesComponent` imported near the top.
<code-example path="toh-pt1/src/app/app.module.ts" region="heroes-import" >
</code-example>
The `HeroesComponent` is declared in the `@NgModule.declarations` array.
<code-example path="toh-pt1/src/app/app.module.ts" region="declarations">
</code-example>
Note that `AppModule` declares both application components, `AppComponent` and `HeroesComponent`.
## Final code review
Your app should look like this <live-example></live-example>. Here are the code files discussed on this page.
@ -261,34 +278,48 @@ Your app should look like this <live-example></live-example>. Here are the code
<code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="toh-pt1/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane title="src/app/heroes/heroes.component.html" path="toh-pt1/src/app/heroes/heroes.component.html">
</code-pane>
<code-pane title="src/app/app.module.ts"
path="toh-pt1/src/app/app.module.ts">
</code-pane>
<code-pane title="src/app/app.component.ts" path="toh-pt1/src/app/app.component.ts">
</code-pane>
<code-pane title="src/app/app.component.html" path="toh-pt1/src/app/app.component.html">
</code-pane>
<code-pane title="src/app/hero.ts"
path="toh-pt1/src/app/hero.ts">
</code-pane>
</code-tabs>
## Summary
## 小结
* You used the CLI to create a second `HeroesComponent`.
* You displayed the `HeroesComponent` by adding it to the `AppComponent` shell.
* You applied the `UppercasePipe` to format the name.
* You used two-way data binding with the `ngModel` directive.
* You learned about the `AppModule`.
* You imported the `FormsModule` in the `AppModule` so that Angular would recognize and apply the `ngModel` directive.
* You learned the importance of declaring components in the `AppModule`
and appreciated that the CLI declared it for you.

View File

@ -3,7 +3,6 @@
In this page, you'll expand the Tour of Heroes app to display a list of heroes, and
allow users to select a hero and display the hero's details.
## Create mock heroes
You'll need some heroes to display.
@ -17,6 +16,7 @@ The file should look like this.
<code-example path="toh-pt2/src/app/mock-heroes.ts" linenums="false"
title="src/app/mock-heroes.ts">
</code-example>
## Displaying heroes
@ -26,11 +26,13 @@ You're about to display the list of heroes at the top of the `HeroesComponent`.
Open the `HeroesComponent` class file and import the mock `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>
Add a `heroes` property to the class that exposes these heroes for binding.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="heroes">
</code-example>
### List heroes with _*ngFor_
@ -38,18 +40,23 @@ Add a `heroes` property to the class that exposes these heroes for binding.
Open the `HeroesComponent` template file and make the following changes:
* Add an `<h2>` at the top,
* Below it add an HTML unordered list (`<ul>`)
* Insert an `<li>` within the `<ul>` that displays properties of a `hero`.
* Sprinkle some CSS classes for styling (you'll add the CSS styles shortly).
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>
Now change the `<li>` to this:
<code-example path="toh-pt2/src/app/heroes/heroes.component.1.html" region="li">
</code-example>
The [`*ngFor`](guide/template-syntax#ngFor) is Angular's _repeater_ directive.
@ -58,7 +65,9 @@ It repeats the host element for each element in a list.
In this example
* `<li>` is the host element
* `heroes` is the list from the `HeroesComponent` class.
* `hero` holds the current hero object for each iteration through the list.
<div class="alert is-important">
@ -95,6 +104,7 @@ and pointed to it in `@Component.styleUrls` like this.
<code-example path="toh-pt2/src/app/heroes/heroes.component.ts" region="metadata"
title="src/app/heroes/heroes.component.ts (@Component)">
</code-example>
Open the `heroes.component.css` file and paste in the private CSS styles for the `HeroesComponent`.
@ -120,6 +130,7 @@ and update the hero detail.
Add a click event binding to the `<li>` like this:
<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>
This is an example of Angular's [event binding](guide/template-syntax#event-binding) syntax.
@ -140,6 +151,7 @@ Add the following `onSelect()` method, which assigns the clicked hero from the t
to the component's `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>
### Update the details template
@ -148,6 +160,7 @@ The template still refers to the component's old `hero` property which no longer
Rename `hero` to `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>
### Hide empty details with _*ngIf_
@ -157,7 +170,9 @@ After the browser refreshes, the application is broken.
Open the browser developer tools and look in the console for an error message like this:
<code-example language="sh" class="code-shell">
HeroesComponent.html:3 ERROR TypeError: Cannot read property 'name' of undefined
</code-example>
Now click one of the list items.
@ -184,6 +199,7 @@ Don't forget the asterisk (*) in front of `ngIf`. It's a critical part of the sy
</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>
After the browser refreshes, the list of names reappears.
@ -218,6 +234,7 @@ Just add `[class.some-css-class]="some-condition"` to the element you want to st
Add the following `[class.selected]` binding to the `<li>` in the `HeroesComponent` template:
<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>
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.
@ -237,20 +254,31 @@ Your app should look like this <live-example></live-example>.
Here are the code files discussed on this page, including the `HeroesComponent` styles.
<code-tabs>
<code-pane title="src/app/heroes/heroes.component.ts" path="toh-pt2/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane title="src/app/heroes/heroes.component.html" path="toh-pt2/src/app/heroes/heroes.component.html">
</code-pane>
<code-pane title="src/app/heroes/heroes.component.css" path="toh-pt2/src/app/heroes/heroes.component.css">
</code-pane>
</code-tabs>
## Summary
## 小结
* The Tour of Heroes app displays a list of heroes in a Master/Detail view.
* The user can select a hero and see that hero's details.
* You used `*ngFor` to display a list.
* You used `*ngIf` to conditionally include or exclude a block of HTML.
* You can toggle a CSS style class with a `class` binding.

View File

@ -15,7 +15,9 @@ The `HeroDetailsComponent` will present details of a selected hero.
Use the Angular CLI to generate a new component named `hero-detail`.
<code-example language="sh" class="code-shell">
ng generate component hero-detail
</code-example>
The command scaffolds the `HeroDetailComponent` files and declares the component in `AppModule`.
@ -43,6 +45,7 @@ Open the `HeroDetailComponent` class file and import the `Hero` symbol.
<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)">
</code-example>
The `hero` property
@ -51,16 +54,19 @@ annotated with the `@Input()` decorator,
because the _external_ `HeroesComponent` [will bind to it](#heroes-component-template) like this.
<code-example path="toh-pt3/src/app/heroes/heroes.component.html" region="hero-detail-binding">
</code-example>
Amend the `@angular/core` import statement to include the `Input` symbol.
<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>
Add a `hero` property, preceded by the `@Input()` decorator.
<code-example path="toh-pt3/src/app/hero-detail/hero-detail.component.ts" region="input-hero" linenums="false">
</code-example>
That's the only change you should make to the `HeroDetailComponent` class.
@ -106,6 +112,7 @@ The revised `HeroesComponent` template should look like this:
<code-example path="toh-pt3/src/app/heroes/heroes.component.html"
title="heroes.component.html" linenums="false">
</code-example>
The browser refreshes and the app starts working again as it did before.
@ -134,24 +141,27 @@ Here are the code files discussed on this page and your app should look like thi
<code-tabs>
<code-pane title="src/app/hero-detail/hero-detail.component.ts" path="toh-pt3/src/app/hero-detail/hero-detail.component.ts">
</code-pane>
<code-pane title="src/app/hero-detail/hero-detail.component.html" path="toh-pt3/src/app/hero-detail/hero-detail.component.html">
</code-pane>
<code-pane title="src/app/heroes/heroes.component.html" path="toh-pt3/src/app/heroes/heroes.component.html">
</code-pane>
</code-tabs>
## Summary
## 小结
* You created a separate, reusable `HeroDetailComponent`.
* You used a [property binding](guide/template-syntax#property-binding) to give the parent `HeroesComponent` control over the child `HeroDetailComponent`.
* You used the [`@Input` decorator](guide/template-syntax#inputs-outputs)
to make the `hero` property available for binding
by the external `HeroesComponent`.

View File

@ -19,15 +19,17 @@ Services are a great way to share information among classes that _don't know eac
You'll create a `MessageService` and inject it in two places:
1. in `HeroService` which uses the service to send a message.
2. in `MessagesComponent` which displays that message.
2. in `MessagesComponent` which displays that message.
## Create the _HeroService_
Using the Angular CLI, create a service called `hero`.
<code-example language="sh" class="code-shell">
ng generate service hero
</code-example>
The command generates skeleton `HeroService` class in `src/app/hero.service.ts`
@ -35,6 +37,7 @@ The `HeroService` class should look like the below.
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="new"
title="src/app/hero.service.ts (new service)" linenums="false">
</code-example>
### _@Injectable()_ services
@ -66,14 +69,17 @@ The implementation in _this_ tutorial will continue to deliver _mock heroes_.
Import the `Hero` and `HEROES`.
<code-example path="toh-pt4/src/app/hero.service.ts" region="import-heroes">
</code-example>
Add a `getHeroes` method to return the _mock heroes_.
<code-example path="toh-pt4/src/app/hero.service.1.ts" region="getHeroes">
</code-example>
{@a provide}
## Provide the `HeroService`
You must _provide_ the `HeroService` in the _dependency injection system_
@ -90,7 +96,9 @@ That's such a popular choice that you could have told the CLI to provide it ther
by appending `--module=app`.
<code-example language="sh" class="code-shell">
ng generate service hero --module=app
</code-example>
Since you did not, you'll have to provide it yourself.
@ -98,6 +106,7 @@ Since you did not, you'll have to provide it yourself.
Open the `AppModule` class, import the `HeroService`, and add it to the `@NgModule.providers` array.
<code-example path="toh-pt4/src/app/app.module.ts" linenums="false" title="src/app/app.module.ts (providers)" region="providers-heroservice">
</code-example>
The `providers` array tells Angular to create a single, shared instance of `HeroService`
@ -125,11 +134,13 @@ Delete the `HEROES` import as you won't need that anymore.
Import the `HeroService` instead.
<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>
Replace the definition of the `heroes` property with a simple declaration.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="heroes">
</code-example>
{@a inject}
@ -139,6 +150,7 @@ Replace the definition of the `heroes` property with a simple declaration.
Add a private `heroService` parameter of type `HeroService` to the constructor.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ctor">
</code-example>
The parameter simultaneously defines a private `heroService` property and identifies it as a `HeroService` injection site.
@ -151,6 +163,7 @@ sets the `heroService` parameter to the singleton instance of `HeroService`.
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>
{@a oninit}
@ -167,6 +180,7 @@ Instead, call `getHeroes()` inside the [*ngOnInit lifecycle hook*](guide/lifecyc
let Angular call `ngOnInit` at an appropriate time _after_ constructing a `HeroesComponent` instance.
<code-example path="toh-pt4/src/app/heroes/heroes.component.ts" region="ng-on-init">
</code-example>
### See it run
@ -182,6 +196,7 @@ The `HeroesComponent` consumes the `getHeroes()` result
as if heroes could be fetched synchronously.
<code-example path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="get-heroes">
</code-example>
This will not work in a real app.
@ -212,6 +227,7 @@ Open the `HeroService` file and import the `Observable` and `of` symbols from Rx
<code-example path="toh-pt4/src/app/hero.service.ts"
title="src/app/hero.service.ts (Observable imports)" region="import-observable">
</code-example>
Replace the `getHeroes` method with this one.
@ -240,10 +256,12 @@ Find the `getHeroes` method and replace it with the following code
<code-pane title="heroes.component.ts (Observable)"
path="toh-pt4/src/app/heroes/heroes.component.ts" region="getHeroes">
</code-pane>
<code-pane title="heroes.component.ts (Original)"
path="toh-pt4/src/app/heroes/heroes.component.1.ts" region="getHeroes">
</code-pane>
</code-tabs>
@ -269,8 +287,11 @@ the `HeroService` requests heroes from the server.
In this section you will
* add a `MessagesComponent` that displays app messages at the bottom of the screen.
* create an injectable, app-wide `MessageService` for sending messages to be displayed
* inject `MessageService` into the `HeroService`
* display a message when `HeroService` fetches heroes successfully.
### Create _MessagesComponent_
@ -278,7 +299,9 @@ In this section you will
Use the CLI to create the `MessagesComponent`.
<code-example language="sh" class="code-shell">
ng generate component messages
</code-example>
The CLI creates the component files in the `src/app/messages` folder and declare `MessagesComponent` in `AppModule`.
@ -288,6 +311,7 @@ Modify the `AppComponent` template to display the generated `MessagesComponent`
<code-example
title = "/src/app/app.component.html"
path="toh-pt4/src/app/app.component.html">
</code-example>
You should see the default paragraph from `MessagesComponent` at the bottom of the page.
@ -298,7 +322,9 @@ Use the CLI to create the `MessageService` in `src/app`.
The `--module=app` option tells the CLI to [_provide_ this service](#provide) in the `AppModule`,
<code-example language="sh" class="code-shell">
ng generate service message --module=app
</code-example>
Open `MessageService` and replace its contents with the following.
@ -306,11 +332,13 @@ Open `MessageService` and replace its contents with the following.
<code-example
title = "/src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts">
</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.
{@a inject-message-service}
### Inject it into the `HeroService`
Re-open the `HeroService` and import the `MessageService`.
@ -318,6 +346,7 @@ Re-open the `HeroService` and import the `MessageService`.
<code-example
title = "/src/app/hero.service.ts (import MessageService)"
path="toh-pt4/src/app/hero.service.ts" region="import-message-service">
</code-example>
Modify the constructor with a parameter that declares a private `messageService` property.
@ -326,6 +355,7 @@ when it creates the `HeroService`.
<code-example
path="toh-pt4/src/app/hero.service.ts" region="ctor">
</code-example>
<div class="l-sub-section">
@ -340,6 +370,7 @@ you inject the `MessageService` into the `HeroService` which is injected into th
Modify the `getHeroes` method to send a message when the heroes are fetched.
<code-example path="toh-pt4/src/app/hero.service.ts" region="getHeroes">
</code-example>
### Display the message from `HeroService`
@ -352,6 +383,7 @@ Open `MessagesComponent` and import the `MessageService`.
<code-example
title = "/src/app/messages/messages.component.ts (import MessageService)"
path="toh-pt4/src/app/messages/messages.component.ts" region="import-message-service">
</code-example>
Modify the constructor with a parameter that declares a **public** `messageService` property.
@ -360,6 +392,7 @@ when it creates the `HeroService`.
<code-example
path="toh-pt4/src/app/messages/messages.component.ts" region="ctor">
</code-example>
The `messageService` property **must be public** because you're about to bind to it in the template.
@ -377,16 +410,15 @@ Replace the CLI-generated `MessagesComponent` template with the following.
<code-example
title = "src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html">
</code-example>
This template binds directly to the component's `messageService`.
* The `*ngIf` only displays the messages area if there are messages to show.
* An `*ngFor` presents the list of messages in repeated `<div>` elements.
* An Angular [event binding](guide/template-syntax#event-binding) binds the button's click event
to `MessageService.clear()`.
@ -407,47 +439,65 @@ Here are the code files discussed on this page and your app should look like thi
<code-pane title="src/app/hero.service.ts"
path="toh-pt4/src/app/hero.service.ts">
</code-pane>
<code-pane title="src/app/message.service.ts"
path="toh-pt4/src/app/message.service.ts">
</code-pane>
<code-pane title="src/app/heroes/heroes.component.ts"
path="toh-pt4/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane title="src/app/messages/messages.component.ts"
path="toh-pt4/src/app/messages/messages.component.ts">
</code-pane>
<code-pane title="src/app/messages/messages.component.html"
path="toh-pt4/src/app/messages/messages.component.html">
</code-pane>
<code-pane title="src/app/messages/messages.component.css"
path="toh-pt4/src/app/messages/messages.component.css">
</code-pane>
<code-pane title="src/app/app.module.ts"
path="toh-pt4/src/app/app.module.ts">
</code-pane>
<code-pane title="src/app/app.component.html"
path="toh-pt4/src/app/app.component.html">
</code-pane>
</code-tabs>
## Summary
## 小结
* You refactored data access to the `HeroService` class.
* You _provided_ the `HeroService` in the root `AppModule` so that it can be injected anywhere.
* You used [Angular Dependency Injection](guide/dependency-injection) to inject it into a component.
* You gave the `HeroService` _get data_ method an asynchronous signature.
* You discovered `Observable` and the RxJS _Observable_ library.
* You used RxJS `of()` to return an _Observable_ of mock heroes (`Observable<Hero[]>`).
* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor.
* You created a `MessageService` for loosely-coupled communication between classes.
* The `HeroService` injected into a component is created with another injected service,
`MessageService`.

View File

@ -3,8 +3,11 @@
There are new requirements for the Tour of Heroes app:
* Add a *Dashboard* view.
* Add the ability to navigate between the *Heroes* and *Dashboard* views.
* When users click a hero name in either view, navigate to a detail view of the selected hero.
* When users click a *deep link* in an email, open the detail view for a particular hero.
When youre done, users will be able to navigate the app like this:
@ -25,19 +28,26 @@ By convention, the module class name is `AppRoutingModule` and it belongs in the
Use the CLI to generate it.
<code-example language="sh" class="code-shell">
ng generate module app-routing --flat --module=app
</code-example>
<div class="l-sub-section">
`--flat` puts the file in `src/app` instead of its own folder.<br>
`--flat` puts the file in `src/app` instead of its own folder.
<br>
`--module=app` tells the CLI to register it in the `imports` array of the `AppModule`.
</div>
The generated file looks like this:
<code-example path="toh-pt5/src/app/app-routing.module.0.ts"
title="src/app/app-routing.module.ts (generated)">
</code-example>
You generally don't declare components in a routing module so you can delete the
@ -55,6 +65,7 @@ in the `AppModule` components that will need them.
<code-example path="toh-pt5/src/app/app-routing.module.ts"
region="v1"
title="src/app/app-routing.module.ts (v1)">
</code-example>
### Add routes
@ -65,6 +76,7 @@ pastes a URL into the browser address bar.
A typical Angular `Route` has two properties:
1. `path`: a string that matches the URL in the browser address bar.
1. `component`: the component that the router should create when navigating to this route.
You intend to navigate to the `HeroesComponent` when the URL is something like `localhost:4200/heroes`.
@ -74,6 +86,7 @@ Then define an array of routes with a single `route` to that component.
<code-example path="toh-pt5/src/app/app-routing.module.ts"
region="heroes-route">
</code-example>
Once you've finished setting up, the router will match that URL to `path: 'heroes'`
@ -89,6 +102,7 @@ configure it with the `routes` in one step by calling
<code-example path="toh-pt5/src/app/app-routing.module.ts"
region="ngmodule-imports">
</code-example>
<div class="l-sub-section">
@ -106,6 +120,7 @@ Open the `AppComponent` template replace the `<app-heroes>` element with a `<rou
<code-example path="toh-pt5/src/app/app.component.html"
region="outlet"
title="src/app/app.component.html (router-outlet)">
</code-example>
You removed `<app-heroes>` because you will only display the `HeroesComponent` when the user navigates to it.
@ -124,7 +139,9 @@ because `AppModule` imports `AppRoutingModule` which exported `RouterModule`.
You should still be running with this CLI command.
<code-example language="sh" class="code-shell">
ng serve
</code-example>
The browser should refresh and display the app title but not the list of heroes.
@ -151,6 +168,7 @@ The revised `AppComponent` template looks like this:
path="toh-pt5/src/app/app.component.html"
region="heroes"
title="src/app/app.component.html (heroes RouterLink)">
</code-example>
A [`routerLink` attribute](#routerlink) is set to `"/heroes"`,
@ -172,7 +190,6 @@ as listed in the [final code review](#appcomponent) below.
</div>
## Add a dashboard view
Routing makes more sense when there are multiple views.
@ -181,7 +198,9 @@ So far there's only the heroes view.
Add a `DashboardComponent` using the CLI:
<code-example language="sh" class="code-shell">
ng generate component dashboard
</code-example>
The CLI generates the files for the `DashboardComponent` and declares it in `AppModule`.
@ -189,34 +208,45 @@ The CLI generates the files for the `DashboardComponent` and declares it in `App
Replace the default file content in these three files as follows and then return for a little discussion:
<code-tabs>
<code-pane
title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.1.html">
</code-pane>
<code-pane
title="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts">
</code-pane>
<code-pane
title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
</code-pane>
</code-tabs>
The _template_ presents a grid of hero name links.
* The `*ngFor` repeater creates as many links as are in the component's `heroes` array.
* The links are styled as colored blocks by the `dashboard.component.css`.
* The links don't go anywhere yet but [they will shortly](#hero-details).
The _class_ is similar to the `HeroesComponent` class.
* It defines a `heroes` array property.
* The constructor expects Angular to inject the `HeroService` into a private `heroService` property.
* The `ngOnInit()` lifecycle hook calls `getHeroes`.
This `getHeroes` reduces the number of heroes displayed to four
(2nd, 3rd, 4th, and 5th).
<code-example path="toh-pt5/src/app/dashboard/dashboard.component.ts" region="getHeroes">
</code-example>
### Add the dashboard route
@ -229,6 +259,7 @@ Import the `DashboardComponent` in the `AppRoutingModule`.
path="toh-pt5/src/app/app-routing.module.ts"
region="import-dashboard"
title="src/app/app-routing.module.ts (import DashboardComponent)">
</code-example>
Add a route to the `AppRoutingModule.routes` array that matches a path to the `DashboardComponent`.
@ -236,6 +267,7 @@ Add a route to the `AppRoutingModule.routes` array that matches a path to the `D
<code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="dashboard-route">
</code-example>
### Add a default route
@ -248,6 +280,7 @@ To make the app navigate to the dashboard automatically, add the following
route to the `AppRoutingModule.Routes` array.
<code-example path="toh-pt5/src/app/app-routing.module.ts" region="redirect-route">
</code-example>
This route redirects a URL that fully matches the empty path to the route whose path is `'/dashboard'`.
@ -264,11 +297,13 @@ navigation area near the top of the page.
Add a dashboard navigation link to the `AppComponent` shell template, just above the *Heroes* link.
<code-example path="toh-pt5/src/app/app.component.html" title="src/app/app.component.html">
</code-example>
After the browser refreshes you can navigate freely between the two views by clicking the links.
{@a hero-details}
## Navigating to hero details
The `HeroDetailsComponent` displays details of a selected hero.
@ -277,7 +312,9 @@ At the moment the `HeroDetailsComponent` is only visible at the bottom of the `H
The user should be able to get to these details in three ways.
1. By clicking a hero in the dashboard.
1. By clicking a hero in the heroes list.
1. By pasting a "deep link" URL into the browser address bar that identifies the hero to display.
In this section, you'll enable navigation to the `HeroDetailsComponent`
@ -306,6 +343,7 @@ Open `AppRoutingModule` and import `HeroDetailComponent`.
path="toh-pt5/src/app/app-routing.module.ts"
region="import-herodetail"
title="src/app/app-routing.module.ts (import HeroDetailComponent)">
</code-example>
Then add a _parameterized_ route to the `AppRoutingModule.routes` array that matches the path pattern to the _hero detail_ view.
@ -313,6 +351,7 @@ Then add a _parameterized_ route to the `AppRoutingModule.routes` array that mat
<code-example
path="toh-pt5/src/app/app-routing.module.ts"
region="detail-route">
</code-example>
The colon (:) in the `path` indicates that `:id` is a placeholder for a specific hero `id`.
@ -323,6 +362,7 @@ At this point, all application routes are in place.
path="toh-pt5/src/app/app-routing.module.ts"
region="routes"
title="src/app/app-routing.module.ts (all routes)">
</code-example>
### _DashboardComponent_ hero links
@ -336,6 +376,7 @@ fix the dashboard hero links to navigate via the _parameterized_ dashboard route
path="toh-pt5/src/app/dashboard/dashboard.component.html"
region="click"
title="src/app/dashboard/dashboard.component.html (hero links)">
</code-example>
You're using Angular [interpolation binding](guide/template-syntax#interpolation) within the `*ngFor` repeater
@ -343,6 +384,7 @@ to insert the current interation's `hero.id` into each
[`routerLink`](#routerlink).
{@a heroes-component-links}
### _HeroesComponent_ hero links
The hero items in the `HeroesComponent` are `<li>` elements whose click events
@ -352,6 +394,7 @@ are bound to the component's `onSelect()` method.
path="toh-pt4/src/app/heroes/heroes.component.html"
region="list"
title="src/app/heroes/heroes.component.html (list with onSelect)">
</code-example>
Strip the `<li>` back to just its `*ngFor`,
@ -363,6 +406,7 @@ is the same as in the dashboard template
path="toh-pt5/src/app/heroes/heroes.component.html"
region="list"
title="src/app/heroes/heroes.component.html (list with links)">
</code-example>
You'll have to fix the private stylesheet (`heroes.component.css`) to make
@ -381,6 +425,7 @@ Here's the class after pruning away the dead code.
path="toh-pt5/src/app/heroes/heroes.component.ts"
region="class"
title="src/app/heroes/heroes.component.ts (cleaned up)" linenums="false">
</code-example>
## Routable *HeroDetailComponent*
@ -394,7 +439,9 @@ Now the router creates the `HeroDetailComponent` in response to a URL such as `~
The `HeroDetailComponent` needs a new way to obtain the _hero-to-display_.
* Get the route that created it,
* Extract the `id` from the route
* Acquire the hero with that `id` from the server via the `HeroService`
Add the following imports:
@ -403,6 +450,7 @@ Add the following imports:
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts"
region="added-imports"
title="src/app/hero-detail/hero-detail.component.ts">
</code-example>
{@a hero-detail-ctor}
@ -412,6 +460,7 @@ into the constructor, saving their values in private fields:
<code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ctor">
</code-example>
The [`ActivatedRoute`](api/router/ActivatedRoute) holds information about the route to this instance of the `HeroDetailComponent`.
@ -431,6 +480,7 @@ call `getHero()` and define it as follows.
<code-example
path="toh-pt5/src/app/hero-detail/hero-detail.component.ts" region="ngOnInit">
</code-example>
The `route.snapshot` is a static image of the route information shortly after the component was created.
@ -454,6 +504,7 @@ Open `HeroService` and add this `getHero()` method
path="toh-pt5/src/app/hero.service.ts"
region="getHero"
title="src/app/hero.service.ts (getHero)">
</code-example>
<div class="alert is-important">
@ -461,6 +512,7 @@ Open `HeroService` and add this `getHero()` method
Note the backticks ( &#96; ) that
define a JavaScript
[_template literal_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) for embedding the `id`.
</div>
Like [`getHeroes()`](tutorial/toh-pt4#observable-heroservice),
@ -495,6 +547,7 @@ to the component's `goBack()` method.
path="toh-pt5/src/app/hero-detail/hero-detail.component.html"
region="back-button"
title="src/app/hero-detail/hero-detail.component.html (back button)">
</code-example>
Add a `goBack()` _method_ to the component class that navigates backward one step
@ -505,7 +558,6 @@ using the `Location` service that you [injected previously](#hero-detail-ctor).
</code-example>
Refresh the browser and start clicking.
Users can navigate around the app, from the dashboard to hero details and back,
from heroes list to the mini detail to the hero details and back to the heroes again.
@ -518,93 +570,132 @@ Here are the code files discussed on this page and your app should look like thi
{@a approutingmodule}
{@a appmodule}
#### _AppRoutingModule_ and _AppModule_
<code-tabs>
<code-pane
title="src/app/app-routing.module.ts"
path="toh-pt5/src/app/app-routing.module.ts">
</code-pane>
<code-pane
title="src/app/app.module.ts"
path="toh-pt5/src/app/app.module.ts">
</code-pane>
</code-tabs>
{@a appcomponent}
#### _AppComponent_
<code-tabs>
<code-pane
title="src/app/app.component.html"
path="toh-pt5/src/app/app.component.html">
</code-pane>
<code-pane
title="src/app/app.component.css"
path="toh-pt5/src/app/app.component.css">
</code-pane>
</code-tabs>
{@a dashboardcomponent}
#### _DashboardComponent_
<code-tabs>
<code-pane
title="src/app/dashboard/dashboard.component.html" path="toh-pt5/src/app/dashboard/dashboard.component.html">
</code-pane>
<code-pane
title="src/app/dashboard/dashboard.component.ts" path="toh-pt5/src/app/dashboard/dashboard.component.ts">
</code-pane>
<code-pane
title="src/app/dashboard/dashboard.component.css" path="toh-pt5/src/app/dashboard/dashboard.component.css">
</code-pane>
</code-tabs>
{@a heroescomponent}
#### _HeroesComponent_
<code-tabs>
<code-pane
title="src/app/heroes/heroes.component.html" path="toh-pt5/src/app/heroes/heroes.component.html">
</code-pane>
<code-pane
title="src/app/heroes/heroes.component.ts"
path="toh-pt5/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane
title="src/app/heroes/heroes.component.css"
path="toh-pt5/src/app/heroes/heroes.component.css">
</code-pane>
</code-tabs>
{@a herodetailcomponent}
#### _HeroDetailComponent_
<code-tabs>
<code-pane
title="src/app/hero-detail/hero-detail.component.html" path="toh-pt5/src/app/hero-detail/hero-detail.component.html">
</code-pane>
<code-pane
title="src/app/hero-detail/hero-detail.component.ts" path="toh-pt5/src/app/hero-detail/hero-detail.component.ts">
</code-pane>
<code-pane
title="src/app/hero-detail/hero-detail.component.css" path="toh-pt5/src/app/hero-detail/hero-detail.component.css">
</code-pane>
</code-tabs>
## Summary
## 小结
* You added the Angular router to navigate among different components.
* You turned the `AppComponent` into a navigation shell with `<a>` links and a `<router-outlet>`.
* You configured the router in an `AppRoutingModule`
* You defined simple routes, a redirect route, and a parameterized route.
* You used the `routerLink` directive in anchor elements.
* You refactored a tightly-coupled master/detail view into a routed detail view.
* You used router link parameters to navigate to the detail view of a user-selected hero.
* You shared the `HeroService` among multiple components.

View File

@ -4,7 +4,9 @@ In this tutorial, you'll add the following data persistence features with help f
Angular's `HttpClient`.
* The `HeroService` gets hero data with HTTP requests.
* Users can add, edit, and delete heroes and save these changes over HTTP.
* Users can search for heroes by name.
When you're done with this page, the app should look like this <live-example></live-example>.
@ -16,7 +18,9 @@ When you're done with this page, the app should look like this <live-example></l
To make `HttpClient` available everywhere in the app,
* open the root `AppModule`,
* import the `HttpClientModule` symbol from `@angular/common/http`,
* add it to the `@NgModule.imports` array.
## Simulate a data server
@ -46,7 +50,9 @@ If you're _coding along_ with this tutorial, stay here and add the *In-memory We
Install the *In-memory Web API* package from _npm_
<code-example language="sh" class="code-shell">
npm install angular-in-memory-web-api --save
</code-example>
Import the `InMemoryWebApiModule` and the `InMemoryDataService` class,
@ -56,6 +62,7 @@ which you will create in a moment.
path="toh-pt6/src/app/app.module.ts"
region="import-in-mem-stuff"
title="src/app/app.module.ts (In-memory Web API imports)">
</code-example>
Add the `InMemoryWebApiModule` to the `@NgModule.imports` array&mdash;
@ -65,6 +72,7 @@ _after importing the `HttpClient`_,
<code-example
path="toh-pt6/src/app/app.module.ts"
region="in-mem-web-api-imports">
</code-example>
The `forRoot()` configuration method takes an `InMemoryDataService` class
@ -82,6 +90,7 @@ When your server is ready, detach the *In-memory Web API*, and the app's request
Now back to the `HttpClient` story.
{@a import-heroes}
## Heroes and HTTP
Import some HTTP symbols that you'll need:
@ -90,6 +99,7 @@ Import some HTTP symbols that you'll need:
path="toh-pt6/src/app/hero.service.ts"
region="import-httpclient"
title="src/app/hero.service.ts (import HTTP symbols)">
</code-example>
Inject `HttpClient` into the constructor in a private property called `http`.
@ -97,6 +107,7 @@ Inject `HttpClient` into the constructor in a private property called `http`.
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="ctor" >
</code-example>
Keep injecting the `MessageService`. You'll call it so frequently that
@ -105,6 +116,7 @@ you'll wrap it in private `log` method.
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="log" >
</code-example>
Define the `heroesUrl` with the address of the heroes resource on the server.
@ -112,6 +124,7 @@ Define the `heroesUrl` with the address of the heroes resource on the server.
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="heroesUrl" >
</code-example>
### Get heroes with _HttpClient_
@ -124,12 +137,14 @@ as an `Observable<Hero[]>`.
path="toh-pt4/src/app/hero.service.ts"
region="getHeroes-1"
title="src/app/hero.service.ts (getHeroes with RxJs 'of()')">
</code-example>
Convert that method to use `HttpClient`
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="getHeroes-1">
</code-example>
Refresh the browser. The hero data should successfully load from the
@ -181,6 +196,7 @@ Import the `catchError` symbol from `rxjs/operators`, along with some other oper
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="import-rxjs-operators">
</code-example>
Now extend the observable result with the `.pipe()` method and
@ -189,6 +205,7 @@ give it a `catchError()` operator.
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="getHeroes-2" >
</code-example>
The `catchError()` operator intercepts an **`Observable` that failed**.
@ -208,6 +225,7 @@ has configured with both the name of the operation that failed and a safe return
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="handleError">
</code-example>
After reporting the error to console, the handler constructs
@ -231,6 +249,7 @@ Here is the final version of `getHeroes` with the `tap` that logs the operation.
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="getHeroes" >
</code-example>
### Get hero by id
@ -244,7 +263,9 @@ Add a `HeroService.getHero()` method to make that request:
There are three significant differences from `getHeroes()`.
* it constructs a request URL with the desired hero's id.
* the server should respond with a single hero rather than an array of heroes.
* therefore, `getHero` returns an `Observable<Hero>` ("_an observable of Hero objects_")
rather than an observable of hero _arrays_ .
@ -277,11 +298,15 @@ on the server.
path="toh-pt6/src/app/hero.service.ts"
region="updateHero"
title="src/app/hero.service.ts (update)">
</code-example>
The `HttpClient.put()` method takes three parameters
* the URL
* the data to update (the modified hero in this case)
* options
The URL is unchanged. The heroes web API knows which hero to update by looking at the hero's `id`.
@ -292,6 +317,7 @@ That header is in the `httpOptions` constant defined in the `HeroService`.
<code-example
path="toh-pt6/src/app/hero.service.ts"
region="http-options">
</code-example>
Refresh the browser, change a hero name, save your change,
@ -330,6 +356,7 @@ Add the following `addHero()` method to the `HeroService` class.
`HeroService.addHero()` differs from `updateHero` in two ways.
* it calls `HttpClient.post()` instead of `put()`.
* it expects the server to generates an id for the new hero,
which it returns in the `Observable<Hero>` to the caller.
@ -384,8 +411,11 @@ Add a `deleteHero()` method to `HeroService` like this.
Note that
* it calls `HttpClient.delete`.
* the URL is the heroes resource URL plus the `id` of the hero to delete
* you don't send data as you did with `put` and `post`.
* you still send the `httpOptions`.
Refresh the browser and try the new delete functionality.
@ -409,6 +439,7 @@ Start by adding a `searchHeroes` method to the `HeroService`.
path="toh-pt6/src/app/hero.service.ts"
region="searchHeroes"
title="src/app/hero.service.ts">
</code-example>
The method returns immediately with an empty array if there is no search term.
@ -423,6 +454,7 @@ Add the hero search element, `<app-hero-search>`, to the bottom of the `Dashboar
<code-example
path="toh-pt6/src/app/dashboard/dashboard.component.html" title="src/app/dashboard/dashboard.component.html" linenums="false">
</code-example>
This template looks a lot like the `*ngFor` repeater in the `HeroesComponent` template.
@ -437,7 +469,9 @@ The `HeroSearchComponent` doesn't exist yet. Fix that.
Create a `HeroSearchComponent` with the CLI.
<code-example language="sh" class="code-shell">
ng generate component hero-search
</code-example>
The CLI generates the three `HeroSearchComponent` and adds the component to the `AppModule' declarations
@ -481,6 +515,7 @@ Notice the declaration of `heroes$` as an `Observable`
<code-example
path="toh-pt6/src/app/hero-search/hero-search.component.ts"
region="heroes-stream">
</code-example>
You'll set it in [`ngOnInit()`](#search-pipe).
@ -521,21 +556,17 @@ Here's the code.
<code-example
path="toh-pt6/src/app/hero-search/hero-search.component.ts"
region="search">
</code-example>
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
before passing along the latest string. You'll never make requests more frequently than 300ms.
* `distinctUntilChanged` ensures that a request is sent only if the filter text changed.
* `switchMap()` calls the search service for each search term that makes it through `debounce` and `distinctUntilChanged`.
It cancels and discards previous search observables, returning only the latest search service observable.
<div class="l-sub-section">
With the [switchMap operator](http://www.learnrxjs.io/operators/transformation/switchmap.html),
@ -561,7 +592,9 @@ Run the app again. In the *Dashboard*, enter some text in the search box.
If you enter characters that match any existing hero names, you'll see something like this.
<figure>
<img src='generated/images/guide/toh/toh-hero-search.png' alt="Hero Search Component">
</figure>
## Final code review
@ -573,81 +606,119 @@ Here are the code files discussed on this page (all in the `src/app/` folder).
{@a heroservice}
{@a inmemorydataservice}
{@a appmodule}
#### _HeroService_, _InMemoryDataService_, _AppModule_
<code-tabs>
<code-pane
title="hero.service.ts"
path="toh-pt6/src/app/hero.service.ts">
</code-pane>
<code-pane
title="in-memory-data.service.ts"
path="toh-pt6/src/app/in-memory-data.service.ts">
</code-pane>
<code-pane
title="app.module.ts"
path="toh-pt6/src/app/app.module.ts">
</code-pane>
</code-tabs>
{@a heroescomponent}
#### _HeroesComponent_
<code-tabs>
<code-pane
title="heroes/heroes.component.html"
path="toh-pt6/src/app/heroes/heroes.component.html">
</code-pane>
<code-pane
title="heroes/heroes.component.ts"
path="toh-pt6/src/app/heroes/heroes.component.ts">
</code-pane>
<code-pane
title="heroes/heroes.component.css"
path="toh-pt6/src/app/heroes/heroes.component.css">
</code-pane>
</code-tabs>
{@a herodetailcomponent}
#### _HeroDetailComponent_
<code-tabs>
<code-pane
title="hero-detail/hero-detail.component.html"
path="toh-pt6/src/app/hero-detail/hero-detail.component.html">
</code-pane>
<code-pane
title="hero-detail/hero-detail.component.ts"
path="toh-pt6/src/app/hero-detail/hero-detail.component.ts">
</code-pane>
</code-tabs>
{@a herosearchcomponent}
#### _HeroSearchComponent_
<code-tabs>
<code-pane
title="hero-search/hero-search.component.html"
path="toh-pt6/src/app/hero-search/hero-search.component.html">
</code-pane>
<code-pane
title="hero-search/hero-search.component.ts"
path="toh-pt6/src/app/hero-search/hero-search.component.ts">
</code-pane>
<code-pane
title="hero-search/hero-search.component.css"
path="toh-pt6/src/app/hero-search/hero-search.component.css">
</code-pane>
</code-tabs>
## Summary
## 小结
You're at the end of your journey, and you've accomplished a lot.
* You added the necessary dependencies to use HTTP in the app.
* You refactored `HeroService` to load heroes from a web API.
* You extended `HeroService` to support `post()`, `put()`, and `delete()` methods.
* You updated the components to allow adding, editing, and deleting of heroes.
* You configured an in-memory web API.
* You learned how to use Observables.
This concludes the "Tour of Heroes" tutorial.