(docs) devguide dependency injection: correct provider terminology in chapter and glossary

This commit is contained in:
Ward Bell 2015-10-27 12:57:50 -07:00 committed by Naomi Black
parent 963f67ea07
commit 359904d0d0
2 changed files with 83 additions and 61 deletions

View File

@ -375,27 +375,31 @@ include ../../../../_includes/_util-fns
What matters is that the injector knows what to do when something asks for a `HeroService`. What matters is that the injector knows what to do when something asks for a `HeroService`.
### Provider mappings ### The Provider Class
When we registered the `HeroService` with the injector, we were actually registering
a mapping between the `HeroService` *token* and a provider that can create a `HeroService`.
When we wrote ... When we wrote ...
``` ```
import {bootstrap} from 'angular2/angular2'; [HeroService];
bootstrap(AppComponent, [HeroService]);
``` ```
... Angular translated that statement into a mapping instruction involving the Angular `provide` method we used a short-hand expression for provider registration.
Angular expanded that short-hand into a call to the Angular `provide` method
``` ```
import {bootstrap, provide} from 'angular2/angular2'; [provide(HeroService, {useClass:HeroService})];
bootstrap(AppComponent, [
provide(HeroService, {useClass:HeroService})
]);
``` ```
Of course we prefer the shorthand syntax - `[HeroService]` - when the provider and the token are the same class. and the `provide` method in turn creates a new instance of the Angular
[Provider class](http://localhost:3000/docs/ts/latest/api/core/Provider-class.html):
```
[new Provider(HeroService, {useClass:HeroService})]
```
This provider instance associates a `HeroService` *token*
with code that can create an *instance* of a `HeroService`.
The first parameter is the [token](#token) that serves as the key for both locating a dependency value
and registering the provider.
Isn't that always the case? Not always. The second parameter is a provider definition object
which we think of as a "recipe" for creating the dependency value.
There are many ways to create dependency values ... and many ways to write a recipe.
### Alternative Class Providers ### Alternative Class Providers
@ -424,7 +428,7 @@ include ../../../../_includes/_util-fns
return [ provide(HeroService, {useValue: emptyHeroService}) ]; return [ provide(HeroService, {useValue: emptyHeroService}) ];
}); });
``` ```
Notice that we mapped with `useValue` instead of `useClass`. Notice we defined the recipe with `useValue` instead of `useClass`.
### Factory Providers ### Factory Providers
@ -472,7 +476,7 @@ include ../../../../_includes/_util-fns
a fact we can't know until runtime. a fact we can't know until runtime.
:markdown :markdown
We use dependency injection everywhere so of course the factory function depends on We use dependency injection everywhere so of course the factory function depends on
two injected services: `Logger` and `UserService`. two injected services: `Logger` and `UserService`.
We declare those requirements in our provider definition object: We declare those requirements in our provider definition object:
``` ```
let heroServiceDefinition = { let heroServiceDefinition = {
@ -484,15 +488,17 @@ include ../../../../_includes/_util-fns
:markdown :markdown
The `useFactory` field tells Angular that the provider is a factory function and that its implementation is the `heroServiceFactory`. The `useFactory` field tells Angular that the provider is a factory function and that its implementation is the `heroServiceFactory`.
The `deps` property is an array of provider mapping tokens. The `deps` property is an array of [provider tokens](#token).
The `Logger` and `UserService` classes serve as tokens for their own class provider mappings. The `Logger` and `UserService` classes serve as tokens for their own class providers.
:markdown :markdown
Finally, we create the mapping and adjust the bootstrapping to include that mapping in its provider configuration. Finally, we create the provider and adjust the bootstrapping to include that provider
among its provider registrations.
``` ```
let heroServiceMapping = provide(HeroService, heroServiceDefinition); let heroServiceProvider = provide(HeroService, heroServiceDefinition);
bootstrap(AppComponent, [heroServiceMapping, Logger, UserService]); bootstrap(AppComponent, [heroServiceProvider, Logger, UserService]);
``` ```
### String tokens ### String tokens
Sometimes we have an object dependency rather than a class dependency. Sometimes we have an object dependency rather than a class dependency.
@ -507,25 +513,31 @@ include ../../../../_includes/_util-fns
``` ```
We'd like to make this `config` object available for injection. We'd like to make this `config` object available for injection.
We know we can register an object with a "Value Provider". But what do we use for the token? We know we can register an object with a "Value Provider". But what do we use for the token?
<a id="token"></a>
Until now, we've always asked the class to play the token role
whether we wrote a provider with a class, value, or factory recipe.
This time we don't have a class to serve as a token. There is no `Config` class.
Until now, we've always had a class to use as the token for mapping. Fortunately, the token can be a string, a class type, or an
The `HeroService` class was our token, whether we mapped it to another class, a value, or a factory provider. [OpaqueToken](http://localhost:3000/docs/ts/latest/api/core/OpaqueToken-class.html).
This time we don't have a class. There is no `Config` class. Internally, the `Provider` turns the string and class parameter into an `OpaqueToken`;
the injector locates dependency values and providers by this token.
Fortunately, a token can be either a JavaScript type (e.g. the class function) **or a string**. We'll map our configuration object
to a string! We'll register our configuration object with a string-based token!
``` ```
bootstrap(AppComponent, [ bootstrap(AppComponent, [
// other mappings // // other providers //
provide('App.config', {useValue:config}) provide('App.config', {useValue:config})
]); ]);
``` ```
Now let's update the `HeroesComponent` constructor so it can display the configured title.
Let's apply what we've learned and update the `HeroesComponent` constructor so it can display the configured title.
Right now the constructor signature is Right now the constructor signature is
``` ```
constructor(heroService: HeroService) constructor(heroService: HeroService)
``` ```
We might think we can write: We might think we can add the `config` dependency by writing:
``` ```
// FAIL! // FAIL!
constructor(heroService: HeroService, config: config) constructor(heroService: HeroService, config: config)

View File

@ -143,35 +143,49 @@
Angular developers prefer to build applications by defining many simple parts Angular developers prefer to build applications by defining many simple parts
that each do one thing well and then wire them together at runtime. that each do one thing well and then wire them together at runtime.
These parts often rely on one another. An Angular [Component](#component) These parts often rely on other parts. An Angular [Component](#component)
part might rely on a service part to get data or perform a calculation. When a part might rely on a service part to get data or perform a calculation. When a
part "A" relies on another part "B", we say that "A" depends on "B" and part "A" relies on another part "B", we say that "A" depends on "B" and
that "B" is a dependency of "A". that "B" is a dependency of "A".
We developers have a choice. We can teach "A" to find or create "B" all by itself. We can ask a "Dependency Injection System" to create "A"
Or we can ask a "Dependency Injection System"" to find or create "B" and deliver for us and handle all the dependencies.
it to part "A" when "A" needs it. If "A" needs "B" and "B" needs "C", the system resolves that chain of dependencies
and returns a fully prepared instance of "A".
These choices and their relative merits are the subject of Angular provides and relies upon its own sophisticated
much discussion under the rubric. "Dependency Injection". [Dependency Injection](./dependency-injection.html) system
We can read about that in many places including
[on the web here](https://en.wikipedia.org/wiki/Dependency_injection)
Angular strongly favors the Dependency Injection approach
and relies on its own sophisticated
[Dependency Injection System](./dependency-injection.html) system
to assemble and run applications by "injecting" application parts to assemble and run applications by "injecting" application parts
where and when needed. into other application parts where and when needed.
These parts (often called "dependencies") are created by [providers](#provider) At the core is an [`Injector`](#injector) that returns dependency values on request.
that we register with an [injector](#injector) at the appropriate time. The expression `injector.get(token)` returns the value associated with the given token.
Quite often the best time to register a provider is when A token is an Angular type (`OpaqueToken`). We rarely deal with tokens directly; most
we [bootstrap](#bootstrap) the application methods accept a class name (`Foo`) or a string ("foo") and Angular converts it
but there are other opportunities to register as well. to a token. When we write `injector.get(Foo)`, the injector returns
the value associated with the token for the `Foo` class, typically an instance of `Foo` itself.
Learn more by reading the [Dependency Injection System](./dependency-injection.html) chapter. Angular makes similar requests internally during many of its operations
as when it creates a [`Component`](#AppComponent) for display.
The `Injector` maintains an internal map of tokens to dependency values.
If the `Injector` can't find a value for a given token, it creates
a new value using a `Provider` for that token.
A [Provider](#provider) is a recipe for
creating new instances of a dependency value associated with a particular token.
An injector can only create a value for a given token if it has
a `Provider` for that token in its internal provider registry.
Registering providers is a critical preparatory step.
Angular registers some of its own providers with every injector.
We can register our own providers. Quite often the best time to register a `Provider`
is when we [bootstrap](#bootstrap) the application.
There are other opportunities to register as well.
Learn more in the [Dependency Injection](./dependency-injection.html) chapter.
:markdown :markdown
## Directive ## Directive
.l-sub-section .l-sub-section
@ -318,18 +332,14 @@
## Provider ## Provider
.l-sub-section .l-sub-section
:markdown :markdown
Angular relies on [dependency injection](#dependency-injection) to create and deliver A Provider creates a new instance of a dependency for the Dependency Injection system.
pieces of functionality to the application parts that need them. Those pieces are It relates a lookup token to code - sometimes called a "recipe" - that can create a dependency value.
often called "dependencies".
Angular can't find or create these dependencies by itself. Something has to "provide" them. For example, `new Provider(Foo, {useClass: Foo})` creates a `Provider`
That something is called a "Provider". A provider can be almost anything that can produce that relates the `Foo` token to a function that creates a new instance of the `Foo` class.
the dependency although it is most often a class that we register with the
[dependency injector](injector). There are other ways to create tokens and recipes.
See [Dependency Injection](#dependency-injection) chapter to learn more.
We typically register our application providers when we [bootstrap](#bootstrap) the application
but there are other opportunities to do that as well.
See the [Dependency Injection[(./dependency-injection.html)] chapter for details.
.l-main-section .l-main-section
:markdown :markdown