Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit fcfa6eb

Browse files
docs(guide/di): clarify what can be injected into what
Also do some general housekeeping and tidying of the page. Closes #6999
1 parent cf8ed01 commit fcfa6eb

File tree

1 file changed

+137
-84
lines changed

1 file changed

+137
-84
lines changed

docs/content/guide/di.ngdoc

Lines changed: 137 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,29 @@
44

55
# Dependency Injection
66

7-
Dependency Injection (DI) is a software design pattern that deals with how code gets hold of its
8-
dependencies.
7+
Dependency Injection (DI) is a software design pattern that deals with how components get hold of
8+
their dependencies.
99

10-
The Angular injector subsystem is in charge of service instantiation, resolution
11-
of dependencies, and provision of dependencies to components as requested.
10+
The Angular injector subsystem is in charge of creating components, resolving their dependencies,
11+
and providing them to other components as requested.
1212

1313
For in-depth discussion about DI, see
1414
[Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) at Wikipedia,
1515
[Inversion of Control](http://martinfowler.com/articles/injection.html) by Martin Fowler,
1616
or read about DI in your favorite software design pattern book.
1717

18-
## DI in a nutshell
19-
20-
There are only three ways an object or a function can get a hold of its dependencies:
18+
## DI in a Nutshell
2119

22-
1. The dependency can be created, typically using the `new` operator.
23-
2. The dependency can be looked up by referring to a global variable.
24-
3. The dependency can be passed in to where it is needed.
20+
There are only three ways a component (object or function) can get a hold of its dependencies:
2521

22+
1. The component can create the dependency, typically using the `new` operator.
23+
2. The component can look up the dependency, by referring to a global variable.
24+
3. The component can have the dependency passed to it where it is needed.
2625

2726
The first two options of creating or looking up dependencies are not optimal because they hard
28-
code the dependency. This makes it difficult, if not impossible, to modify the dependencies.
29-
This is especially problematic in tests, where it is often desirable to provide mock dependencies
30-
for test isolation.
27+
code the dependency to the component. This makes it difficult, if not impossible, to modify the
28+
dependencies. This is especially problematic in tests, where it is often desirable to provide mock
29+
dependencies for test isolation.
3130

3231
The third option is the most viable, since it removes the responsibility of locating the
3332
dependency from the component. The dependency is simply handed to the component.
@@ -42,83 +41,99 @@ SomeClass.prototype.doSomething = function(name) {
4241
}
4342
```
4443

45-
In the above example `SomeClass` is not concerned with locating the `greeter` dependency, it
46-
is simply handed the `greeter` at runtime.
44+
In the above example `SomeClass` is not concerned with creating or locating the `greeter`
45+
dependency, it is simply handed the `greeter` when it is instantiated.
4746

4847
This is desirable, but it puts the responsibility of getting hold of the dependency on the
4948
code that constructs `SomeClass`.
5049

5150
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
5251

5352
To manage the responsibility of dependency creation, each Angular application has an {@link
54-
angular.injector injector}. The injector is a service locator that is responsible for
53+
angular.injector injector}. The injector is a
54+
[service locator](http://en.wikipedia.org/wiki/Service_locator_pattern) that is responsible for
5555
construction and lookup of dependencies.
5656

5757
Here is an example of using the injector service:
5858

5959
```js
6060
// Provide the wiring information in a module
61-
angular.module('myModule', []).
62-
63-
// Teach the injector how to build a 'greeter'
64-
// Notice that greeter itself is dependent on '$window'
65-
factory('greeter', function($window) {
66-
// This is a factory function, and is responsible for
67-
// creating the 'greet' service.
68-
return {
69-
greet: function(text) {
70-
$window.alert(text);
71-
}
72-
};
73-
});
74-
75-
// New injector is created from the module.
76-
// (This is usually done automatically by angular bootstrap)
77-
var injector = angular.injector(['myModule', 'ng']);
61+
var myModule = angular.module('myModule', []);
62+
```
63+
64+
Teach the injector how to build a `greeter` service. Notice that `greeter` is dependent on the
65+
`$window` service. The `greeter` service is an object that contains a `greet` method.
66+
67+
```js
68+
myModule.factory('greeter', function($window) {
69+
return {
70+
greet: function(text) {
71+
$window.alert(text);
72+
}
73+
};
74+
});
75+
```
76+
77+
Create a new injector that can provide components defined in our `myModule` module and request our
78+
`greeter` service from the injector. (This is usually done automatically by angular bootstrap).
7879

79-
// Request any dependency from the injector
80+
```js
81+
var injector = angular.injector(['myModule', 'ng']);
8082
var greeter = injector.get('greeter');
8183
```
8284

8385
Asking for dependencies solves the issue of hard coding, but it also means that the injector needs
84-
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 turn the
85-
dependency lookup responsibility to the injector by declaring the dependencies as in this example:
86+
to be passed throughout the application. Passing the injector breaks the
87+
[Law of Demeter](http://en.wikipedia.org/wiki/Law_of_Demeter). To remedy this, we use a declarative
88+
notation in our HTML templates, to hand the responsibility of creating components over to the
89+
injector, as in this example:
8690

8791
```html
88-
<!-- Given this HTML -->
8992
<div ng-controller="MyController">
9093
<button ng-click="sayHello()">Hello</button>
9194
</div>
9295
```
9396

9497
```js
95-
// And this controller definition
9698
function MyController($scope, greeter) {
9799
$scope.sayHello = function() {
98100
greeter.greet('Hello World');
99101
};
100102
}
103+
```
101104

102-
// The 'ng-controller' directive does this behind the scenes
105+
When Angular compiles the HTML, it processes the `ng-controller` directive, which in turn
106+
asks the injector to create an instance of the controller and its dependencies.
107+
108+
```js
103109
injector.instantiate(MyController);
104110
```
105111

106-
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
107-
dependencies of `MyController` without the controller ever knowing about the injector. This is
108-
the best outcome. The application code simply asks for the dependencies it needs, without having to
109-
deal with the injector. This setup does not break the Law of Demeter.
112+
This is all done behinds the scenes. Notice that by having the `ng-controller` ask the injector to
113+
instantiate the class, it can satisfy all of the dependencies of `MyController` without the
114+
controller ever knowing about the injector.
115+
116+
This is the best outcome. The application code simply declares the dependencies it needs, without
117+
having to deal with the injector. This setup does not break the Law of Demeter.
118+
110119

111120
## Dependency Annotation
112121

113-
How does the injector know what service needs to be injected?
122+
**How does the injector know what components need to be injected?**
114123

115124
The application developer needs to provide annotation information that the injector uses in order
116125
to resolve the dependencies. Throughout Angular, certain API functions are invoked using the
117126
injector, as per the API documentation. The injector needs to know what services to inject into
118-
the function. Below are three equivalent ways of annotating your code with service name
119-
information. These can be used interchangeably as you see fit and are equivalent.
127+
the function. There are three equivalent ways of annotating your code with service name
128+
information:
120129

121-
### Inferring Dependencies
130+
- Implicitly from the function parameter names
131+
- Using the `$inject` property annotation
132+
- Using the inline array annotation
133+
134+
These can be used interchangeably as you see fit and are equivalent.
135+
136+
### Implicit Dependencies
122137

123138
The simplest way to get hold of the dependencies, is to assume that the function parameter names
124139
are the names of the dependencies.
@@ -134,11 +149,12 @@ function declaration and extracting the parameter names. In the above example `$
134149
`greeter` are two services which need to be injected into the function.
135150

136151
While straightforward, this method will not work with JavaScript minifiers/obfuscators as they
137-
rename the method parameter names. This makes this way of annotating only useful for [pretotyping](http://www.pretotyping.org/), and demo applications.
152+
rename the method parameter names. This makes this way of annotating only useful for
153+
[pretotyping](http://www.pretotyping.org/), and demo applications.
138154

139-
### `$inject` Annotation
155+
### `$inject` Property Annotation
140156

141-
To allow the minifers to rename the function parameters and still be able to inject right services
157+
To allow the minifers to rename the function parameters and still be able to inject right services,
142158
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
143159
of service names to inject.
144160

@@ -149,18 +165,18 @@ var MyController = function(renamed$scope, renamedGreeter) {
149165
MyController['$inject'] = ['$scope', 'greeter'];
150166
```
151167

152-
In this scenario the ordering of the values in the '$inject' array must match the ordering of the arguments to inject.
153-
Using above code snippet as an example, '$scope' will be injected into 'renamed$scope' and 'greeter' into 'renamedGreeter'.
154-
Care must be taken that the `$inject` annotation is kept in sync with the actual arguments in the
155-
function declaration.
168+
In this scenario the ordering of the values in the `$inject` array must match the ordering of the
169+
arguments to inject. Using above code snippet as an example, `$scope` will be injected into
170+
`renamed$scope` and `greeter` into `renamedGreeter`. Care must be taken that the `$inject`
171+
annotation is kept in sync with the actual arguments in the function declaration.
156172

157173
This method of annotation is useful for controller declarations since it assigns the annotation
158174
information with the function.
159175

160-
### Inline Annotation
176+
### Inline Array Annotation
161177

162178
Sometimes using the `$inject` annotation style is not convenient such as when annotating
163-
directives.
179+
directives or services defined inline by a factory function.
164180

165181
For example:
166182

@@ -190,53 +206,90 @@ someModule.factory('greeter', ['$window', function(renamed$window) {
190206
}]);
191207
```
192208

209+
Here, instead of simply providing the factory function, we pass an array, whose elements consist of
210+
a list of strings (the names of the depenendencies) followed by the function itself.
211+
193212
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
194213
where injection is supported.
195214

196-
## Where can I use DI?
215+
## Where Can I Use DI?
197216

198-
DI is pervasive throughout Angular. You can use it in controllers, services, directives, filters,
199-
animations, and `run` and `config` blocks.
217+
DI is pervasive throughout Angular. You can use it when defining components or when providing `run`
218+
and `config` blocks for a module.
200219

201-
### DI in controllers
202-
203-
Controllers are classes which are responsible for application behavior. The recommended way of
204-
declaring controllers is using the array notation:
220+
- Components such as services, directives, filters and animations are defined by an injectable factory
221+
method or constructor function. These components can be injected with "service" components as
222+
dependencies.
205223

206-
```js
207-
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
208-
...
209-
$scope.aMethod = function() {
210-
...
211-
}
212-
...
213-
}]);
214-
```
224+
- The `run` and `config` methods accept a function, which can also be injected with "service"
225+
components as dependencies.
215226

216-
This avoids the creation of global functions for controllers and also protects against minification.
227+
- Controllers are defined by an constructor function, which can be injected with any of the "service"
228+
components as dependencies, but they can also be provided with special dependencies. See "DI in
229+
Controllers" below.
217230

218231

219-
### Factory methods
232+
### Factory Methods
220233

221234
Factory methods are responsible for creating most objects in Angular. Examples are directives,
222235
services, and filters. The factory methods are registered with the module, and the recommended way
223236
of declaring factories is:
224237

225238
```js
226-
angular.module('myModule', []).
227-
config(['depProvider', function(depProvider){
239+
angular.module('myModule', [])
240+
.factory('serviceId', ['depService', function(depService) {
228241
...
229-
}]).
230-
factory('serviceId', ['depService', function(depService) {
242+
}])
243+
.directive('directiveName', ['depService', function(depService) {
231244
...
232-
}]).
233-
directive('directiveName', ['depService', function(depService) {
245+
}])
246+
.filter('filterName', ['depService', function(depService) {
234247
...
235-
}]).
236-
filter('filterName', ['depService', function(depService) {
248+
}]);
249+
```
250+
251+
### Module Methods
252+
253+
We can specify functions to run at configuration and run time for a module by calling the `run` and
254+
`config` methods. These functions are injectable with dependencies just like the factory functions
255+
above.
256+
257+
```js
258+
angular.module('myModule', [])
259+
.config(['depProvider', function(depProvider){
237260
...
238-
}]).
239-
run(['depService', function(depService) {
261+
}])
262+
.run(['depService', function(depService) {
240263
...
241264
}]);
242265
```
266+
267+
### Controllers
268+
269+
Controllers are "classes" or "constructor functions" that are responsible for providing the
270+
application behavior that supports the declarative markup in the template. The recommended way of
271+
declaring Controllers is using the array notation:
272+
273+
```js
274+
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
275+
...
276+
$scope.aMethod = function() {
277+
...
278+
}
279+
...
280+
}]);
281+
```
282+
283+
This avoids the creation of global functions for controllers and also protects against minification.
284+
285+
Controllers are special in that, unlike services, there can be many instances of them in the
286+
application. For example, there would be one instance of a for every instance of the `ng-controller`
287+
directive in the template.
288+
289+
Moreover, additional dependencies are made available to Controllers:
290+
291+
* {@link scope `$scope`}: Controllers are always associated with a point in the DOM and so are provided with
292+
access to the {@link scope scope} at that point. Other components, such as servies only have access to the
293+
singleton {@link $rootScope} service.
294+
* {@link $route} resolves: If a controller is instantiated as part of a route, then any values that
295+
are resolved as part of the route are made available for injection into the controller.

0 commit comments

Comments
 (0)