Understand AngularJS services

Understand AngularJS services Banner

AngularJS have 5 few ways to create service in AngularJS:
provider(); factory(); service(); value(); constant()
If you don’t know different then it’s better to reed official documentation or go through my notes. The point is to choose method consciously.

Before new service can be created AngularJS should know about this service. Service previously registered by $provide function.

Provider

So, the most fundamental method of create the service is:

$provide.provider().

app.config(function($provide){
     $provide.provider('testService', function() {
        this.$get = function(){
            var title = 'Project';
            return {
                title: title
            };
        }
    });
});

Working snippet on CodePen.

The benefit of this function is ability of configure this service in module.
app.config() with injected $provide function.

Also we can create provider directly from the module object and example of configuration some parameters.

app.provider('testService', function(){  
     this.titleId  = 1;
     this.$get = function(){
          var title = 'Project #' + this.titleId;          
          return {
               title: title
          };       
     }     
});
app.config(function(testServiceProvider){
     testServiceProvider.titleId = 2;
});

Working snippet on CodePen.

Instead of injecting the provide service in config - inject the testServiceProvider. (“Provider” automatically appends the name of the service).

Factory and Service

Investigating AngularJS core we can find factory() and service () function.
And it looks like just wrappers around provider() function.

https://github.com/angular/angular.js/blob/v1.5.x/src/auto/injector.js

Let’s compare factory() example:

app.factory('testService', function(){  
  return {
    testList: function(){
      return ['item1', 'item2', 'item3']
    }
  }
});
app.controller('TestController', function(testService, $scope) {
    $scope.testList = testService.testList();
});

with service() example:

app.service('testService', testService);
function testService() {
  TestServiceBase.call(this);    
  this.testList = function(id) {
    return ['item1 ' + this.version(id), 
            'item2 ' + this.version(id), 
            'item3 ' + this.version(id)];
  }  
}
function TestServiceBase() {}
TestServiceBase.prototype.version = function(id){ 
     return "version #" + id;
}
testService.prototype = Object.create(TestServiceBase.prototype);
app.controller('TestController', function(testService, $scope) {
    $scope.testList = testService.testList(2);
});

(working snippet of factory on CodePen)
(working snippet of service on CodePen)

As you see, difference between service and factory is that the function you passed to the service method will be treated as a constructor function and called with the JavaScript “new” operator. So, service() is better for inheritance.

Example of service can be pretty complicated. I will put here the same server of getting testList as simple as possible (CodePen).

app.service('testService', function(){
  this.testList = function() {
    return ['item1 ', 'item2 ', 'item3 '];
  }  
});

Value and Constant

Constant service — simply register service with injector. The only of functions here that is not wrapper of provider() function.

Constant is good for storing static data and can be injected in module configuration function and can’t be overwritten.

app.constant('constants', {
     APP_TITLE: 'Project',
     APP_VERSION: '1'
});
app.config(function(constants){
  console.log(constants.APP_TITLE);
});

Working snippet on CodePen.

Value — is shorthand of factory function. Good for use if you have nothing to inject. Value service can store functions with attributes.

app.value('testService', {
  retrieveVersion: function(version) {
    var status;
    if (version == 3) {status = 'alpha';}
    else if (version == 2) {status = 'stable';} 
    else if (version == 1) {status = 'legacy';}
    else {status = 'unknown';}
    return status;
  }
});

Working snippet on CodePen.

Using services

Using services in controllers or another services looks the same.
We inform injector what services to inject with dependency annotation.

DA as function parameter names (the simplest) 
(you can find example in any CodePen snippet above)

app.controller('TestController', function(testService) {
     console.log(testService);
});

DA as inline array annotation (good for minification)

app.controller('TestController', ['testService', function(testService) {
     console.log(testService);
}]);

With inject method

app.controller('TaskController', function(testService){
     console.log(testService);
}.$inject = ['testService'])

Summary

It’s better to create service with technique that is better match requirement for service functionality and it’s destination.

  • Provider — when we need to configure it dynamically in config function.

  • Factory — as a simple, regular service

  • Service — when we need to inherit something.

  • Value — when we don’t need any injections and have no dependency.

  • Constant — as a storage of values.

Thanks for great tutorial by Brice Wilson — AngularJS Services In-depth
It was the main inspiration for this article.

September 21, 2016

Artem Deikun

Artem Deikun