1. Dependency Injection
Dependency injection (DI) is a software design pattern that deals with how code gets the resources it depends on.
For a deeper discussion about DI, you can visit Dependency Injection (http://en.wikipedia.org/wiki/Dependency_injection), Inversion of Control (http://martinfowler.com/articles/injection.html), or you can visit the book on software design patterns.
1. DI in a nutshell (simply speaking DI)
object or function can only obtain the resources they depend on in the following three ways:
1) You can create dependent resources through the new operator.
2) You can find dependent resources through global variables.
3) The dependent resources can be passed through parameters.
The two methods 1 and 2 are not the best, because they hard code the dependencies, which makes it not impossible to modify the dependencies, but it will become more complicated. This is especially a problem for testing, and usually when testing independently, it is desired to provide mock dependencies.
The third method is relatively the most feasible because it removes the responsibility of locating dependencies from components. Reliance is just handed over to the components.
function SomeClass(greeter) { this.greeter = greeter}SomeClass.prototype.doSomething = function(name) { this.greeter.greet(name);}In the above example, SomeClass does not need to care about locating the greeter dependency, it only passes greeter at runtime.
This is more appropriate, but it leaves the responsibility for obtaining the dependency resources to the code responsible for building SomeClass.
To manage the responsibility for creating dependencies, each angular application has an injector (http://code.angularjs.org/1.0.2/docs/api/angular.injector). Injector is a service locator that is responsible for locating and creating dependent resources.
Request dependencies, solves the problem of hard code, but it means that injector needs to run through the entire application. Passing injector will destroy Law of Demeter (http://baike.baidu.com/view/823220.htm). To correct this problem, we transfer the responsibility for dependency searches to the injector.
I have said so much above. Look at the examples I have modified below. I have merged two examples of the original text, using inject inside and outside angular:
<!DOCTYPE HTML><html lang="zh-cn" ng-app="MainApp"><head> <meta charset="UTF-8"> <title>injector</title></head><body><div ng-controller="MyController"> <button ng-click="sayHello()">Say Hello</button></div><script src="../angular-1.0.1.js" type="text/javascript"></script><script type="text/javascript"> //Create the module OtherModule, which is equivalent to the external module var otherModule = angular.module("OtherModule", []); //Teach injector how to create "greeter" //Note that greeter itself needs to rely on $window otherModule.factory("greeter", function ($window) { //This is a factory method, responsible for creating greet service return { greet:function (text) { $window.alert(text); } }; }); //The following shows that in a non-current module, call the greet method through the injector: //Create a new injector from the module //This step is usually done automatically when angular is started. //The 'ng', angular things must be introduced //The order is deliberately reversed, and it is temporarily confirmed that the order of this thing does not matter. . var injector = angular.injector(['OtherModule','ng']); //Request greeter's dependency. var g = injector.get("greeter"); //Call it directly~ g.greet("Hi~My Little Dada~"); //This is the current main app, and you need to rely on OtherModule var mainApp = angular.module("MainApp", ["OtherModule"]); // Pay attention to the parameters of the Controller's definition function, and directly inject $scope and greeter here. // The greeter service is mainApp.controller("MyController",function MyController($scope,greeter) { $scope.sayHello = function() { greeter.greet("Hello Kitty~~"); }; } ); //ng-controller has done this thing silently behind the scenes //injector.instantiate(MyController);</script></body></html>Note that because there is an ng-controller, MyController is initialized, it can meet all the dependencies of MyController, so that MyController does not need to know the existence of injector. This is the best result. The application code simply requests the dependencies it needs without handling the injector. This setting will not break Law of Demeter.
2. Dependency Annotation (dependency comments, explaining the way of dependencies)
How does injector know what service needs to be injected?
Application developers need to provide annotation information used by injector as a solution to dependencies. All existing API functions in angular refer to injector, and this is the case with the API mentioned in each document. Here are three equivalent ways to annotate our code with service name information.
1. Inferring Dependencies
This is the easiest way to get a dependent resource, but it is necessary to assume that the parameter name of the function is consistent with the name of the dependent resource.
function MyController($scope, greeter) { ...}The injector of a function can guess the name of the service that needs to be injected (functionName.toString(), RegExp) by checking the function definition and extracting the function name. In the above example, $scope and greeter are two services that need to be injected into the function (the names are also the same).
Although this is simple, this method will not work after javascript obfuscation compression, because the parameter name will be changed. This makes this method only useful for pretotyping (product usability prototype simulation test method, http://www.pretotyping.org/, http://tech.qq.com/a/20120217/000320.htm) and demo applications.
2. $inject Annotation ($inject comment)
In order to allow the script compressor to rename the function's method and still be able to inject the correct service, the function must comment on the dependency through the $inject property. The $inject property is an array of the names of the services that need to be injected.
var MyController = function(renamed$scope, renamedGreeter) { ...}//If the thing that is dependent here is not in the current module, it still does not recognize it. //You need to first rely on the corresponding module in the current module. It's similar to the previous example. But I don't know if this is the right way.
MyController.$inject = ['$scope', 'greeter'];
It should be careful that the order of $inject needs to be consistent with the order of arguments declared by the function.
This annotation method is useful for controller declarations because it specifies annotation information with the function.
3. inline Annotation (inline comments)
Sometimes, it is not convenient to use the $inject annotation method, such as when commenting directly.
For example:
someModule.factory('greeter', function($window) { ...;});Because temporary variables are required (prevent it from being unable to be used after compression), the code will bloat as:
var greeterFactory = function(renamed$window) { ...;};greeterFactory.$inject = ['$window'];someModule.factory('greeter', greeterFactory);Because of this (code bloat), angular also provides a third comment style:
someModule.factory('greeter', ['$window', function(renamed$window) { ...;}]);Remember that all comment styles are equivalent and can be used anywhere in an angular that supports injection.
3. Where can I user DI?
DI is all over the angular. It is usually used in controller and factory methods.
1. DI in controllers
The controller is the class responsible for (describing) application behavior. The recommended controller declaration method is:
var MyController = function(dep1, dep2) { ...}MyController.$inject = ['dep1', 'dep2'];MyController.prototype.aMethod = function() { ...}2. Factory methods
The factory method is responsible for creating most angular objects. For example, directive, service, filter. The factory method is registered in the module. The recommended factory declaration method is:
angualar.module('myModule', []). config(['depProvider', function(depProvider){ ... }]). factory('serviceId', ['depService', function(depService) { ... }]). directive('directiveName', ['depService', function(depService) { ... }]). filter('filterName', ['depService', function(depService) { ... }]);The above is the summary of AngularJS Dependency Injection information. Thank you for your support for this site!