forked from angular/angular.js
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdi.ngdoc
336 lines (249 loc) · 11.6 KB
/
di.ngdoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
@ngdoc overview
@name Dependency Injection
@sortOrder 250
@description
# Dependency Injection
Dependency Injection (DI) is a software design pattern that deals with how components get hold of
their dependencies.
The Angular injector subsystem is in charge of creating components, resolving their dependencies,
and providing them to other components as requested.
## Using Dependency Injection
DI is pervasive throughout Angular. You can use it when defining components or when providing `run`
and `config` blocks for a module.
- Components such as services, directives, filters, and animations are defined by an injectable
factory method or constructor function. These components can be injected with "service" and "value"
components as dependencies.
- Controllers are defined by a constructor function, which can be injected with any of the "service"
and "value" components as dependencies, but they can also be provided with special dependencies. See
{@link di#controllers Controllers} below for a list of these special dependencies.
- The `run` method accepts a function, which can be injected with "service", "value" and "constant"
components as dependencies. Note that you cannot inject "providers" into `run` blocks.
- The `config` method accepts a function, which can be injected with "provider" and "constant"
components as dependencies. Note that you cannot inject "service" or "value" components into
configuration.
See {@link module#module-loading-dependencies Modules} for more details about `run` and `config`
blocks.
### Factory Methods
The way you define a directive, service, or filter is with a factory function.
The factory methods are registered with modules. The recommended way of declaring factories is:
```js
angular.module('myModule', [])
.factory('serviceId', ['depService', function(depService) {
// ...
}])
.directive('directiveName', ['depService', function(depService) {
// ...
}])
.filter('filterName', ['depService', function(depService) {
// ...
}]);
```
### Module Methods
We can specify functions to run at configuration and run time for a module by calling the `config`
and `run` methods. These functions are injectable with dependencies just like the factory functions
above.
```js
angular.module('myModule', [])
.config(['depProvider', function(depProvider) {
// ...
}])
.run(['depService', function(depService) {
// ...
}]);
```
### Controllers
Controllers are "classes" or "constructor functions" that are responsible for providing the
application behavior that supports the declarative markup in the template. The recommended way of
declaring Controllers is using the array notation:
```js
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
...
}
...
}]);
```
Unlike services, there can be many instances of the same type of controller in an application.
Moreover, additional dependencies are made available to Controllers:
* {@link scope `$scope`}: Controllers are associated with an element in the DOM and so are
provided with access to the {@link scope scope}. Other components (like services) only have
access to the {@link $rootScope `$rootScope`} service.
* {@link api/ngRoute/provider/$routeProvider#when resolves}: If a controller is instantiated as part of a route, then any values that
are resolved as part of the route are made available for injection into the controller.
## Dependency Annotation
Angular invokes certain functions (like service factories and controllers) via the injector.
You need to annotate these functions so that the injector knows what services to inject into
the function. There are three ways of annotating your code with service name information:
- Using the inline array annotation (preferred)
- Using the `$inject` property annotation
- Implicitly from the function parameter names (has caveats)
### Inline Array Annotation
This is the preferred way to annotate application components. This is how the examples in the
documentation are written.
For example:
```js
someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
// ...
}]);
```
Here we pass an array whose elements consist of a list of strings (the names of the dependencies)
followed by the function itself.
When using this type of annotation, take care to keep the annotation array in sync with the
parameters in the function declaration.
### `$inject` Property Annotation
To allow the minifiers to rename the function parameters and still be able to inject the right services,
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
of service names to inject.
```js
var MyController = function($scope, greeter) {
// ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);
```
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
parameters in `MyController`.
Just like with the array annotation, you'll need to take care to keep the `$inject` in sync with
the parameters in the function declaration.
### Implicit Annotation
<div class="alert alert-danger">
**Careful:** If you plan to [minify](http://en.wikipedia.org/wiki/Minification_(programming))
your code, your service names will get renamed and break your app.
</div>
The simplest way to get hold of the dependencies is to assume that the function parameter names
are the names of the dependencies.
```js
someModule.controller('MyController', function($scope, greeter) {
// ...
});
```
Given a function the injector can infer the names of the services to inject by examining the
function declaration and extracting the parameter names. In the above example `$scope`, and
`greeter` are two services which need to be injected into the function.
One advantage of this approach is that there's no array of names to keep in sync with the
function parameters. You can also freely reorder dependencies.
However this method will not work with JavaScript minifiers/obfuscators because of how they
rename parameters.
Tools like [ng-annotate](https://github.com/olov/ng-annotate) let you use implicit dependency
annotations in your app and automatically add inline array annotations prior to minifying.
If you decide to take this approach, you probably want to use `ng-strict-di`.
Because of these caveats, we recommend avoiding this style of annotation.
## Using Strict Dependency Injection
You can add an `ng-strict-di` directive on the same element as `ng-app` to opt into strict DI mode:
```html
<!doctype html>
<html ng-app="myApp" ng-strict-di>
<body>
I can add: {{ 1 + 2 }}.
<script src="angular.js"></script>
</body>
</html>
```
Strict mode throws an error whenever a service tries to use implicit annotations.
Consider this module, which includes a `willBreak` service that uses implicit DI:
```js
angular.module('myApp', [])
.factory('willBreak', function($rootScope) {
// $rootScope is implicitly injected
})
.run(['willBreak', function(willBreak) {
// Angular will throw when this runs
}]);
```
When the `willBreak` service is instantiated, Angular will throw an error because of strict mode.
This is useful when using a tool like [ng-annotate](https://github.com/olov/ng-annotate) to
ensure that all of your application components have annotations.
If you're using manual bootstrapping, you can also use strict DI by providing `strictDi: true` in
the optional config argument:
```js
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
```
## Why Dependency Injection?
This section motivates and explains Angular's use of DI. For how to use DI, see above.
For in-depth discussion about DI, see
[Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) at Wikipedia,
[Inversion of Control](http://martinfowler.com/articles/injection.html) by Martin Fowler,
or read about DI in your favorite software design pattern book.
There are only three ways a component (object or function) can get a hold of its dependencies:
1. The component can create the dependency, typically using the `new` operator.
2. The component can look up the dependency, by referring to a global variable.
3. The component can have the dependency passed to it where it is needed.
The first two options of creating or looking up dependencies are not optimal because they hard
code the dependency to the component. This makes it difficult, if not impossible, to modify the
dependencies. This is especially problematic in tests, where it is often desirable to provide mock
dependencies for test isolation.
The third option is the most viable, since it removes the responsibility of locating the
dependency from the component. The dependency is simply handed to the component.
```js
function SomeClass(greeter) {
this.greeter = greeter;
}
SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}
```
In the above example `SomeClass` is not concerned with creating or locating the `greeter`
dependency, it is simply handed the `greeter` when it is instantiated.
This is desirable, but it puts the responsibility of getting hold of the dependency on the
code that constructs `SomeClass`.
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
To manage the responsibility of dependency creation, each Angular application has an {@link
angular.injector injector}. The injector is a
[service locator](http://en.wikipedia.org/wiki/Service_locator_pattern) that is responsible for
construction and lookup of dependencies.
Here is an example of using the injector service:
```js
// Provide the wiring information in a module
var myModule = angular.module('myModule', []);
```
Teach the injector how to build a `greeter` service. Notice that `greeter` is dependent on the
`$window` service. The `greeter` service is an object that contains a `greet` method.
```js
myModule.factory('greeter', function($window) {
return {
greet: function(text) {
$window.alert(text);
}
};
});
```
Create a new injector that can provide components defined in our `myModule` module and request our
`greeter` service from the injector. (This is usually done automatically by angular bootstrap).
```js
var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');
```
Asking for dependencies solves the issue of hard coding, but it also means that the injector needs
to be passed throughout the application. Passing the injector breaks the
[Law of Demeter](http://en.wikipedia.org/wiki/Law_of_Demeter). To remedy this, we use a declarative
notation in our HTML templates, to hand the responsibility of creating components over to the
injector, as in this example:
```html
<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
```
```js
function MyController($scope, greeter) {
$scope.sayHello = function() {
greeter.greet('Hello World');
};
}
```
When Angular compiles the HTML, it processes the `ng-controller` directive, which in turn
asks the injector to create an instance of the controller and its dependencies.
```js
injector.instantiate(MyController);
```
This is all done behind the scenes. Notice that by having the `ng-controller` ask the injector to
instantiate the class, it can satisfy all of the dependencies of `MyController` without the
controller ever knowing about the injector.
This is the best outcome. The application code simply declares the dependencies it needs, without
having to deal with the injector. This setup does not break the Law of Demeter.
<div class="alert alert-info">
**Note:** Angular uses
[**constructor injection**](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/).
</div>