This commit is contained in:
Rex Ye 2016-05-17 15:42:26 +01:00
commit dc5e87aad0
6 changed files with 65 additions and 69 deletions

View File

@ -2,7 +2,7 @@
"index": {
"title": "烹饪书",
"navTitle": "概览",
"description": "一组常见Angular应用场景的“菜谱”"
"description": "一组常见Angular应用场景的“烹饪书”"
},
"a1-a2-quick-reference": {

View File

@ -5,7 +5,7 @@ include ../_util-fns
This cookbook contains recipes for common component communication scenarios
in which two or more components share information.
菜谱包含了常见的组件通讯场景,也就是让两个或多个组件之间共享信息的方法。
烹饪书包含了常见的组件通讯场景,也就是让两个或多个组件之间共享信息的方法。
.l-sub-section
:marked

View File

@ -4,7 +4,7 @@ include ../_util-fns
Dependency Injection is a powerful pattern for managing code dependencies.
In this cookbook we will explore many of the features of Dependency Injection (DI) in Angular.
依赖注入是一个强大的管理代码依赖链的架构模式。在这个“菜谱”中我们会讨论Angular依赖注入的许多特性。
依赖注入是一个用来管理代码依赖的强大模式。在这本“烹饪书”中我们会讨论Angular依赖注入的许多特性。
<a id="toc"></a>
:marked
@ -18,23 +18,23 @@ include ../_util-fns
[External module configuration](#external-module-configuration)
[外部模块置](#external-module-configuration)
[外部模块置](#external-module-configuration)
[*@Injectable* and nested service dependencies](#nested-dependencies)
[*@Injectable*嵌套服务的依赖](#nested-dependencies)
[*@Injectable*嵌套服务的依赖](#nested-dependencies)
[Limit service scope to a component subtree](#service-scope)
[限制服务作用范围到一个组件支树](#service-scope)
[把服务作用范围限制到一个子组件树](#service-scope)
[Multiple service instances (sandboxing)](#multiple-service-instances)
[多个服务实例(sandboxing)](#multiple-service-instances)
[多个服务实例(沙箱)](#multiple-service-instances)
[Qualify dependency lookup with *@Optional* and *@Host*](#qualify-dependency-lookup)
[使用*@Optional*和*@Host*装饰来认证依赖调用过程](#qualify-dependency-lookup)
[使用*@Optional*和*@Host*装饰器来限定依赖查找方式](#qualify-dependency-lookup)
[Inject the component's DOM element](#component-element)
@ -46,7 +46,7 @@ include ../_util-fns
* [The *provide* function](#provide)
* [*provide*功能](#provide)
* [*provide*函数](#provide)
* [useValue - the *value provider*](#usevalue)
@ -66,7 +66,7 @@ include ../_util-fns
[Provider token alternatives](#tokens)
[供应商可选令牌](#tokens)
[供应商可选Token](#tokens)
* [class-interface](#class-interface)
@ -82,23 +82,23 @@ include ../_util-fns
[Find a parent component by injection](#find-parent)
[通过注入来锁定父级组件](#find-parent)
[通过注入来查找父组件](#find-parent)
* [Find parent with a known component type](#known-parent)
* [通过已知组件类型锁定父级组件](#known-parent)
* [通过已知组件类型查找父组件](#known-parent)
* [Cannot find a parent by its base class](#base-parent)
* [通过自己的基础类无法锁定父级组件](#base-parent)
* [无法通过自己的基类查找父组件](#base-parent)
* [Find a parent by its class-interface](#class-interface-parent)
* [通过父级的类-接口锁定父级组件](#class-interface-parent)
* [通过类-接口查找父组件](#class-interface-parent)
* [Find a parent in a tree of parents (*@SkipSelf*)](#parent-tree)
* [使用(*@SkipSelf*)在父级树里锁定一个父级组件](#parent-tree)
* [在父组件树里查找一个父组件(*@SkipSelf*)](#parent-tree)
* [A *provideParent* helper function](#provideparent)
@ -106,13 +106,13 @@ include ../_util-fns
[Break circularities with a forward class reference (*forwardRef*)](#forwardref)
[使用一个forward类引用(*forwardRef*)打破环依赖](#forwardref)
[使用类的前向引用(*forwardRef*)打破环依赖](#forwardref)
:marked
**See the [live example](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)**
of the code supporting this cookbook.
获取本“菜谱”的代码支持**参见[在线例子](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)**。
要获取本“烹饪书”的代码**参见[在线例子](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)**。
.l-main-section
@ -124,13 +124,13 @@ include ../_util-fns
Register providers for dependencies used throughout the application in the root application component, `AppComponent`.
在应用程序根组件`AppComponent`注册那些被应用程序全局使用的依赖供应商。
在应用程序根组件`AppComponent`注册那些被应用程序全局使用的依赖供应商。
In the following example, we import and register several services
(the `LoggerService`, `UserContext`, and the `UserService`)
in the `@Component` metadata `providers` array.
在下面的例子中,在`@Component`元数据的`Providers`数组中,导入和注册了几个服务(`LoggerService`, `UserContext`和`UserService`)。
在下面的例子中,通过`@Component`元数据的`providers`数组导入和注册了几个服务(`LoggerService`, `UserContext`和`UserService`)。
+makeExample('cb-dependency-injection/ts/app/app.component.ts','import-services','app/app.component.ts (excerpt)')(format='.')
:marked
@ -138,7 +138,7 @@ include ../_util-fns
Service classes can act as their own providers which is why listing them in the `providers` array
is all the registration we need.
所有上面这些服务都是用类实现的。服务类能充当自己的供应商,这就是为什么把它们列到一个`providers`数组里是唯一的注册要求
所有这些服务都是用类实现的。服务类能充当自己的供应商,这就是为什么只要把它们列在`providers`数组里就算注册成功了
.l-sub-section
:marked
@ -146,13 +146,13 @@ include ../_util-fns
Angular creates a service instance from a class provider by "new-ing" it.
Learn more about Providers [below](#providers).
*供应商*是用来新建或者送交服务的。Angular从一个类-供应商里面通过“new-ing”来新建服务实例的。从[下面](#providers)学习更多关于供应商的知识。
*供应商*是用来新建或者交付服务的。Angular拿到“类供应商”之后会通过“new”操作来新建服务实例。从[下面](#providers)可以学到更多关于供应商的知识。
:marked
Now that we've registered these services,
Angular can inject them into the constructor of *any* component or service, *anywhere* in the application.
现在已经注册了这些服务Angular能够在应用程序的*任何地方*,将它们注入到*任何*组件和服务的构造函数里
现在我们已经注册了这些服务这样Angular就能在应用程序的*任何地方*,把它们注入到*任何*组件和服务的构造函数里。
+makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','ctor','app/hero-bios.component.ts (component constructor injection)')(format='.')
@ -162,38 +162,35 @@ include ../_util-fns
.l-main-section
:marked
## External module configuration
## 外部模块设置
We can register _certain_ module providers when bootstrapping rather than in the root application component.
可以在引导过程中注册_某些_模块供应商而非在应用程序根组件里。
可以在引导过程中注册_某些_模块供应商而非在应用程序根组件里。
We'd do this when we expect to select or configure external modules that support our application
but (a) aren't conceptually part of the application and (b) that we could change later without
altering the essential logic of the application.
当使用支持我们的应用的外部组件时,在满足下面两个条件的时候,应该在引导过程中注册:
a在概念上不是我们程序的一部分
b在未来可能需要在不变化主要应用程序逻辑的情况下更换它。
使用外部模块时如果满足下面两个条件就应该在引导过程中注册a它在概念上不是我们程序的一部分以及 b将来我们可能要在不改变主要应用逻辑的情况下更换它。
For example, we might configure the Component Router with different
[location strategies](../guide/router.html#location-strategy) based on environmental factors.
The choice of location strategy doesn't matter to the application itself.
比如,根据不同的环境因素设置不同的组件路由, 使用不同的[location strategies](../guide/router.html#location-strategy)。这个location strategy不直接影响应用程序本身。
比如,可能会根据不同的环境组件路由器,使用不同的[location策略](../guide/router.html#location-strategy)来配置组件路由器。而这个location策略不会直接影响到应用程序本身。
We could sneak in a fake HTTP backend with sample data during development rather than
allow http calls to a remote server (that might not yet exist).
We'll switch to the real backend in production.
The application shouldn't know or care one way or the other.
在开发过程中,可以偷偷把一个假的带有例子数据的HTTP后端嵌入进来来取代对一个远程服务器可能还不存在进行http查询。我们在产品发布时再切换到真正的后端。应用程序不需要知道,也不在乎哪个后端
在开发过程中,可以偷偷把一个假的带样本数据的HTTP后端嵌入进来以代替对一个远程服务器可能还不存在进行http查询。我们在产品发布时再切换到真正的后端。应用程序不用知道也不用管正在跟哪个后端打交道
See both examples in the following `main.ts`
where we list their service providers in an array in the second parameter of the `bootstrap` method.
在下面`main.ts`的两个例子中,在`bootstrap`方法的第二个参数的数组中,我们列出了它们的服务供应商。
在下面`main.ts`的两个例子中,在`bootstrap`方法的第二个数组型参数中,我们列出了它们的服务供应商。
+makeExample('cb-dependency-injection/ts/app/main.ts','bootstrap','app/main.ts')(format='.')
@ -209,18 +206,18 @@ a(id="nested-dependencies")
It shouldn't care.
It's the dependency injection's job to create and cache that service.
被注入服务的使用者不应该知道如何创建这个服务。它也不应该在乎。新建和缓存这个服务是依赖注入器的工作。
这些被注入服务的消费者不需要知道如何创建这个服务,它也不应该在乎。新建和缓存这个服务是依赖注入器的工作。
Sometimes a service depends on other services ... which may depend on yet other services.
Resolving these nested dependencies in the correct order is also the framework's job.
At each step, the consumer of dependencies simply declares what it requires in its constructor and the framework takes over.
有时候一个服务依赖其它服务...而其它服务可能依赖另外的服务。按正确的顺序解析这些嵌套依赖也是框架工具Angualar 2依赖注入的工作。
在每一步,依赖的使用者只是在它的构造函数里简单地声明它需要什么,框架工具会做剩余的事情。
有时候一个服务依赖其它服务...而其它服务可能依赖另外的更多服务。按正确的顺序解析这些嵌套依赖也是框架的工作。
在每一步,依赖的使用者只要在它的构造函数里简单声明它需要什么,框架就会完成所有剩下的事情。
For example, we inject both the `LoggerService` and the `UserContext` in the `AppComponent`.
比如,我们在`AppComponent`里注入`LoggerService`和`UserContext`。
比如,我们在`AppComponent`里注入`LoggerService`和`UserContext`。
+makeExample('cb-dependency-injection/ts/app/app.component.ts','ctor','app/app.component.ts')(format='.')
@ -238,24 +235,23 @@ a(id="nested-dependencies")
The `UserContextService` needs the `LoggerService`, which the framework already has, and the `UserService`, which it has yet to create.
The `UserService` has no dependencies so the dependency injection framework can just `new` one into existence.
当Angular新建`AppComponent`时,依赖注入框架工具创建一个`LoggerService`的实例,并开始创建`UserContextService`实例。
`UserContextService`需要框架工具已经创建了的`LoggerService`实例和还没创建的`UserService`实例。
`UserService`没有其它依赖,所以依赖注入框架工具可以直接`new`一个实例。
当Angular新建`AppComponent`时,依赖注入框架先创建一个`LoggerService`的实例,然后创建`UserContextService`实例。
`UserContextService`需要框架已经创建好的`LoggerService`实例和尚未创建的`UserService`实例。
`UserService`没有其它依赖,所以依赖注入框架可以直接`new`一个实例。
The beauty of dependency injection is that the author of `AppComponent` didn't care about any of this.
The author simply declared what was needed in the constructor (`LoggerService` and `UserContextService`) and the framework did the rest.
依赖注入美丽的地方在于,`AppComponent`的作者不需要在乎这一切。作者只是在(`LoggerService`和`UserContextService`的)构造函数里面简单地声明一下,框架工具来做剩下的工作。
依赖注入最帅的地方在于,`AppComponent`的作者不需要在乎这一切。作者只是在(`LoggerService`和`UserContextService`的)构造函数里面简单的声明一下,框架就完成了剩下的工作。
Once all the dependencies are in place, the `AppComponent` displays the user information:
一旦所有依赖都准备好了,`AppComponent`显示用户信息:
一旦所有依赖都准备好了,`AppComponent`就会显示用户信息:
figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/logged-in-user.png" alt="Logged In User")
:marked
### *@Injectable()*
### *@Injectable()*
Notice the `@Injectable()`decorator on the `UserContextService` class.
@ -266,27 +262,27 @@ figure.image-display
:marked
That decorator makes it possible for Angular to identify the types of its two dependencies, `LoggerService` and `UserService`.
该装饰器让Angular有能力辨认它的两个依赖 `LoggerService` 和 `UserService`
该装饰器让Angular有能力识别这两个依赖 `LoggerService` 和 `UserService`的类型
Technically, the `@Injectable()`decorator is only _required_ for a service class that has _its own dependencies_.
The `LoggerService` doesn't depend on anything. The logger would work if we omitted `@Injectable()`
and the generated code would be slightly smaller.
技术上讲,这个`@Injectable()`装饰器只在一个服务类有_自己的依赖_的时候才是_不可缺少_的。
`LoggerService`不依赖任何东西,所以该日志服务在没有`@Injectable()`的时候应该也工作,生成的代码也小一些。
技术上讲,这个`@Injectable()`装饰器只在一个服务类有_自己的依赖_的时候才是_不可缺少_的。
`LoggerService`不依赖任何东西,所以该日志服务在没有`@Injectable()`的时候应该也能工作,生成的代码也更少一些。
But the service would break the moment we gave it a dependency and we'd have to go back and
and add `@Injectable()` to fix it. We add `@Injectable()` from the start for the sake of consistency and to avoid future pain.
但是在添加依赖给它的那一刻,该服务就会停止工作,要修复它,就必须要添加`@Injectable()`。
为了保持一致性和防止将来的麻烦,推荐从一开始就加`@Injectable()`。
但是在给它添加依赖的那一瞬间,该服务就会停止工作,要想修复它,就必须要添加`@Injectable()`。
为了保持一致性和防止将来的麻烦,推荐从一开始就加`@Injectable()`。
.alert.is-helpful
:marked
Although we recommend applying `@Injectable` to all service classes, do not feel bound by it.
Some developers prefer to add it only where needed and that's a reasonable policy too.
虽然我们推荐在所有服务中使用`@Injectable()`,但是你不需要一定要这么做。一些开发者宁可在需要添加的地方才添加,这也是一个合理的策略。
虽然我们推荐在所有服务中使用`@Injectable()`,但你也不需要一定要这么做。一些开发者就更喜欢在真正需要的地方才添加,这也是一个合理的策略。
.l-sub-section
:marked
@ -294,41 +290,41 @@ figure.image-display
It didn't need `@Injectable()` because that component class has the `@Component` decorator.
In Angular with TypeScript, a *single* decorator &mdash; *any* decorator &mdash; is sufficient to identify dependency types.
`AppComponent`类有两个依赖,但没有`@Injectable()`。
它不需要`@Injectable()`是因为组件类有`@Component`装饰器。
在用TypeScript的Angular应用里有一个 *单独的* 装饰器 &mdash; *任何* 装饰器 &mdash; 来辨识依赖类别就足够了。
`AppComponent`类有两个依赖,但没有`@Injectable()`。
它不需要`@Injectable()`,这是因为组件类有`@Component`装饰器。
在用TypeScript的Angular应用里有一个*单独的*装饰器 &mdash; *任何*装饰器 &mdash; 来标识依赖的类型就够了。
<a id="service-scope"></a>
.l-main-section
:marked
## Limit service scope to a component subtree
## 限制服务作用范围到一个组件支树
## 把服务作用范围限制到一个组件支树
All injected service dependencies are singletons meaning that,
for a given dependency injector ("injector"), there is only one instance of service.
所有注入的服务依赖都是单例singletons)的,也就是说,在任意一个依赖注入器("injector")中,每个服务只有一个唯一的实例。
所有注入的服务依赖都是单例的,也就是说,在任意一个依赖注入器("injector")中,每个服务只有唯一的实例。
But an Angular application has multiple dependency injectors, arranged in a tree hierarchy that parallels the component tree.
So a particular service can be *provided* (and created) at any component level and multiple times
if provided in multiple components.
但是Angular应用程序有多个依赖注入器组织在一个与组件树平行的树形结构中。所以,可以在任何组件级别*提供*(和建立)特定的服务。如果在多个组件中注入,服务就会被新建多个实例,分别组件中提供。
但是Angular应用程序有多个依赖注入器组织成一个与组件树平行的树状结构。所以,可以在任何组件级别*提供*(和建立)特定的服务。如果在多个组件中注入,服务就会被新建多个实例,分别提供给不同的组件
By default, a service dependency provided in one component is visible to all of its child components and
Angular injects the same service instance into all child components that ask for that service.
默认情况下,一个组件中注入的服务依赖,会在所有该组件的子组件中能见而且Angular会注入同样的服务实例到要求该服务的子组件中。
默认情况下,一个组件中注入的服务依赖,会在该组件的所有子组件中可见而且Angular会把同样的服务实例注入到需要该服务的子组件中。
Accordingly, dependencies provided in the root `AppComponent` can be injected into *any* component *anywhere* in the application.
同样,在根部`AppComponent`提供的依赖的单一实例能被注入到*任何*组件,到应用程序的*任何地方*
所以,在根部的`AppComponent`提供的依赖单例就能被注入到应用程序中*任何地方*的*任何*组件
That isn't always desireable.
Sometimes we want to restrict service availability to a particular region of the application.
这不一定总是我们想要的。有时候我们想要把服务的有效性限制到应用程序的一个特定区域。
这不一定总是我们想要的。有时候我们想要把服务的有效性限制到应用程序的一个特定区域。
We can limit the scope of an injected service to a *branch* of the application hierarchy
by providing that service *at the sub-root component for that branch*.
@ -469,7 +465,7 @@ a(id="qualify-dependency-lookup")
But when this component is projected into a *parent* component, that parent component becomes the host.
We look at this second, more interesting case in our next example.
宿主组件一般为请求依赖的组件。但是当这个组件被投放到一个*父级*组件后,该父组件变成了主持。我们考虑一会,更多有趣的案例还在后面。
宿主组件一般为请求依赖的组件。但是当这个组件被投放到一个*父级*组件后,该父组件变成了主持。我们考虑一会,更多有趣的案例还在后面。
### Demonstration
### 示范
@ -820,7 +816,7 @@ a(id='useclass')
This component and its tree of child components receive the `DateLoggerService` instance.
Components outside the tree continue to receive the original `LoggerService` instance.
这个组件和它的子组件树得到`DateLoggerService`实例。在这些组件之外的组件树得到的还是`LoggerService`实例。
这个组件和它的子组件树得到`DateLoggerService`实例。在这些组件之外的组件树得到的还是`LoggerService`实例。
:marked
The `DateLoggerService` inherits from `LoggerService`; it appends the current date/time to each message:
@ -1145,7 +1141,7 @@ a(id="find-parent")
:marked
## Find a parent component by injection
## 通过注入来找到一个父组件
## 通过注入来找到一个父组件
Application components often need to share information.
We prefer the more loosely coupled techniques such as data binding and service sharing.
@ -1170,7 +1166,7 @@ a(id="find-parent")
But because every component instance is added to an injector's container,
we can use Angular dependency injection to reach a parent component.
没有公共API来获取父组件的引用。但是因为每个组件实例都被加到了依赖注入器容器中我们可以使用Angular依赖注入来抓住父组件。
没有公共API来获取父组件的引用。但是因为每个组件实例都被加到了依赖注入器容器中我们可以使用Angular依赖注入来抓住父组件。
This section describes some techniques for doing that.
@ -1179,11 +1175,11 @@ a(id="find-parent")
<a id="known-parent"></a>
### Find a parent component of known type
### 找到已知类型的父组件
### 找到已知类型的父组件
We use standard class injection to acquire a parent component whose type we know.
我们使用标准类注入来获取已知类型的父组件。
我们使用标准类注入来获取已知类型的父组件。
In the following example, the parent `AlexComponent` has several children including a `CathyComponent`:
@ -1212,7 +1208,7 @@ a(id='alex')
What if we do *not* know the concrete parent component class?
如果我们*不*知道父组件类的具体实施怎么办?
如果我们*不*知道父组件类的具体实施怎么办?
A re-usable component might be a child of multiple components.
Imagine a component for rendering breaking news about a financial instrument.
@ -1269,7 +1265,7 @@ a(id='alex')
We can find a parent component with a [class-interface](#class-interface).
我们能通过[类-接口](#class-interface)找到一个父组件。
我们能通过[类-接口](#class-interface)找到一个父组件。
The parent must cooperate by providing an *alias* to itself in the name of a *class-interface* token.
@ -1297,7 +1293,7 @@ a(id="alex-providers")
*Carol*, the third of *Alex*'s child components, injects the parent into its `parent` parameter, the same way we've done it before:
*Carol**Alex*的第三个子组件,把父级注入到自己的`parent`参数,和我们之前做的一样:
*Carol**Alex*的第三个子组件,把父级注入到自己的`parent`参数,和我们之前做的一样:
+makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','carol-class','parent-finder.component.ts (CarolComponent class)')(format='.')
:marked
@ -1395,8 +1391,8 @@ a(id="parent-token")
The `name` property is the only member of a parent component that a child component can call.
Such a narrowing interface helps decouple the child component class from its parent components.
该`Parent` *类-接口*定义了`Name`属性,它有类型声明,但是*没有实施*,该`name`是该父级的所有子组件们唯一能调用的属性。
这样一个窄的接口帮助分离子级类和它的父组件。
该`Parent` *类-接口*定义了`Name`属性,它有类型声明,但是*没有实施*,该`name`是该父级的所有子组件们唯一能调用的属性。
这样一个窄的接口帮助分离子级类和它的父组件。
A component that could serve as a parent *should* implement the *class-interface* as the `AliceComponent` does:

View File

@ -14,7 +14,7 @@ include ../_util-fns
It might evolve to support a much richer variety of questions, more graceful rendering, and superior user experience.
All such greatness has humble beginnings.
本菜谱中,我们会展示如何利用`ngFormModel`来动态渲染一个简单的表单,包括多种类型控制器和验证规则。
此烹饪书中,我们会展示如何利用`ngFormModel`来动态渲染一个简单的表单,包括多种类型控制器和验证规则。
这只是一个初级的开始,但是任何伟大都是从谦卑开始的。我们可以在这个基础上添加种类丰富的问卷问题,更加优美的渲染和更加优越的用户体验。
In our example we use a dynamic form to build an online application experience for heroes seeking employment.

View File

@ -17,7 +17,7 @@ include ../_util-fns
:marked
The cookbook is just getting started. Many more recipes are on the way.
这本烹饪书只是一个开始。我们正在编写更多“菜谱”。
这本烹饪书只是一个开始。我们正在编写更多“烹饪书”。
:marked
Each cookbook chapter links to a live sample with every recipe included.

View File

@ -5,7 +5,7 @@ a(id='top')
Our app should be able to make the browser title bar say whatever we want it to say.
This cookbook explains how to do it.
应用程序应该能让浏览器标题栏显示我们想要它显示的内容。本*菜谱*解释怎么做。
应用程序应该能让浏览器标题栏显示我们想要它显示的内容。本*烹饪书*解释怎么做。
:marked
**See the [live example](/resources/live-examples/cb-set-document-title/ts/plnkr.html)**.