dependency injection - AngularJS: Service vs provider vs factory

ID : 150

viewed : 64

Tags : angularjsdependency-injectionangularjs-serviceangularjs-factoryangularjs-providerangularjs

Top 5 Answer for dependency injection - AngularJS: Service vs provider vs factory

vote vote

95

From the AngularJS mailing list I got an amazing thread that explains service vs factory vs provider and their injection usage. Compiling the answers:

Services

Syntax: module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().

Factories

Syntax: module.factory( 'factoryName', function );
Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory.

Providers

Syntax: module.provider( 'providerName', function );
Result: When declaring providerName as an injectable argument you will be provided with (new ProviderFunction()).$get(). The constructor function is instantiated before the $get method is called - ProviderFunction is the function reference passed to module.provider.

Providers have the advantage that they can be configured during the module configuration phase.

See here for the provided code.

Here's a great further explanation by Misko:

provide.value('a', 123);  function Controller(a) {   expect(a).toEqual(123); } 

In this case the injector simply returns the value as is. But what if you want to compute the value? Then use a factory

provide.factory('b', function(a) {   return a*2; });  function Controller(b) {   expect(b).toEqual(246); } 

So factory is a function which is responsible for creating the value. Notice that the factory function can ask for other dependencies.

But what if you want to be more OO and have a class called Greeter?

function Greeter(a) {   this.greet = function() {     return 'Hello ' + a;   } } 

Then to instantiate you would have to write

provide.factory('greeter', function(a) {   return new Greeter(a); }); 

Then we could ask for 'greeter' in controller like this

function Controller(greeter) {   expect(greeter instanceof Greeter).toBe(true);   expect(greeter.greet()).toEqual('Hello 123'); } 

But that is way too wordy. A shorter way to write this would be provider.service('greeter', Greeter);

But what if we wanted to configure the Greeter class before the injection? Then we could write

provide.provider('greeter2', function() {   var salutation = 'Hello';   this.setSalutation = function(s) {     salutation = s;   }    function Greeter(a) {     this.greet = function() {       return salutation + ' ' + a;     }   }    this.$get = function(a) {     return new Greeter(a);   }; }); 

Then we can do this:

angular.module('abc', []).config(function(greeter2Provider) {   greeter2Provider.setSalutation('Halo'); });  function Controller(greeter2) {   expect(greeter2.greet()).toEqual('Halo 123'); } 

As a side note, service, factory, and value are all derived from provider.

provider.service = function(name, Class) {   provider.provide(name, function() {     this.$get = function($injector) {       return $injector.instantiate(Class);     };   }); }  provider.factory = function(name, factory) {   provider.provide(name, function() {     this.$get = function($injector) {       return $injector.invoke(factory);     };   }); }  provider.value = function(name, value) {   provider.factory(name, function() {     return value;   }); }; 
vote vote

88

JS Fiddle Demo

" Hello world " example with factory / service / provider:

var myApp = angular.module('myApp', []);    //service style, probably the simplest one  myApp.service('helloWorldFromService', function() {      this.sayHello = function() {          return "Hello, World!";      };  });    //factory style, more involved but more sophisticated  myApp.factory('helloWorldFromFactory', function() {      return {          sayHello: function() {              return "Hello, World!";          }      };  });        //provider style, full blown, configurable version       myApp.provider('helloWorld', function() {        this.name = 'Default';        this.$get = function() {          var name = this.name;          return {              sayHello: function() {                  return "Hello, " + name + "!";              }          }      };        this.setName = function(name) {          this.name = name;      };  });    //hey, we can configure a provider!              myApp.config(function(helloWorldProvider){      helloWorldProvider.setName('World');  });              function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {            $scope.hellos = [          helloWorld.sayHello(),          helloWorldFromFactory.sayHello(),          helloWorldFromService.sayHello()];  }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>  <body ng-app="myApp">  <div ng-controller="MyCtrl">      {{hellos}}  </div>  </body>

vote vote

73

TL;DR

1) When you’re using a Factory you create an object, add properties to it, then return that same object. When you pass this factory into your controller, those properties on the object will now be available in that controller through your factory.

app.controller(‘myFactoryCtrl’, function($scope, myFactory){   $scope.artist = myFactory.getArtist(); });  app.factory(‘myFactory’, function(){   var _artist = ‘Shakira’;   var service = {};    service.getArtist = function(){     return _artist;   }    return service; }); 


2) When you’re using Service, AngularJS instantiates it behind the scenes with the ‘new’ keyword. Because of that, you’ll add properties to ‘this’ and the service will return ‘this’. When you pass the service into your controller, those properties on ‘this’ will now be available on that controller through your service.

app.controller(‘myServiceCtrl’, function($scope, myService){   $scope.artist = myService.getArtist(); });  app.service(‘myService’, function(){   var _artist = ‘Nelly’;   this.getArtist = function(){     return _artist;   } }); 



3) Providers are the only service you can pass into your .config() function. Use a provider when you want to provide module-wide configuration for your service object before making it available.

app.controller(‘myProvider’, function($scope, myProvider){   $scope.artist = myProvider.getArtist();   $scope.data.thingFromConfig = myProvider.thingOnConfig; });  app.provider(‘myProvider’, function(){  //Only the next two lines are available in the app.config()  this._artist = ‘’;  this.thingFromConfig = ‘’;   this.$get = function(){     var that = this;     return {       getArtist: function(){         return that._artist;       },       thingOnConfig: that.thingFromConfig     }   } });  app.config(function(myProviderProvider){   myProviderProvider.thingFromConfig = ‘This was set in config’; }); 



Non TL;DR

1) Factory
Factories are the most popular way to create and configure a service. There’s really not much more than what the TL;DR said. You just create an object, add properties to it, then return that same object. Then when you pass the factory into your controller, those properties on the object will now be available in that controller through your factory. A more extensive example is below.

app.factory(‘myFactory’, function(){   var service = {};   return service; }); 

Now whatever properties we attach to ‘service’ will be available to us when we pass ‘myFactory’ into our controller.

Now let’s add some ‘private’ variables to our callback function. These won’t be directly accessible from the controller, but we will eventually set up some getter/setter methods on ‘service’ to be able to alter these ‘private’ variables when needed.

app.factory(‘myFactory’, function($http, $q){   var service = {};   var baseUrl = ‘https://itunes.apple.com/search?term=’;   var _artist = ‘’;   var _finalUrl = ‘’;    var makeUrl = function(){    _artist = _artist.split(‘ ‘).join(‘+’);     _finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;     return _finalUrl   }    return service; }); 

Here you’ll notice we’re not attaching those variables/function to ‘service’. We’re simply creating them in order to either use or modify them later.

  • baseUrl is the base URL that the iTunes API requires
  • _artist is the artist we wish to lookup
  • _finalUrl is the final and fully built URL to which we’ll make the call to iTunes
  • makeUrl is a function that will create and return our iTunes friendly URL.

Now that our helper/private variables and function are in place, let’s add some properties to the ‘service’ object. Whatever we put on ‘service’ can be directly used inside whichever controller we pass ‘myFactory’ into.

We are going to create setArtist and getArtist methods that simply return or set the artist. We are also going to create a method that will call the iTunes API with our created URL. This method is going to return a promise that will fulfill once the data has come back from the iTunes API. If you haven’t had much experience using promises in AngularJS, I highly recommend doing a deep dive on them.

Below setArtist accepts an artist and allows you to set the artist. getArtist returns the artist. callItunes first calls makeUrl() in order to build the URL we’ll use with our $http request. Then it sets up a promise object, makes an $http request with our final url, then because $http returns a promise, we are able to call .success or .error after our request. We then resolve our promise with the iTunes data, or we reject it with a message saying ‘There was an error’.

app.factory('myFactory', function($http, $q){   var service = {};   var baseUrl = 'https://itunes.apple.com/search?term=';   var _artist = '';   var _finalUrl = '';    var makeUrl = function(){     _artist = _artist.split(' ').join('+');     _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'     return _finalUrl;   }    service.setArtist = function(artist){     _artist = artist;   }    service.getArtist = function(){     return _artist;   }    service.callItunes = function(){     makeUrl();     var deferred = $q.defer();     $http({       method: 'JSONP',       url: _finalUrl     }).success(function(data){       deferred.resolve(data);     }).error(function(){       deferred.reject('There was an error')     })     return deferred.promise;   }    return service; }); 

Now our factory is complete. We are now able to inject ‘myFactory’ into any controller and we’ll then be able to call our methods that we attached to our service object (setArtist, getArtist, and callItunes).

app.controller('myFactoryCtrl', function($scope, myFactory){   $scope.data = {};   $scope.updateArtist = function(){     myFactory.setArtist($scope.data.artist);   };    $scope.submitArtist = function(){     myFactory.callItunes()       .then(function(data){         $scope.data.artistData = data;       }, function(data){         alert(data);       })   } }); 

In the controller above we’re injecting in the ‘myFactory’ service. We then set properties on our $scope object with data from ‘myFactory’. The only tricky code above is if you’ve never dealt with promises before. Because callItunes is returning a promise, we are able to use the .then() method and only set $scope.data.artistData once our promise is fulfilled with the iTunes data. You’ll notice our controller is very ‘thin’ (This is a good coding practise). All of our logic and persistent data is located in our service, not in our controller.

2) Service
Perhaps the biggest thing to know when dealing with creating a Service is that that it’s instantiated with the ‘new’ keyword. For you JavaScript gurus this should give you a big hint into the nature of the code. For those of you with a limited background in JavaScript or for those who aren’t too familiar with what the ‘new’ keyword actually does, let’s review some JavaScript fundamentals that will eventually help us in understanding the nature of a Service.

To really see the changes that occur when you invoke a function with the ‘new’ keyword, let’s create a function and invoke it with the ‘new’ keyword, then let’s show what the interpreter does when it sees the ‘new’ keyword. The end results will both be the same.

First let’s create our Constructor.

var Person = function(name, age){   this.name = name;   this.age = age; } 

This is a typical JavaScript constructor function. Now whenever we invoke the Person function using the ‘new’ keyword, ‘this’ will be bound to the newly created object.

Now let’s add a method onto our Person’s prototype so it will be available on every instance of our Person ‘class’.

Person.prototype.sayName = function(){   alert(‘My name is ‘ + this.name); } 

Now, because we put the sayName function on the prototype, every instance of Person will be able to call the sayName function in order alert that instance’s name.

Now that we have our Person constructor function and our sayName function on its prototype, let’s actually create an instance of Person then call the sayName function.

var tyler = new Person(‘Tyler’, 23); tyler.sayName(); //alerts ‘My name is Tyler’ 

So all together the code for creating a Person constructor, adding a function to it’s prototype, creating a Person instance, and then calling the function on its prototype looks like this.

var Person = function(name, age){   this.name = name;   this.age = age; } Person.prototype.sayName = function(){   alert(‘My name is ‘ + this.name); } var tyler = new Person(‘Tyler’, 23); tyler.sayName(); //alerts ‘My name is Tyler’ 

Now let’s look at what actually is happening when you use the ‘new’ keyword in JavaScript. First thing you should notice is that after using ‘new’ in our example, we’re able to call a method (sayName) on ‘tyler’ just as if it were an object - that’s because it is. So first, we know that our Person constructor is returning an object, whether we can see that in the code or not. Second, we know that because our sayName function is located on the prototype and not directly on the Person instance, the object that the Person function is returning must be delegating to its prototype on failed lookups. In more simple terms, when we call tyler.sayName() the interpreter says “OK, I’m going to look on the ‘tyler’ object we just created, locate the sayName function, then call it. Wait a minute, I don’t see it here - all I see is name and age, let me check the prototype. Yup, looks like it’s on the prototype, let me call it.”.

Below is code for how you can think about what the ‘new’ keyword is actually doing in JavaScript. It’s basically a code example of the above paragraph. I’ve put the ‘interpreter view’ or the way the interpreter sees the code inside of notes.

var Person = function(name, age){   //The below line creates an object(obj) that will delegate to the person’s prototype on failed lookups.   //var obj = Object.create(Person.prototype);    //The line directly below this sets ‘this’ to the newly created object   //this = obj;    this.name = name;   this.age = age;    //return this; } 

Now having this knowledge of what the ‘new’ keyword really does in JavaScript, creating a Service in AngularJS should be easier to understand.

The biggest thing to understand when creating a Service is knowing that Services are instantiated with the ‘new’ keyword. Combining that knowledge with our examples above, you should now recognize that you’ll be attaching your properties and methods directly to ‘this’ which will then be returned from the Service itself. Let’s take a look at this in action.

Unlike what we originally did with the Factory example, we don’t need to create an object then return that object because, like mentioned many times before, we used the ‘new’ keyword so the interpreter will create that object, have it delegate to it’s prototype, then return it for us without us having to do the work.

First things first, let’s create our ‘private’ and helper function. This should look very familiar since we did the exact same thing with our factory. I won’t explain what each line does here because I did that in the factory example, if you’re confused, re-read the factory example.

app.service('myService', function($http, $q){   var baseUrl = 'https://itunes.apple.com/search?term=';   var _artist = '';   var _finalUrl = '';    var makeUrl = function(){     _artist = _artist.split(' ').join('+');     _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'     return _finalUrl;   } }); 

Now, we’ll attach all of our methods that will be available in our controller to ‘this’.

app.service('myService', function($http, $q){   var baseUrl = 'https://itunes.apple.com/search?term=';   var _artist = '';   var _finalUrl = '';    var makeUrl = function(){     _artist = _artist.split(' ').join('+');     _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'     return _finalUrl;   }    this.setArtist = function(artist){     _artist = artist;   }    this.getArtist = function(){     return _artist;   }    this.callItunes = function(){     makeUrl();     var deferred = $q.defer();     $http({       method: 'JSONP',       url: _finalUrl     }).success(function(data){       deferred.resolve(data);     }).error(function(){       deferred.reject('There was an error')     })     return deferred.promise;   }  }); 

Now just like in our factory, setArtist, getArtist, and callItunes will be available in whichever controller we pass myService into. Here’s the myService controller (which is almost exactly the same as our factory controller).

app.controller('myServiceCtrl', function($scope, myService){   $scope.data = {};   $scope.updateArtist = function(){     myService.setArtist($scope.data.artist);   };    $scope.submitArtist = function(){     myService.callItunes()       .then(function(data){         $scope.data.artistData = data;       }, function(data){         alert(data);       })   } }); 

Like I mentioned before, once you really understand what ‘new’ does, Services are almost identical to factories in AngularJS.

3) Provider

The biggest thing to remember about Providers is that they’re the only service that you can pass into the app.config portion of your application. This is of huge importance if you’re needing to alter some portion of your service object before it’s available everywhere else in your application. Although very similar to Services/Factories, there are a few differences which we’ll discuss.

First we set up our Provider in a similar way we did with our Service and Factory. The variables below are our ‘private’ and helper function.

app.provider('myProvider', function(){    var baseUrl = 'https://itunes.apple.com/search?term=';   var _artist = '';   var _finalUrl = '';    //Going to set this property on the config function below.   this.thingFromConfig = ‘’;    var makeUrl = function(){     _artist = _artist.split(' ').join('+');     _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'     return _finalUrl;   } } 

*Again if any portion of the above code is confusing, check out the Factory section where I explain what it all does it greater details.

You can think of Providers as having three sections. The first section is the ‘private’ variables/functions that will be modified/set later (shown above). The second section is the variables/functions that will be available in your app.config function and are therefore available to alter before they’re available anywhere else (also shown above). It’s important to note that those variables need to be attached to the ‘this’ keyword. In our example, only ‘thingFromConfig’ will be available to alter in the app.config. The third section (shown below) is all the variables/functions that will be available in your controller when you pass in the ‘myProvider’ service into that specific controller.

When creating a service with Provider, the only properties/methods that will be available in your controller are those properties/methods which are returned from the $get() function. The code below puts $get on ‘this’ (which we know will eventually be returned from that function). Now, that $get function returns all the methods/properties we want to be available in the controller. Here’s a code example.

this.$get = function($http, $q){     return {       callItunes: function(){         makeUrl();         var deferred = $q.defer();         $http({           method: 'JSONP',           url: _finalUrl         }).success(function(data){           deferred.resolve(data);         }).error(function(){           deferred.reject('There was an error')         })         return deferred.promise;       },       setArtist: function(artist){         _artist = artist;       },       getArtist: function(){         return _artist;       },       thingOnConfig: this.thingFromConfig     }   } 

Now the full Provider code looks like this

app.provider('myProvider', function(){   var baseUrl = 'https://itunes.apple.com/search?term=';   var _artist = '';   var _finalUrl = '';    //Going to set this property on the config function below   this.thingFromConfig = '';    var makeUrl = function(){     _artist = _artist.split(' ').join('+');     _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'     return _finalUrl;   }    this.$get = function($http, $q){     return {       callItunes: function(){         makeUrl();         var deferred = $q.defer();         $http({           method: 'JSONP',           url: _finalUrl         }).success(function(data){           deferred.resolve(data);         }).error(function(){           deferred.reject('There was an error')         })         return deferred.promise;       },       setArtist: function(artist){         _artist = artist;       },       getArtist: function(){         return _artist;       },       thingOnConfig: this.thingFromConfig     }   } }); 

Now just like in our factory and Service, setArtist, getArtist, and callItunes will be available in whichever controller we pass myProvider into. Here’s the myProvider controller (which is almost exactly the same as our factory/Service controller).

app.controller('myProviderCtrl', function($scope, myProvider){   $scope.data = {};   $scope.updateArtist = function(){     myProvider.setArtist($scope.data.artist);   };    $scope.submitArtist = function(){     myProvider.callItunes()       .then(function(data){         $scope.data.artistData = data;       }, function(data){         alert(data);       })   }    $scope.data.thingFromConfig = myProvider.thingOnConfig; }); 

As mentioned before, the whole point of creating a service with Provider is to be able to alter some variables through the app.config function before the final object is passed to the rest of the application. Let’s see an example of that.

app.config(function(myProviderProvider){   //Providers are the only service you can pass into app.config   myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works'; }); 

Now you can see how ‘thingFromConfig’ is as empty string in our provider, but when that shows up in the DOM, it will be ‘This sentence was set…’.

vote vote

65

All Services are singletons; they get instantiated once per app. They can be of any type, whether it be a primitive, object literal, function, or even an instance of a custom type.

The value, factory, service, constant, and provider methods are all providers. They teach the Injector how to instantiate the Services.

The most verbose, but also the most comprehensive one is a Provider recipe. The remaining four recipe types — Value, Factory, Service and Constant — are just syntactic sugar on top of a provider recipe.

  • The Value Recipe is the simplest case, where you instantiate the Service yourself and provide the instantiated value to the injector.
  • The Factory recipe gives the Injector a factory function that it calls when it needs to instantiate the service. When called, the factory function creates and returns the service instance. The dependencies of the Service are injected as the functions' arguments. So using this recipe adds the following abilities:
    • Ability to use other services (have dependencies)
    • Service initialization
    • Delayed/lazy initialization
  • The Service recipe is almost the same as the Factory recipe, but here the Injector invokes a constructor with the new operator instead of a factory function.
  • The Provider recipe is usually overkill. It adds one more layer of indirection by allowing you to configure the creation of the factory.

    You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.

  • The Constant recipe is just like the Value recipe except it allows you to define services that are available in the config phase. Sooner than services created using the Value recipe. Unlike Values, they cannot be decorated using decorator.
See the provider documentation.

vote vote

50

Understanding AngularJS Factory, Service and Provider

All of these are used to share reusable singleton objects. It helps to share reusable code across your app/various components/modules.

From Docs Service/Factory:

  • Lazily instantiated – Angular only instantiates a service/factory when an application component depends on it.
  • Singletons – Each component dependent on a service gets a reference to the single instance generated by the service factory.

Factory

A factory is function where you can manipulate/add logic before creating an object, then the newly created object gets returned.

app.factory('MyFactory', function() {     var serviceObj = {};     //creating an object with methods/functions or variables     serviceObj.myFunction = function() {         //TO DO:     };     //return that object     return serviceObj; }); 

Usage

It can be just a collection of functions like a class. Hence, it can be instantiated in different controllers when you are injecting it inside your controller/factory/directive functions. It is instantiated only once per app.

Service

Simply while looking at the services think about the array prototype. A service is a function which instantiates a new object using the 'new' keyword. You can add properties and functions to a service object by using the this keyword. Unlike a factory, it doesn't return anything (it returns an object which contains methods/properties).

app.service('MyService', function() {     //directly binding events to this context     this.myServiceFunction = function() {         //TO DO:     }; }); 

Usage

Use it when you need to share a single object throughout the application. For example, authenticated user details, share-able methods/data, Utility functions etc.

Provider

A provider is used to create a configurable service object. You can configure the service setting from config function. It returns a value by using the $get() function. The $get function gets executed on the run phase in angular.

app.provider('configurableService', function() {     var name = '';     //this method can be be available at configuration time inside app.config.     this.setName = function(newName) {         name = newName;     };     this.$get = function() {         var getName = function() {              return name;         };         return {             getName: getName //exposed object to where it gets injected.         };     }; }); 

Usage

When you need to provide module-wise configuration for your service object before making it available, eg. suppose you want to set your API URL on basis of your Environment like dev, stage or prod

NOTE

Only provider will be available in config phase of angular, while service & factory are not.

Hope this has cleared up your understanding about Factory, Service and Provider.

Top 3 video Explaining dependency injection - AngularJS: Service vs provider vs factory

Related QUESTION?