A detailed description of dependency injection in Angularjs

Source: Internet
Author: User
Tags abstract tree

Dependency Injection

In general, an object can only get its dependent items in three ways:

    1. We can create dependent projects inside the object
    2. We can use dependencies as a global variable to find or reference
    3. We can pass the dependency to where it's needed.

When using dependency injection, we are using a third approach (the other two approaches can cause other difficult challenges, such as polluting the global scope and making the isolation almost impossible). Dependency Injection is a design pattern that removes hard-coded dependencies so that we can remove and change dependent projects at any time while running.

The ability to modify dependent projects during the run allows us to create an isolated environment, which is ideal for testing. We can replace a real object in the production environment with a spoofed object in the test environment.

Functionally, this pattern injects dependent resources into places where they are needed by automatically finding dependencies and providing targets for dependencies.

When we write a component that relies on other objects or libraries, we describe its dependent projects. During the run, an injector will create the dependent instances and pass them on to a dependent consumer.

// A good example from the Angularjs function SomeClass (greeter) {     this.greeter =function(name) {        this. Greeter.greet (name)  }

Note: As with the instance code above, it is never a good idea to create a controller in the global scope. The code above simply simplifies the principle of dependency injection.

In the run, SomeClass doesn't care how it gets greeter dependent, just get it on the line. In order to pass the Greeter instance to SomeClass, the creator of SomeClass also has to be responsible for passing dependencies on the function when it is created.

For these reasons, angular uses $injector to manage dependent queries and instantiate dependent projects. In fact, $injector is responsible for all the instances of our angular components, including the modules, instructions, controllers and so on that we apply.

During the run, when any of our modules are booted, the injector is actually responsible for instantiating the instance of the object and passing it the dependent items it needs.

For example, the following simple code declares a separate module and a separate controller, as follows:

Angular.module (' myApp ', [])  . Factory (functionreturn   function(msg) {alert (msg);}}  ) . Controller (' Mycontroller ',  functionfunction() {  Greeter.greet ("hello!" ); };  });

During runtime, when Angularjs Initializes an instance of our model, it looks for greeter and simply passes it to our module:

<DivNg-app= "MYAPP"><DivNg-controller= "Mycontroller"><ButtonNg-click= "SayHello ()">Hello</Button> </Div></Div>

Behind the scenes, the process of running the angular is as follows:

// loading an   application with an injector var injector = Angular.injector ([' ng ', ' myApp '/// and injector loaded with $controllervar $controller = injector.get (' $controller 'var scope = injector.get (' $rootScope '). $New // load the controller, pass it to a scope // This is what angular does during the run. Var    Mycontroller = $controller (' Mycontroller ', {$scope: scope})

The above example does not describe how we are going to find greeter; it runs very simply, during which the injector helps us find and load dependent projects.

During instantiation, Angularjs uses a comment function to extract attributes from the passed array. You can view this function by entering the following code in the developer tools of Chrome Browser:

> injector.annotate (function($q, greeter) {}) ["$q", "greeter"]

In every angular application, $injector is always running, whether we are aware of it or not. When we write a controller but do not add the [] bracket designator, or explicitly set them, $injector will infer dependent items based on the name of the variable.

to annotate by speculation

Angular assumes that the parameter name of the function is the name of the dependent project, if not specifically specified. Therefore, it calls the ToString () method on the function, parses and extracts the variable from the function, and then injects the variable into an instance of the object using $injector. The process of injection is this:

Injector.invoke (function($http, greeter) {});

Note that this process can only be done under a code that is not compressed, without ambiguity, because angular requires a full parsing variable.

In JavaScript speculation, the order of the parameters is not important: angular will find these parameters for us and inject the correct attributes into the "correct" position.

JavaScript refiners generally reduce the final volume of JavaScript files by changing the function's parameters to a minimum number of letters (which also changes the spaces, removing new lines and annotations, and so on). If we do not explicitly describe the variable, angular will not be able to speculate on the variable so that it cannot inject the required dependency.

Explicit Annotations

Angular provides us with a way to explicitly define the dependent items required for a function. This method allows the refiner to rename the parameters of the function and also ensures that the appropriate service is injected into the function.

The injection process uses the $inject property to annotate the function. The $inject property of a function is an array of service names that are injected into the function as dependencies.

To use the $inject property method, we set it on a function or function name.

varAcontrollerfactory =functionAcontroller ($scope, greeter) {Console.log ("LOADED Controller", greeter); // ... Controller};acontrollerfactory. $inject= [' $scope ', ' greeter '];//Greeter ServicevarGreeterservice =function() {Console.log ("Greeter Service");}//Our application ControllersAngular.module (' myApp '), []). Controller (' Mycontroller ', Acontrollerfactory). Factory (' Greeter ', greeterservice);//get the injector and create a new scopevarInjector = Angular.injector ([' ng ', ' myApp ')]), controller= Injector.get (' $controller '), Rootscope= Injector.get (' $rootScope '), NewScope= rootscope.$New();//Call ControllerController (' Mycontroller ', {$scope: NewScope});

With this style of annotation, the order is important, so the $inject array must match the order of the injected variables. This method of injection works well in the case of thin code, because the annotation information is still packaged in the function.

Inline Comments

The last method that angular provides is an inline comment. This syntax sugar works the same way as the $inject injection method mentioned above, but allows us to write inline parameters when the function is defined. In addition, it allows us to define without using a temporary variable.

Inline annotations allow us to pass an array of arguments instead of a function when defining a angular object. The elements in the array are a list of injected dependency strings, and the last variable is the function definition of the object.

For example:

Angular.module (' myApp ')  . Controller (' Mycontroller ',  [function($scope, greeter) {}]);

The inline annotation method works well in the case of thin code, because we pass a list of strings in it. We often call this method a square bracket comment or an array comment.

$inject API

Even though we need to use $injector directly, there is very little to know about $inject's API, which will help us to better understand its operating mechanism.

Annotate ()

The annotate () function returns an array of service names that will be injected into the function at initialization time. The annotate () function is typically used by the injector to determine what service should be injected at the time of invocation.

The annotate () function receives a variable:

    • fn (function or array)

FN can be a given function, or it can be an array containing the function definition in the square bracket identifier.

The annotate () function returns an array of service names that will be injected into the function at initialization time.

var injector = Angular.injector ([' ng ', ' myApp ']); Injector.annotate (function($q, greeter) {}); // [' $q ', ' greeter ']

Try it out in the debugger of your Chrome browser.

Get ()

The Get () method receives a parameter and returns an instance of the service.

    • Name (String)

The name variable is the names of the instances we want to get.

Get () returns an instance of a service by name.

Has ()

If the injector knows that its registration service contains a service, the has () method returns True, and conversely returns false. It receives a parameter:

    • Name (String)

This string is the name of the service that we want to find in the registry service of the injector.

Instantiate ()

The instantiate () method creates a new instance of the JavaScript type. It receives a constructor function and invokes the new operator with all specified parameters. It receives two parameters:

    • Type (function)

This function is the comment constructor function that will be called.

    • Locals (object – optional)

This optional parameter provides another way to pass parameters when the function is called.

The instantiate () method returns a new instance of type.

Invoke

The Invoke () method invokes the method to add a method parameter from the $injector.

This invoke () method receives three parameters:

    • FN (function)

This function is the function that will be called. This parameter for the function is set along with the comment.

    • Self (object – optional)

The self variable allows us to set the this variable of the method that will be called.

    • Locals (object – optional)

This optional parameter provides another way to pass the variable name when the function is invoked.

Ngmin

With the above three ways of defining annotations, it is important to note that these options exist when you define a function. However, in the specific production process, deliberately pay attention to the parameter sequence and code expansion is very inconvenient.

The Ngmin tool eases the pain of displaying defined dependencies. The ngmin is a pre-refiner for angular applications. It will traverse our angular application and set up dependency injection for us.

For example, it will have the following code:

Angular.module (' myApp ', []). Directive (' mydirective ',function($http) {}). Controller (' Indexcontroller ',function($scope, $q) {});

Convert to the following code:

Angular.module (' myApp ', []). Directive (' mydirective ',[' $http ',function ($http) {}]). Controller ('indexcontroller ' $scope ',' $q ',function  ($ Scope, $q) {}]);

Ngmin saved us a lot of time to enter the code, and it made our source files very clean.

Installing Ngmin

In order to install ngmin, we need to use the NPM Package Manager:

npm install -g ngmin

If we use grunt, we can install Grunt-ngmin Grunt task. If we use rails, we can use Ruby gem ngmin-rails.

Using Ngmin

We can use Ngmin in the command-line tool standalone mode, just pass two parameters for it: Input.js and output.js or through stdio/stdout, as shown below:

$ ngmin inpit.js output.js

Or

$ ngmin < input.js > output.js

In the example above input.js is our source file, Output.js is the comment output file.

How does the ngmin work?

At its core, Ngmin uses the abstract tree (AST) to traverse the JavaScript source files. With the help of astral– an AST tool framework – It rebuilds the source file with the necessary annotations and outputs the updated file using Escodegen.

Ngmin wants our angular source files to be made up of logical declarations. If our code syntax is similar to the code syntax used in this book, Ngmin will be able to parse the source file and pre-refine it.

This article is translated from the 14th chapter of Ng-book. Loaded from: http://www.html-js.com/article/1887

A detailed description of dependency injection in Angularjs

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.