Dependency Injection (DI) in {{AngularJS}} Contd.– Part 17

This post is in continuation of my last post DI on AngularJS. In previous post, we first discussed about DI in details with an example of implementing it in JavaScript. Then we discussed the way AngularJS provides us the opportunity to implement DI and various options available with it.  We discussed two types Value and Factory in detail. In this post, we will be discussing rest three types and will see how DI takes place behind the scene. I would suggest you to go through the previous post (Dependency Injection (DI) in {{AngularJS}} – Part 16) before continuing further.

Note – This post is a part of series of posts on AngularJS and it is 17th one. Click here to view all the post. Apart from that you can also use the navigation links for next and previous post in each post at the bottom to check all.

Service :  It provides another way to create a service and similar to factory. Only difference between factory and service is that service returns a new’ed instance by invoking constructor. Let’s see the example. Here I am going to use the same example that we used in factory

var myangularapp = angular.module('myangularapp', []);

myangularapp.service('Circle', function() {

    var pi = 3.14;
    this.Area = function (r) {
        return pi * r * r;
    }
    this.Circuimference = function (r) {
        return 2* pi * r;
    }
});

myangularapp.controller("mycontroller", function ($scope, Circle) {
    $scope.AreaofCircle = Circle.Area(5);
    $scope.CircuimferenceOfCircle = Circle.Circuimference(5);

});

In above example, you can see that I have removed myfactory variable and all the APIs starts with this operator.

Provider – Provider is the key for all the other types as others are just syntactic sugar on it. We have put different wrapper over that to get different flavor. Writing provider directly is not very intuitive and requires us to write bit more code but very helpful in understanding the concept and fits best in some scenarios. For creating a new Provider, there are two steps involved, first creating a provider and then configuring it. Provider can be used when exposing API throughout the application. These APIs are configured before the application starts. It provides us ability to change the behavior of Provider a bit between multiple applicationd. Let’s see an example

var myangularapp = angular.module('myangularapp', []);

// Creating the provider
myangularapp.provider('RequestProcessor', function () {

    var requestId = '00000000';

    this.setrequestId = function (value) {
        requestId = value;
    };

    this.$get = function () {
        return "Processing Request Id : " + requestId;
    };
});

In the above provider, we have two items, one that takes the requestId and assigns it in local variable and another $get property, which is actually key here and returns the instance of the service. Let’s see the configuration part

// Configuring the provider
myangularapp.config(["RequestProcessorProvider", function (RequestProcessorProvider) {
    RequestProcessorProvider.setrequestId("123456");
}]);

Here we see a Provider is injected in config method (provider is added as suffix) and the setrequestid is called. It is not the normal instance injector. When an Angular application starts, it configures and instantiates all the providers. And till this time application is not completely initialized, it is in configuration phase, so any type of services that we discussed earlier, will not be accessible here. Now we can use it in our page as

myangularapp.controller("mycontroller", function ($scope, RequestProcessor) {
    $scope.statusmessage = RequestProcessor;
});

The same provider can be used at another place with different behavior, if we put the provider in some common file and config part in the view (or in another JS file and include accordingly). Let’s say in one view, I have the above config implementation and in other we have as

myangularapp.config(["RequestProcessorProvider", function (RequestProcessorProvider) {
    RequestProcessorProvider.setrequestId("5678");
}]);

Here I am passing different Id. So the same provider can be used differently in two views. Complete example is available in attached sample.

Constant : It is similar to Value but the difference lies where it is initialized. Value gets set during application configuration phase as discussed while constant earlier. It means we cannot add any dependency in provider which is initialized via Value or even factory/service while Constant one can be used. Let’s see the example.

myangularapp.constant('applicationName', 'CodeWala request processor');
myangularapp.constant('applicationmetainfo', {
    version: '1.0'
});

We have discussed that how we can create multiple type of providers and then later use them at different places. We pass those services as parameter as when we access them they are properly initialized. But how does that happen?

Dependency Injection behind the scene We have talked briefly about the $injector in my previous post as said that it is the core of dependency injection in AngularJS.In simple terms, whenever you see that an custom (that we discussed) or an inbuilt service (like $http, $q etc) are provided as parameter, $injector will be at work. It actually locate and find or create the instance and return it. Let’s see the flow pictorially DIflowFrom the above image, we can understand that once the instance gets created, it gets cached and later whenever it is required returned from the cache only. This is how all the services behaves as singleton as mentioned earlier. We have seen that how injector works behind the scene, lets see some example using it specifically. Earlier we passed the services as parameter, now we will get the instance using injector. Earlier we wrote our controller as

myangularapp.controller("mycontroller", function ($scope, Circle) {
    $scope.AreaofCircle = Circle.Area(5);
    $scope.CircuimferenceOfCircle = Circle.Circuimference(5);
});

We can also write it as

// Getting the injector
var injector = angular.injector(['myangularapp', 'ng']);

myangularapp.controller("mycontroller", function ($scope) {

    // Getting the instance via injetcor
    var Circle = injector.get('Circle');
    $scope.AreaofCircle = Circle.Area(5);
    $scope.CircuimferenceOfCircle = Circle.Circuimference(5);
});

Even we can invoke any function as

angular.injector(["myangularapp"]).invoke(function (Circle) {
    alert(Circle.Area(5));
});

Here we saw that instead of passing services as parameter, we got the instance using injector. And invoke allows us to execute that particular service. When we pass the services as a parameter, how does injector come into the picture. Actually, when we write as ng-controller=”mycontroller” then here the injector comes into the scene and it is the injector which actually resolves all the required dependencies by injector.instantiate(‘mycontroller’).

So in this post, we discussed about the other three types to implement DI. Then later we discussed how does it work actually behind the scene. Hope you have enjoyed this post. Do share your feedback.

Thanks
Brij

[28th Aug 2015 : Updated this post for Angular version 1.4]

Advertisement

2 thoughts on “Dependency Injection (DI) in {{AngularJS}} Contd.– Part 17

  1. Pingback: Dependency Injection Annotation Process in AngularJS – Part 18 | Code Wala

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s