mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-05-13 01:13:08 +00:00
docs(dependency injecton): rewrite
This commit is contained in:
parent
581f93ae56
commit
2e90cdc3d4
12 changed files with 244 additions and 290 deletions
|
|
@ -1,32 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: About Dependency Injection (DI)
|
|
||||||
@description
|
|
||||||
|
|
||||||
Dependency Injection (DI) is an object-oriented software design pattern that supports the
|
|
||||||
decoupling and dependency management of application components.
|
|
||||||
|
|
||||||
The idea behind DI is to decouple each component from all of the other components that it depends
|
|
||||||
on to do its particular job. The way this is done in DI is by moving the responsibility for
|
|
||||||
managing dependencies out of each individual component and into a provider component. The provider
|
|
||||||
(or injector) component manages the life cycles and dependencies for all of the other components in
|
|
||||||
an application.
|
|
||||||
|
|
||||||
Angular has a built-in dependency management subsystem that helps to make your applications easier
|
|
||||||
to develop, understand, and test.
|
|
||||||
|
|
||||||
For more information on DI in general, see {@link http://en.wikipedia.org/wiki/Dependency_injection
|
|
||||||
Dependency Injection} at Wikipedia, and {@link http://martinfowler.com/articles/injection.html
|
|
||||||
Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
|
|
||||||
book.
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
|
||||||
|
|
||||||
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
|
|
||||||
* {@link dev_guide.services Angular Services}
|
|
||||||
|
|
||||||
|
|
||||||
## Related API
|
|
||||||
|
|
||||||
* {@link api/angular.module.ng Service API}
|
|
||||||
* {@link api/angular.injector Angular Injector API}
|
|
||||||
|
|
@ -1,193 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: DI: Understanding DI in Angular
|
|
||||||
@description
|
|
||||||
|
|
||||||
|
|
||||||
While DI is widely used in statically typed languages such as Java or C++, it has not been widely
|
|
||||||
used in JavaScript. Angular brings the benefits of DI into JavaScript apps.
|
|
||||||
|
|
||||||
In angular, DI is implemented as a subsystem that manages dependencies between services,
|
|
||||||
controllers, widgets, and filters.
|
|
||||||
|
|
||||||
Services are objects that handle common tasks in web applications. Angular provides several {@link
|
|
||||||
api/angular.module.ng built-in services}, and you can create your
|
|
||||||
{@link dev_guide.services.creating_services own custom services}.
|
|
||||||
|
|
||||||
The main job of angular's DI subsystem is to provide services to angular components that depend on
|
|
||||||
them. The way the DI subsystem provides services is as follows: all services are registered with
|
|
||||||
angular's {@link api/angular.module.ng service API}, and all components that depend on services
|
|
||||||
define those dependencies as a property (`$inject`). With this information, the DI subsystem
|
|
||||||
manages the creation of service objects and the provision of those objects to the components that
|
|
||||||
need them, at the time they need them. The following illustration steps through the sequence of
|
|
||||||
events:
|
|
||||||
|
|
||||||
<img src="img/guide/di_sequence_final.png">
|
|
||||||
|
|
||||||
In the illustration above, the dependency injection sequence proceeds as follows:
|
|
||||||
|
|
||||||
1. Module "phonecat" is created and all the service providers are registered with this module.
|
|
||||||
(the "ng" module is created by Angular behind the scenes as well)
|
|
||||||
2. `ngApp` triggers bootstrap sequence on given element, during which angular creates injector,
|
|
||||||
loads "phonecat" and "ng" modules and compiles the template.
|
|
||||||
3. The `ngController` directive implicitly creates a new child scope and instantiates
|
|
||||||
`PhoneListCtrl` controller.
|
|
||||||
4. Injector identifies the `$http` service as `PhoneListCtrl` controller's only dependency.
|
|
||||||
5. Injector checks its instances cache whether the `$http` service has already been instantiated.
|
|
||||||
If not uses the provider from the available modules to construct it.
|
|
||||||
6. Injector provides the instance of `$http` service to the `PhoneListCtrl` controller constructor.
|
|
||||||
|
|
||||||
|
|
||||||
## How Scope Relates to DI
|
|
||||||
|
|
||||||
The root scope of the application is just a service that is available for injection to any part of
|
|
||||||
the application under the service name "$rootScope".
|
|
||||||
|
|
||||||
|
|
||||||
## Inferring dependencies from the signature of the factory function or constructor
|
|
||||||
|
|
||||||
**EXPERIMENTAL FEATURE**: This is an experimental feature. See the important note at the end of
|
|
||||||
this section for drawbacks.
|
|
||||||
|
|
||||||
We resort to `$inject` and our own annotation because there is no way in JavaScript to get a list
|
|
||||||
of arguments. Or is there? It turns out that calling `.toString()` on a function returns the
|
|
||||||
function declaration along with the argument names as shown below:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
function myFn(a,b){}
|
|
||||||
expect(myFn.toString()).toEqual('function myFn(a,b){}');
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
This means that angular can infer the function names after all and use that information to generate
|
|
||||||
the `$inject` annotation automatically. Therefore the following two function definitions are
|
|
||||||
equivalent:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
// given a user defined service
|
|
||||||
angular.module('module1', [], function($provide) {
|
|
||||||
$provide.factory('serviceA', ...);
|
|
||||||
});
|
|
||||||
|
|
||||||
// inject '$window', 'serviceA', curry 'name';
|
|
||||||
function fnA($window, serviceA, name){};
|
|
||||||
fnA.$inject = ['$window', 'serviceA'];
|
|
||||||
|
|
||||||
// inject '$window', 'serviceA', curry 'name';
|
|
||||||
function fnB($window, serviceA_, name){};
|
|
||||||
// implies: fnB.$inject = ['$window', 'serviceA'];
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
If angular does not find a `$inject` annotation on the function, then it calls the `.toString()`
|
|
||||||
method and tries to infer what should be injected by using function argument names as dependency
|
|
||||||
identifiers.
|
|
||||||
|
|
||||||
**IMPORTANT**
|
|
||||||
Minifiers/obfuscators change the names of function arguments and will therefore break the `$inject`
|
|
||||||
inference. For this reason, either explicitly declare the `$inject` or do not use
|
|
||||||
minifiers/obfuscators. In the future, we may provide a pre-processor which will scan the source
|
|
||||||
code and insert the `$inject` into the source code so that it can be minified/obfuscated.
|
|
||||||
|
|
||||||
|
|
||||||
### Dependency inference and variable name shadowing
|
|
||||||
|
|
||||||
During inference, the injector considers argument names with leading and trailing underscores to be
|
|
||||||
equivivalent to the name without these underscores. For example `_fooSvc_` argument name is treated
|
|
||||||
as if it was `fooSvc`, this is useful especially in tests where variable name shadowing can cause
|
|
||||||
some friction. This is best illustrated on examples:
|
|
||||||
|
|
||||||
When testing a service, it's common to need a reference to it in every single test. This can be
|
|
||||||
done in jasmine with DI inference like this:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
describe('fooSvc', function() {
|
|
||||||
it('should do this thing', inject(function(fooSvc) {
|
|
||||||
//test fooSvc
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should do that thing', inject(function(fooSvc) {
|
|
||||||
//test fooSvc
|
|
||||||
}));
|
|
||||||
|
|
||||||
// more its
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
... but having to inject the service over and over gets easily tiresome.
|
|
||||||
|
|
||||||
It's likely better to rewrite these tests with a use of jasmine's `beforeEach`:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
describe('fooSvc', function() {
|
|
||||||
var fooSvc;
|
|
||||||
|
|
||||||
beforeEach(inject(function(fooSvc) {
|
|
||||||
fooSvc = fooSvc; // DOESN'T WORK! outer fooSvc is being shadowed
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should do this thing', function() {
|
|
||||||
//test fooSvc
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should do that thing', function() {
|
|
||||||
//test fooSvc
|
|
||||||
});
|
|
||||||
|
|
||||||
// more its
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
This obviously won't work because `fooSvc` variable in the describe block is being shadowed by the
|
|
||||||
`fooSvc` argument of the beforeEach function. So we have to resort to alternative solutions, like
|
|
||||||
for example use of array notation to annotate the beforeEach fn:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
describe('fooSvc', function() {
|
|
||||||
var fooSvc;
|
|
||||||
|
|
||||||
beforeEach(inject(['fooSvc', function(fooSvc_) {
|
|
||||||
fooSvc = fooSvc_;
|
|
||||||
}]));
|
|
||||||
|
|
||||||
it('should do this thing', function() {
|
|
||||||
//test fooSvc
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should do that thing', function() {
|
|
||||||
//test fooSvc
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
|
|
||||||
That's better, but it's still annoying, especially if you have many services to inject.
|
|
||||||
|
|
||||||
To resolve this shadowing problem, the injector considers `_fooSvc_` argument names equal to
|
|
||||||
`fooSvc`, so the test can be rewritten like this:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
describe('fooSvc', function() {
|
|
||||||
var fooSvc;
|
|
||||||
|
|
||||||
beforeEach(inject(function(_fooSvc_) {
|
|
||||||
fooSvc = _fooSvc_;
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should do this thing', function() {
|
|
||||||
//test fooSvc
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should do that thing', function() {
|
|
||||||
//test fooSvc
|
|
||||||
});
|
|
||||||
|
|
||||||
// more its
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
|
||||||
|
|
||||||
* {@link dev_guide.services Angular Services}
|
|
||||||
|
|
||||||
## Related API
|
|
||||||
|
|
||||||
* {@link api/angular.module.ng Services API}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
@ngdoc overview
|
|
||||||
@name Developer Guide: DI: Using DI in Controllers
|
|
||||||
@description
|
|
||||||
|
|
||||||
The most common place to use dependency injection in angular applications is in {@link
|
|
||||||
dev_guide.mvc.understanding_controller controllers}. Here is a simple example:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
function MyController($location){
|
|
||||||
// do stuff with the $location service
|
|
||||||
}
|
|
||||||
MyController.$inject = ['$location'];
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
In this example, the `MyController` constructor function takes one argument, the {@link
|
|
||||||
api/angular.module.ng.$location $location} service. Angular is then responsible for supplying the
|
|
||||||
instance of `$location` to the controller when the constructor is instantiated. There are two ways
|
|
||||||
to cause controller instantiation – by configuring routes with the `$location` service, or by
|
|
||||||
referencing the controller from the HTML template, as follows:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<!doctype html>
|
|
||||||
<html ng-controller="MyController" ng-app>
|
|
||||||
<script src="http://code.angularjs.org/angular.min.js"></script>
|
|
||||||
<body>
|
|
||||||
...
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
When angular is instantiating your controller, it needs to know what services, if any, should be
|
|
||||||
injected (passed in as arguments) into the controller. Since there is no reflection in JavaScript,
|
|
||||||
we have to supply this information to angular in the form of an additional property on the
|
|
||||||
controller constructor function called `$inject`. Think of it as annotations for JavaScript.
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
MyController.$inject = ['$location'];
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
The information in `$inject` is then used by the {@link api/angular.injector injector} to call the
|
|
||||||
function with the correct arguments.
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
|
||||||
|
|
||||||
* {@link dev_guide.di About Dependency Injection}
|
|
||||||
* {@link dev_guide.di.understanding_di Understanding Dependency Injection in Angular}
|
|
||||||
* {@link dev_guide.services Angular Services}
|
|
||||||
|
|
||||||
## Related API
|
|
||||||
|
|
||||||
* {@link api/angular.injector Angular Injector API}
|
|
||||||
|
|
@ -12,7 +12,7 @@ The MVC pattern greatly summarized:
|
||||||
* Separate applications into distinct presentation, data, and logic components
|
* Separate applications into distinct presentation, data, and logic components
|
||||||
* Encourage loose coupling between these components
|
* Encourage loose coupling between these components
|
||||||
|
|
||||||
Along with {@link dev_guide.services services} and {@link dev_guide.di dependency injection}, MVC
|
Along with {@link dev_guide.services services} and {@link di dependency injection}, MVC
|
||||||
makes angular applications better structured, easier to maintain and more testable.
|
makes angular applications better structured, easier to maintain and more testable.
|
||||||
|
|
||||||
The following topics explain how angular incorporates the MVC pattern into the angular way of
|
The following topics explain how angular incorporates the MVC pattern into the angular way of
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ needed for a single view.
|
||||||
|
|
||||||
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
|
The most common way to keep controllers slim is by encapsulating work that doesn't belong to
|
||||||
controllers into services and then using these services in controllers via dependency injection.
|
controllers into services and then using these services in controllers via dependency injection.
|
||||||
This is discussed in the {@link dev_guide.di Dependency Injection} {@link dev_guide.services
|
This is discussed in the {@link di Dependency Injection} {@link dev_guide.services
|
||||||
Services} sections of this guide.
|
Services} sections of this guide.
|
||||||
|
|
||||||
Do not use controllers for:
|
Do not use controllers for:
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ to write your own custom services. To do this you begin by registering a service
|
||||||
with a module either via the {@link api/angular.module Module#factory api} or directly
|
with a module either via the {@link api/angular.module Module#factory api} or directly
|
||||||
via the {@link api/angular.module.AUTO.$provide $provide} api inside of module config function.
|
via the {@link api/angular.module.AUTO.$provide $provide} api inside of module config function.
|
||||||
|
|
||||||
All angular services participate in {@link dev_guide.di dependency injection (DI)} by registering
|
All angular services participate in {@link di dependency injection (DI)} by registering
|
||||||
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
||||||
dependencies which need to be provided for the factory function of the registered service. The
|
dependencies which need to be provided for the factory function of the registered service. The
|
||||||
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
||||||
|
|
@ -49,7 +49,7 @@ create this instance when called.
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
Services can not only be depended upon, but also have its own dependencies. These can be specified
|
Services can not only be depended upon, but also have its own dependencies. These can be specified
|
||||||
as arguments of the factory function. {@link dev_guide.di.understanding_di Read more} about the DI
|
as arguments of the factory function. {@link di.understanding_di Read more} about the DI
|
||||||
in Angular and the use of array notation and $inject property to make DI annotation
|
in Angular and the use of array notation and $inject property to make DI annotation
|
||||||
minification-proof.
|
minification-proof.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
Services are a feature that angular brings to client-side web apps from the server side, where
|
Services are a feature that angular brings to client-side web apps from the server side, where
|
||||||
services have been commonly used for a long time. Services in angular apps are substitutable
|
services have been commonly used for a long time. Services in angular apps are substitutable
|
||||||
objects that are wired together using {@link dev_guide.di dependency injection (DI)}. Services are
|
objects that are wired together using {@link di dependency injection (DI)}. Services are
|
||||||
most often used with {@link dev_guide.di dependency injection}, also a key feature of angular apps.
|
most often used with {@link di dependency injection}, also a key feature of angular apps.
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ above). You can also create your own custom services.
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
* {@link dev_guide.di About Angular Dependency Injection}
|
* {@link di About Angular Dependency Injection}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ myClass.doWork();
|
||||||
|
|
||||||
Notice that no global variables were harmed in the writing of this test.
|
Notice that no global variables were harmed in the writing of this test.
|
||||||
|
|
||||||
Angular comes with {@link dev_guide.di dependency-injection} built in which makes the right thing
|
Angular comes with {@link di dependency-injection} built in which makes the right thing
|
||||||
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
easy to do, but you still need to do it if you wish to take advantage of the testability story.
|
||||||
|
|
||||||
## Controllers
|
## Controllers
|
||||||
|
|
|
||||||
234
docs/content/guide/di.ngdoc
Normal file
234
docs/content/guide/di.ngdoc
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
@ngdoc overview
|
||||||
|
@name Developer Guide: Dependency Injection
|
||||||
|
@description
|
||||||
|
|
||||||
|
# Dependency Injection
|
||||||
|
|
||||||
|
Dependency Injection (DI) is a software design pattern that deals with how code gets hold of its
|
||||||
|
dependencies.
|
||||||
|
|
||||||
|
For in-depth discussion about DI, see {@link http://en.wikipedia.org/wiki/Dependency_injection
|
||||||
|
Dependency Injection} at Wikipedia, {@link http://martinfowler.com/articles/injection.html
|
||||||
|
Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
|
||||||
|
book.
|
||||||
|
|
||||||
|
## DI in a nutshell
|
||||||
|
|
||||||
|
There are only three ways how an object or a function can get a hold of its dependencies:
|
||||||
|
|
||||||
|
1. The dependency can be created, typically using the `new` operator.
|
||||||
|
|
||||||
|
2. The dependency can be looked up by referring to a global variable.
|
||||||
|
|
||||||
|
3. The dependency can be passed in to where it is needed.
|
||||||
|
|
||||||
|
|
||||||
|
The first two option of creating or looking up dependencies are not optimal, because they hard
|
||||||
|
code the dependency, making 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.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
function SomeClass(greeter) {
|
||||||
|
this.greeter = greeter
|
||||||
|
}
|
||||||
|
|
||||||
|
SomeClass.prototype.doSomething = function(name) {
|
||||||
|
this.greeter.greet(name);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
In the above example the `SomeClass` is not concerned with locating the `greeter` dependency, it
|
||||||
|
is simply handed the `greeter` at runtime.
|
||||||
|
|
||||||
|
This is desirable, but it puts the responsibility of getting hold of the dependency onto the
|
||||||
|
code responsible for the construction of `SomeClass`.
|
||||||
|
|
||||||
|
To manage the responsibility of dependency creation, each angular application has an {@link
|
||||||
|
api/angular.injector injector}. The injector is a service locator that is responsible for
|
||||||
|
construction and lookup of dependencies.
|
||||||
|
|
||||||
|
|
||||||
|
Here is an example of using the injector service.
|
||||||
|
<pre>
|
||||||
|
// Provide the wiring information in a module
|
||||||
|
angular.module('myModule', []).
|
||||||
|
|
||||||
|
// Teach the injector how to build a 'greeter'
|
||||||
|
// Notice that greeter itself is dependent on '$window'
|
||||||
|
factory('greeter', function($window) {
|
||||||
|
// This is a factory function, and is responsible for
|
||||||
|
// creating the 'greet' service.
|
||||||
|
return {
|
||||||
|
greet: function(text) {
|
||||||
|
$window.alert(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}).
|
||||||
|
|
||||||
|
// New injector is created from the module.
|
||||||
|
// (This is usually done automatically by angular bootstrap)
|
||||||
|
var injector = angular.injector('myModule');
|
||||||
|
|
||||||
|
// Request any dependency from the injector
|
||||||
|
var greeter = injector.get('greeter');
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
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 {@link
|
||||||
|
http://en.wikipedia.org/wiki/Law_of_Demeter Law of Demeter}. To remedy this, we turn the
|
||||||
|
dependency lookup responsibility to the injector by declaring the dependencies as in this example:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<!-- Given this HTML -->
|
||||||
|
<div ng-controller="MyController">
|
||||||
|
<button ng-click="sayHello()">Hello</button>
|
||||||
|
</div>
|
||||||
|
</pre>
|
||||||
|
<pre>
|
||||||
|
// And this controller definition
|
||||||
|
function MyController($scope, greeter) {
|
||||||
|
$scope.sayHello = function() {
|
||||||
|
greeter('Hello World');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 'ng-controller' directive does this behind the scenes
|
||||||
|
injector.instantiate(MyController);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
|
||||||
|
dependencies of the `MyController` without the controller ever knowing about the injector. This is
|
||||||
|
the best outcome. The application code simply ask for the dependencies it needs, without having to
|
||||||
|
deal with the injector. This setup does not break the Law of Demeter.
|
||||||
|
|
||||||
|
# Dependency Annotation
|
||||||
|
|
||||||
|
How does the injector know what service needs to be injected?
|
||||||
|
|
||||||
|
The application developer needs to provide annotation information, that the injector uses in order
|
||||||
|
to resolve the dependencies. Throughout Angular certain API functions are invoked using the
|
||||||
|
injector, as per the API documentation. The injector needs to know what services to inject into
|
||||||
|
the function. Below are three equivalent ways of annotating your code with service name
|
||||||
|
information. These can be used interchangeably as you see fit and are equivalent.
|
||||||
|
|
||||||
|
# Inferring Dependencies
|
||||||
|
|
||||||
|
The simplest way to get hold of the dependencies, is to assume that the function parameter names
|
||||||
|
are the names of the dependencies.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
function MyController($scope, greeter) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Given a function the injector can infer the names of the service 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.
|
||||||
|
|
||||||
|
While straightforward, this method will not work with JavaScript minifiers/obfuscators as they
|
||||||
|
rename the method parameter names. This makes this way of annotating only useful for {@link
|
||||||
|
http://www.pretotyping.org/ pretotyping}, and demo applications.
|
||||||
|
|
||||||
|
# `$inject` Annotation
|
||||||
|
|
||||||
|
To allow the minifers to rename the function parameters and still be able to inject right services
|
||||||
|
the function needs to be annotate with the `$inject` property. The `$inject` property is an array
|
||||||
|
of service names to inject.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
var MyController = function(renamed$scope, renamedGreeter) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
MyController.$inject = ['$scope', 'greeter'];
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Care must be taken that the `$inject` annotation is kept in sync with the actual arguments in the
|
||||||
|
function declaration.
|
||||||
|
|
||||||
|
This method of annotation is useful for controller declarations since it assigns the annotation
|
||||||
|
information with the function.
|
||||||
|
|
||||||
|
# Inline Annotation
|
||||||
|
|
||||||
|
Sometimes using the `$inject` annotation style is not convenient such as when annotating
|
||||||
|
directives.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
<pre>
|
||||||
|
someModule.factory('greeter', function($window) {
|
||||||
|
...;
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Results in code bloat do to the need of temporary variable:
|
||||||
|
<pre>
|
||||||
|
var greeterFactory = function(renamed$window) {
|
||||||
|
...;
|
||||||
|
};
|
||||||
|
|
||||||
|
greeterFactory.$inject = ['$window'];
|
||||||
|
|
||||||
|
someModule.factory('greeter', greeterFactory);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
For this reason the third annotation style is provided as well.
|
||||||
|
<pre>
|
||||||
|
someModule.factory('greeter', ['$window', function(renamed$window) {
|
||||||
|
...;
|
||||||
|
}]);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
|
||||||
|
where injection is supported.
|
||||||
|
|
||||||
|
|
||||||
|
# Where can I use DI?
|
||||||
|
|
||||||
|
DI is pervasive throughout Angular. It is typically used in controllers and factory methods.
|
||||||
|
|
||||||
|
## DI in controllers
|
||||||
|
|
||||||
|
Controllers are classes which are responsible for application behavior. Recommended way of
|
||||||
|
declaring controllers is:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
var MyController = function(dep1, dep2) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
MyController.$inject = ['dep1', 'dep2'];
|
||||||
|
|
||||||
|
MyController.prototype.aMethod = function() {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
## Factory methods
|
||||||
|
|
||||||
|
Factory methods are responsible for creating most objects in Angular. Examples are directives,
|
||||||
|
services, and filters. The factory methods are register with the module, and the recommended way
|
||||||
|
of declaring factories is:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
angualar.module('myModule', []).
|
||||||
|
config(['depProvider', function(depProvider){
|
||||||
|
...
|
||||||
|
}]).
|
||||||
|
factory('serviceId', ['depService', function(depService) {
|
||||||
|
...
|
||||||
|
}]).
|
||||||
|
directive('directiveName', ['depService', function(depService) {
|
||||||
|
...
|
||||||
|
}]).
|
||||||
|
filter('filterName', ['depService', function(depService) {
|
||||||
|
...
|
||||||
|
}]).
|
||||||
|
run(['depService', function(depService) {
|
||||||
|
...
|
||||||
|
}]);
|
||||||
|
</pre>
|
||||||
|
|
@ -44,7 +44,4 @@ of the following documents before returning here to the Developer Guide:
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.testing_services Testing Angular Services}
|
* {@link dev_guide.services.testing_services Testing Angular Services}
|
||||||
|
|
||||||
## {@link dev_guide.di About Dependency Injection}
|
## {@link di About Dependency Injection}
|
||||||
|
|
||||||
* {@link dev_guide.di.understanding_di Understanding DI in Angular}
|
|
||||||
* {@link dev_guide.di.using_di_controllers Using DI in Controllers}
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* Creates an injector function that can be used for retrieving services as well as for
|
* Creates an injector function that can be used for retrieving services as well as for
|
||||||
* dependency injection (see {@link guide/dev_guide.di dependency injection}).
|
* dependency injection (see {@link guide/di dependency injection}).
|
||||||
*
|
*
|
||||||
|
|
||||||
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
|
* @param {Array.<string|Function>} modules A list of module functions or their aliases. See
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue