di review - half.

This commit is contained in:
Zhimin(Rex) YE 2016-05-14 16:27:11 +01:00
parent 33292b942c
commit 6a4799fe2d
1 changed files with 113 additions and 68 deletions

View File

@ -128,26 +128,30 @@ include ../_util-fns
(the `LoggerService`, `UserContext`, and the `UserService`)
in the `@Component` metadata `providers` array.
在下面的例子中,我们在`@Component`元数据的`供应商`数组中,导入和注册了几个服务(`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
All of these services are implemented as classes.
Service classes can act as their own providers which is why listing them in the `providers` array
is all the registration we need.
所有上面这些服务都是用类来实现的。服务类能充当它们自己的供应商,这就是为什么把它们列到一个`供应商`数组里是唯一的注册要求。
所有上面这些服务都是用类来实现的。服务类能充当自己的供应商,这就是为什么把它们列到一个`providers`数组里是唯一的注册要求。
.l-sub-section
:marked
A *provider* is something that can create or deliver a service.
Angular creates a service instance from a class provider by "new-ing" it.
Learn more about 供应商 [below](#providers).
一个*供应商*是用来新建或者送交服务的。Angular从一个类供应商里面通过“new-ing”来新建服务实例的。从[下面](#providers)学习更多关于provders的知识。
Learn more about Providers [below](#providers).
*供应商*是用来新建或者送交服务的。Angular从一个类-供应商里面通过“new-ing”来新建服务实例的。从[下面](#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='.')
+makeExample('cb-dependency-injection/ts/app/user-context.service.ts','ctor','app/user-context.service.ts (service constructor injection)')(format='.')
@ -157,35 +161,36 @@ include ../_util-fns
: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在未来我们可能需要在不变化主要应用程序逻辑的情况下,更改或更换它。
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 strategies](../guide/router.html#location-strategy)。这个location strategy不直接影响应用程序本身。
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`类方法的第二个参数的数组中我们列出了它们的service 供应商(服务提供者)
在下面`main.ts`的两个例子中,在`bootstrap`函数方法的第二个参数的数组中,我们列出了它们的服务供应商
+makeExample('cb-dependency-injection/ts/app/main.ts','bootstrap','app/main.ts')(format='.')
@ -200,7 +205,7 @@ 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.
@ -212,13 +217,14 @@ a(id="nested-dependencies")
For example, we inject both the `LoggerService` and the `UserContext` in the `AppComponent`.
比如,我们在`AppComponent`里注入`LoggerService`和`UserContext`。
+makeExample('cb-dependency-injection/ts/app/app.component.ts','ctor','app/app.component.ts')(format='.')
:marked
The `UserContext` in turn has dependencies on both the `LoggerService` (again) and
a `UserService` that gathers information about a particular user.
`UserContext`有两个依赖`LoggerService`(再次)和负责获取特定用户信息的`UserService`。
`UserContext`有两个依赖`LoggerService`(再次)和负责获取特定用户信息的`UserService`。
+makeExample('cb-dependency-injection/ts/app/user-context.service.ts','injectables','user-context.service.ts (injection)')(format='.')
@ -228,25 +234,29 @@ 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`。
当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`显示用户信息:
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.
请注意在`UserContextService`类里面的`@Injectable()`装饰器。
注意在`UserContextService`类里面的`@Injectable()`装饰器。
+makeExample('cb-dependency-injection/ts/app/user-context.service.ts','injectable','user-context.service.ts (@Injectable)')(format='.')
:marked
That decorator makes it possible for Angular to identify the types of its two dependencies, `LoggerService` and `UserService`.
@ -257,18 +267,21 @@ figure.image-display
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
@ -276,44 +289,48 @@ figure.image-display
It didn't need `@Injectable()` because that component class has the `@Component` decorator.
In Angular with TypeScript, a *single* decorator — *any* decorator — is sufficient to identify dependency types.
`AppComponent`类有两个依赖,但是没有`@Injectable()`。它不需要`@Injectable()`是因为组件类有`@Component`装饰器。
在用TypeScript的Angular应用程序一个 *单独的* 装饰器 — *任何* 装饰器 — 来辨识依赖类别就足够了。
`AppComponent`类有两个依赖,但是没有`@Injectable()`。
它不需要`@Injectable()`是因为组件类有`@Component`装饰器。
在用TypeScript的Angular应用里有一个 *单独的* 装饰器 — *任何* 装饰器 — 来辨识依赖类别就足够了。
<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")中,每个服务只有一个唯一的实例。
所有注入的服务依赖都是单例singletons)的,也就是说,在任意一个依赖注入器("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*.
Here we provide the `HeroService` to the `HeroesBaseComponent` by listing it in the `providers` array:
通过*在该分支的子级根部组件*中提供该服务, 我们能把一个注入服务的作用范围局限到一个应用程序结构的该*分支*中。
这里我们通过列入`供应商`数列,在`HeroesBaseComponent`中提供了`HeroService`
通过*在组件树分支的子级根部组件*中提供服务,把一个被注入的服务的作用范围局限到应用程序结构中的某个*分支*中。
这里通过列入`providers`数列,在`HeroesBaseComponent`中提供了`HeroService`
+makeExample('cb-dependency-injection/ts/app/sorted-heroes.component.ts','injection','app/sorted-heroes.component.ts (HeroesBaseComponent excerpt)')
:marked
When Angular creates the `HeroesBaseComponent`, it also creates a new instance of `HeroService`
@ -324,24 +341,27 @@ figure.image-display
We could also provide the `HeroService` to a *different* component elsewhere in the application.
That would result in a *different* instance of the service, living in a *different* injector.
我们也可以在应用程序的另外的地方的*不同的*组件里提供`HeroService`。这样的结果是一个*不同的*该服务的实例,在一个*不同的*注入器内存在。
我们也可以在应用程序的另外的地方的*不同的*组件里提供`HeroService`。这样的结果是该服务的*不同的*实例,在*不同的*注入器内存在。
.l-sub-section
:marked
We examples of such scoped `HeroService` singletons appear throughout the accompanying sample code,
including the `HeroBiosComponent`, `HeroOfTheMonthComponent`, and `HeroesBaseComponent`.
Each of these components has its own `HeroService` instance managing its own independent collection of heroes.
我们这个局限范围的`HeroService`单例的例子,贯穿伴随例子代码,包括`HeroBiosComponent`, `HeroOfTheMonthComponent`和`HeroBaseComponent`。
这些组件中每个都有自己的`HeroService`实例,管理自己独立的英雄库。
这个局限范围的`HeroService`单例的例子,贯穿伴随例子代码,包括`HeroBiosComponent``HeroOfTheMonthComponent`和`HeroBaseComponent`。
这些组件中每个都有自己的`HeroService`实例,用来管理自己独立的英雄库。
.l-main-section
.alert.is-helpful
:marked
### Take a break!
### 休息一下!
This much Dependency Injection knowledge may be all that many Angular developers
ever need to build their applications. It doesn't always have to be more complicated.
对一些Angular开发者来说这么多依赖注入知识可能是所有需要的全部知识。不一定都要更加复杂。
对一些Angular开发者来说这么多依赖注入知识可能是全部他们需要的知识。不一定都需要更加复杂的用法。
<a id="multiple-service-instances"></a>
.l-main-section
@ -358,30 +378,34 @@ figure.image-display
Each service has its own work-state, isolated from the service-and-state of a different component.
We call this *sandboxing* because each service and component instance has its own sandbox to play in.
一个管理自己伴随组件实例状态的服务是个好例子。
对每个组件,我们都需要该服务的单独实例。每个服务有自己的工作-状态,与其它组件的服务-和-状态隔离。我们叫这个*sandboxing*,因为每个服务和组件实例都在自己的沙盒里运行。
一个用来保存自己伴随组件实例状态的服务是个好例子。
对每个组件,我们都需要该服务的单独实例。
每个服务有自己的工作-状态,与其它组件的服务-和-状态隔离。我们称作*sandboxing*,因为每个服务和组件实例都在自己的沙盒里运行。
<a id="hero-bios-component"></a>
Imagine a `HeroBiosComponent` that presents three instances of the `HeroBioComponent`.
想象一下,一个`HeroBioComponent`,显示三个`HeroBioComponent`的实例。
想象一下,一个`HeroBioComponent`组件显示三个`HeroBioComponent`的实例。
+makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','simple','ap/hero-bios.component.ts')
:marked
Each `HeroBioComponent` can edit a single hero's biography.
A `HeroBioComponent` relies on a `HeroCacheService` to fetch, cache, and perform other persistence operations on that hero.
每个`HeroBioComponent`都能编辑一个英雄的生平。一个`HeroBioComponent`依赖一个`HeroCacheService`来对该英雄进行读取、缓存和执行其它持久性质的操作。
每个`HeroBioComponent`都能编辑一个英雄的生平。`HeroBioComponent`依赖`HeroCacheService`服务来对该英雄进行读取、缓存和执行其它持久性质的操作。
+makeExample('cb-dependency-injection/ts/app/hero-cache.service.ts','service','app/hero-cache.service.ts')
:marked
Clearly the three instances of the `HeroBioComponent` can't share the same `HeroCacheService`.
They'd be competing with each other to determine which hero to cache.
很明显,这三个`HeroBioComponent`实例不能共享一样的`HeroCacheService`。要不然它们会相互竞争冲突,取决于哪个英雄在缓存里面。
很明显,这三个`HeroBioComponent`实例不能共享一样的`HeroCacheService`。要不然它们会相互竞争冲突,争相决定哪个英雄在缓存里面。
Each `HeroBioComponent` gets its *own* `HeroCacheService` instance
by listing the `HeroCacheService` in its metadata `providers` array.
通过在自己的元数据metadata)提供者(供应商)数组里面列出`HeroCacheService`, 每个`HeroBioComponent`有自己*拥有*的`HeroCacheService`实例。
通过在自己的元数据metadata)`Providers`数组里面列出`HeroCacheService`, 每个`HeroBioComponent`*拥有*自己独立的`HeroCacheService`实例。
+makeExample('cb-dependency-injection/ts/app/hero-bio.component.ts','component','app/hero-bio.component.ts')
:marked
The parent `HeroBiosComponent` binds a value to the `heroId`.
@ -389,12 +413,13 @@ figure.image-display
The getter for the `hero` property pulls the cached hero from the service.
And the template displays this data-bound property.
父级`HeroBioComponent`绑定一个变量到`HeroId`。`ngOnInit`传递该`id`到服务,服务获取和缓存英雄。`hero`属性的getter从服务里面获取缓冲的英雄并在模板里面显示该数据绑定的属性。
父级`HeroBioComponent`绑定一个变量到`HeroId`。`ngOnInit`传递该`id`到服务,然后服务获取和缓存英雄。`hero`属性的getter从服务里面获取缓冲的英雄并在模板里面显示该数据绑定的属性
Find this example in [live code](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)
and confirm that the three `HeroBioComponent` instances have their own cached hero data.
在[在线代码](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)找到这个例子,确认三个`HeroBioComponent`实例有自己拥有的缓冲的英雄数据。
到[在线代码](/resources/live-examples/cb-dependency-injection/ts/plnkr.html)找到这个例子,确认三个`HeroBioComponent`实例拥有自己独立的英雄数据缓冲。
figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/hero-bios.png" alt="Bios")
@ -407,12 +432,12 @@ a(id="qualify-dependency-lookup")
We learned that dependencies can be registered at any level in the component hierarchy.
我们学习了依赖可以在任何组件级别注册依赖
我们学习了依赖可以被注入到任何组件级别
When a component requests a dependency, Angular starts with that component's injector and walks up the injector tree
until it finds the first suitable provider. Angular throws an error if it can't find the dependency during that walk.
当一个组件请求一个依赖Angular以该组件注入器开始然后往上面以及的注入器树走知道它找到第一个合适的供应商。如果Angular不能再这个过程中找不到合适的依赖,它就抛出一个错误。
当一个组件要求一个依赖Angular从该组件自己的注入器开始沿着依赖注入器树往上走直到它找到第一个符合要求的供应商。如果Angular不能在这个过程中找到合适的依赖,它就抛出一个错误。
We *want* this behavior most of the time.
But sometimes we need to limit the search and/or accommodate a missing dependency.
@ -421,81 +446,95 @@ a(id="qualify-dependency-lookup")
在大部分时候,我们*想要*这个行为。
但是有时候,我们需要限制这个(依赖)搜索,并且/或者提供一个缺失的依赖。
单独使用或者一起使用`@Host`和`@Optional`认证装饰器我们能修改Angular的搜索行为。
单独使用或者联合使用`@Host`和`@Optional`认证装饰器我们能修改Angular的搜索行为。
The `@Optional` decorator tells Angular to continue when it can't find the dependency.
Angular sets the injection parameter to `null` instead.
当Angular找不到依赖时`@Optional`装饰器告诉Angular继续执行。Angular设置该注入参数为`null`(取代抛出错误得行为)。
当Angular找不到依赖时`@Optional`装饰器告诉Angular继续执行。Angular设置该注入参数为`null`(取代了默认的抛出错误得行为)。
The `@Host` decorator stops the upward search at the *host component*.
`@Host`装饰器将往上搜索的行为停止到*主组件host component*
`@Host`装饰器将往上搜索的行为停止到*宿主组件*
The host component is typically the component requesting the dependency.
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
### 示范
The `HeroBiosAndContactsComponent` is a revision of the `HeroBiosComponent` that we looked at [above](#hero-bios-component).
该`HeroBiosAndContactsComponent`是[上面](#hero-bios-component)我们看过的`HeroBiosComponent`的修改版。
`HeroBiosAndContactsComponent`是[上面](#hero-bios-component)我们见过的`HeroBiosComponent`的修改版。
+makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','hero-bios-and-contacts','app/hero-bios.component.ts (HeroBiosAndContactsComponent)')
:marked
Focus on the template:
注意它的模板:
聚焦到它的模板:
+makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','template')(format='.')
:marked
We've inserted a `<hero-contact>` element between the `<hero-bio>` tags.
Angular *projects* (*transcludes*) the corresponding `HeroContactComponent` into the `HeroBioComponent` view,
placing it in the `<ng-content>` slot of the `HeroBioComponent` template:
我们在`<hero-bio>`标签里插入了`<hero-contact>`元素。Angular*投放**transcludes*)对应的`HeroContactComponent`到`HeroBioComponent`视图里,将它放到`HeroBioComponent`模板的`<ng-content>`槽里面。
我们在`<hero-bio>`标签里插入了`<hero-contact>`元素。Angular*投放**transcludes*)对应的`HeroContactComponent`到`HeroBioComponent`视图里,
将它放到`HeroBioComponent`模板的`<ng-content>`标签槽里面。
+makeExample('cb-dependency-injection/ts/app/hero-bio.component.ts','template','app/hero-bio.component.ts (template)')(format='.')
:marked
It looks like this, with the heroe's telephone number from `HeroContactComponent` projected above the hero description:
从`HeroContactComponent`来的英雄的电话号码被投放到上面的英雄说明里面,看起来像这样:
从`HeroContactComponent`获得的英雄电话号码,被投放到上面的英雄说明里面,看起来像这样:
figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/hero-bio-and-content.png" alt="bio and contact")
:marked
Here's the `HeroContactComponent` which demonstrates the qualifying decorators that we're talking about in this section:
下面是`HeroContactComponent`,示范了我们在本节一直在讨论的认证装饰器(Qualifying decorators)
下面是`HeroContactComponent`,示范了我们在本节一直在讨论的认证装饰器(@Optional和@Host
+makeExample('cb-dependency-injection/ts/app/hero-contact.component.ts','component','app/hero-contact.component.ts')
:marked
Focus on the constructor parameters
请注意看构造函数的参数。
聚焦到构造函数参数
+makeExample('cb-dependency-injection/ts/app/hero-contact.component.ts','ctor-params','app/hero-contact.component.ts')(format='.')
:marked
The `@Host()` function decorating the `_heroCache` property ensures that
we get a reference to the cache service from the parent `HeroBioComponent`.
Angular throws if the parent lacks that service, even if a component higher in the component tree happens to have that service.
`@Host()`函数装饰`_heroCache`属性,确保我们从其父级`HeroBioComponent`得到一个缓冲服务的引用。如果该父级不存在这个服务Angular则抛错就算组件树里再上级有一个组件拥有这个服务Angular也抛错
`@Host()`函数装饰了`_heroCache`属性,确保我们从其父级`HeroBioComponent`得到一个缓冲服务。如果该父级不存在这个服务Angular则抛错就算组件树里再上级有一个组件拥有这个服务Angular也抛错
A second `@Host()` function decorates the `_loggerService` property.
We know the only `LoggerService` instance in the app is provided at the `AppComponent` level.
The host `HeroBioComponent` doesn't have its own `LoggerService` provider.
另外一个`@Host()`函数装饰`_loggerService`属性,我们知道在应用程序中,只有一个`LoggerService`实例,在`AppComponent`级别提供的。该主持`HeroBioComponent`没有自己的`LoggerService`供应商。
另外一个`@Host()`函数装饰的属性`_loggerService`,我们明白在应用程序中,只有一个`LoggerService`实例,即为在`AppComponent`级别提供的服务。
该主持`HeroBioComponent`没有自己的`LoggerService`供应商。
Angular would throw an error if we hadn't also decorated the property with the `@Optional()` function.
Thanks to `@Optional()`, Angular sets the `loggerService` to null and the rest of the component adapts.
如果我们没有同时使用`@Optional()`来装饰该属性的话Angular会抛错。感谢`@Optional()`Angular将`loggerService`设置为null并继续改组件的执行
如果我们没有同时使用`@Optional()`来装饰该属性的话Angular会抛错。多亏了`@Optional()`Angular把`loggerService`设置为null并继续执行组件而不抛错
.l-sub-section
:marked
We'll come back to the `elementRef` property shortly.
我们将很快回到`elementRef`属性。
:marked
Here's the `HeroBiosAndContactsComponent` in action.
下面是`HeroBiosAndContactsComponent`的执行结果:
figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/hero-bios-and-contacts.png" alt="Bios with contact into")
:marked
@ -503,7 +542,7 @@ figure.image-display
until it finds the logger at the `AppComponent` level. The logger logic kicks in and the hero display updates
with the gratuituous "!!!", indicating that the logger was found.
如果我们注释掉`@Host()`装饰器Angular沿着注入器树就会往上走,直到在`AppComponent`找到该日志服务。这个日志服务的逻辑加入进来,英雄显示更新,表明日志服务已找到。
如果我们注释掉`@Host()`装饰器Angular就会沿着注入器树往上走,直到在`AppComponent`找到该日志服务。日志服务的逻辑加入进来,更新了英雄显示,表明日志服务已找到。
figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/hero-bio-contact-no-host.png" alt="Without @Host")
:marked
@ -512,14 +551,14 @@ figure.image-display
<br>
`EXCEPTION: No provider for LoggerService! (HeroContactComponent -> LoggerService)`
另一方面,如果我们恢复`@Host()`装饰器,注释掉`@Optional`我们的应用程序(运行)失败,因为它在主持组件级别找不到需要的日志服务。
另一方面,如果我们恢复`@Host()`装饰器,注释掉`@Optional`,应用程序(运行)失败,因为它在主持组件级别找不到需要的日志服务。
<br>
`EXCEPTION: No provider for LoggerService! (HeroContactComponent -> LoggerService)`
<a id="component-element"></a>
:marked
## Inject the component's element
## 注入一个组件的元素
## 注入组件的元素
On occasion we might need to access a component's corresponding DOM element.
Although we strive to avoid it, many visual effects and 3rd party tools (such as jQuery)
@ -530,28 +569,32 @@ figure.image-display
To illustrate, we've written a simplified version of the `HighlightDirective` from
the [Attribute Directives](../guide/attribute-directives.html) chapter.
为了示范,我们在[属性指令Attribute Directives](../guide/attribute-directives.html)的`HighlightDirective`的基础上,编写了一个简化版本。
为了示范,我们在[特征指令Attribute Directives](../guide/attribute-directives.html)的`HighlightDirective`的基础上,编写了一个简化版本。
+makeExample('cb-dependency-injection/ts/app/highlight.directive.ts','','app/highlight.directive.ts')
:marked
The directive sets the background to a highlight color when the user mouses over the
DOM element to which it is applied.
当用户鼠标移到DOM元素是,该指令将该元素的背景设置为一个高亮颜色。
当用户鼠标移到DOM元素时,指令将该元素的背景设置为一个高亮颜色。
Angular set the constructor's `el` parameter to the injected `ElementRef` which is
a wrapper around that DOM element.
Its `nativeElement` property exposes the DOM element for the directive to manipulate.
Angular在构造函数的参数`el`设置到注入的`ElementRef`,该`ElementRef`代表了主持hostDOM元素 它的`nativeElement`属性暴露该DOM元素给指令。
Angular把构造函数参数`el`设置为注入的`ElementRef`,该`ElementRef`代表了(宿主的DOM元素 它的`nativeElement`属性暴露该DOM元素给指令。
The sample code applies the directive's `myHighlight` attribute to two `<div>` tags,
first without a value (yielding the default color) and then with an assigned color value.
下面的代码把指令`myHighlight`属性使用到两个`<div>`标签里,一个没有赋值,一个赋值了颜色。
下面的代码把指令`myHighlight`特征使用到两个`<div>`标签里,一个没有赋值,一个赋值了颜色。
+makeExample('cb-dependency-injection/ts/app/app.component.html','highlight','app/app.component.html (highlight)')(format='.')
:marked
The following image shows the effect of mousing over the `<hero-bios-and-contacts>` tag.
下图显示了鼠标移到`<hero-bios-and-contacts>`标签的效果:
figure.image-display
img(src="/resources/images/cookbooks/dependency-injection/highlight.png" alt="Highlighted bios")
:marked
@ -561,12 +604,14 @@ figure.image-display
:marked
## Define dependencies with providers
## 使用供应商来定义依赖
In this section we learn to write providers that deliver dependent services.
在这个部分,我们学习如何编写供应商来提供依赖服务。
### Background
### 背景知识
We get a service from a dependency injector by giving it a ***token***.
我们从一个依赖注入器,通过给他一个***令牌token***来获取一个服务。
@ -612,7 +657,7 @@ figure.image-display
We have to register our _own_ application providers manually,
usually in the `providers` array of the `Component` or `Directive` metadata:
Angular初始化一些他自己建立和需要的注入器附带一些供应商。我们必须要亲自手动注册属于_自己_的供应商通常在`组件`或者`指令`的元数据里面的`供应商`数组(里面注册)。
Angular初始化一些他自己建立和需要的注入器附带一些供应商。我们必须要亲自手动注册属于_自己_的供应商通常在`组件`或者`指令`的元数据里面的`providers`数组(里面注册)。
+makeExample('cb-dependency-injection/ts/app/app.component.ts','providers','app/app.component.ts (providers)')
:marked
### Defining providers
@ -622,7 +667,7 @@ figure.image-display
We mention the class in the `providers` array and we're done.
目前一个简单的类供应商是最典型的例子。
我们在`供应商`的数值里面提到该类就行了。
我们在`providers`的数值里面提到该类就行了。
+makeExample('cb-dependency-injection/ts/app/hero-bios.component.ts','class-provider','app/hero-bios.component.ts (class provider)')(format='.')
:marked
It's that simple because the most common injected service is an instance of a class.
@ -1186,7 +1231,7 @@ a(id='alex')
and add that provider to the `providers` array of the `@Component` metadata for the `AlexComponent`:
我们编写一个[*别名供应商*](#useexisting) &mdash一个拥有`useExisting`定义的`provide`函数 &mdash;
它新建一个*可选的*方法来注入一样的组件实例,并添加这个供应商到`AlexComponent`的`@Component`元数据里的`供应商`数组。
它新建一个*可选的*方法来注入一样的组件实例,并添加这个供应商到`AlexComponent`的`@Component`元数据里的`providers`数组。
a(id="alex-providers")
+makeExample('cb-dependency-injection/ts/app/parent-finder.component.ts','alex-providers','parent-finder.component.ts (AlexComponent providers)')(format='.')
:marked
@ -1229,7 +1274,7 @@ a(id="parent-tree")
*Barry*'s `providers` array looks just like [*Alex*'s](#alex-providers).
If we're going to keep writing [*alias providers*](#useexisting) like this we should create a [helper function](#provideparent).
*Barry*的`供应商`数组看起来像[*Alex*的]#alex-providers).
*Barry*的`providers`数组看起来像[*Alex*的]#alex-providers).
如果我们一直要像这样编写[*别名供应商*](#useexisting)的话,我们应该建立一个[帮助函数](#provideparent)。
For now, focus on *Barry*'s constructor:
@ -1411,7 +1456,7 @@ a(id="forwardref")
appear *above* the class definition.
当一个类使用*一个自己的引用*的时候,我们面临同样的窘境,就像`AlexComponent`的`provdiers`数组里的困境一样。
该`供应商`数组是一个`@Component`装饰器函数的一个属性,它必须要在类定义*之前*出现。
该`providers`数组是一个`@Component`装饰器函数的一个属性,它必须要在类定义*之前*出现。
Again we break the circularity with `forwardRef`: