di review - half.
This commit is contained in:
parent
33292b942c
commit
6a4799fe2d
|
@ -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`代表了(主持host)DOM元素, 它的`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`函数 —
|
||||
它新建一个*可选的*方法来注入一样的组件实例,并添加这个供应商到`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`:
|
||||
|
||||
|
|
Loading…
Reference in New Issue