AngularJS Providers, Factories and Services

Angular Services

Angular relies heavily upon objects that it refers to as Services. An Angular Service is a singleton object that can be injected into other Angular components (other Services, Controllers, Directives, Filters, etc).

Services may be defined and registered in a number of ways using Angular’s Module interface. The Module interface offers the functions, provider, factory and service for service definition. (There are other service definition functions on this interface, but they’re of less interest here.) Each of these functions is used in a manner that the Angular documentation refers to as a recipe, with each offering varying degrees of sophistication and configurability.

The $provider Service can be used to register Services after Angular’s configuration phase, however we normally only require the Module interface.

Provider

Module.provider() offers the greatest flexibility in defining and registering a Service. Module.factory() and Module.service() wrap and simplify Module.provider() to achieve their results.

Here’s an example of a Pony Service defined and registered using Module.provider().

var Pony = function(ponyColour, FoodService) {
    // ...
};

var ponyModule = angular.module('ponyModule');

ponyModule.provider('Pony', function() {
    var colour = 'pink';

    this.setColour = function(value) {
        colour = value;
    };

    this.$get = ['Cheese', function(Cheese) {
        return new Pony(colour, Cheese);
    }];
};

After creating an Angular module named ponyModule, the above code defines and registers an Angular Service Provider which is used to create the Pony Service. The Service Provider is responsible for constructing and returning the Angular Service instance of Pony from its $get() factory function. Notice that the Pony service is also injected with the Cheese service (defined elsewhere).

The Provider method of creating a Service is overkill in most circumstances, but it is useful to understand Service creation in it’s more fundamental form. Only use this technique when a Service is used by more than one application and requires application-specific configuration during Angular’s module configuration phase.

In the above code, a pony’s colour may be overridden by calling the setColour() function (defined on the Provider object instance) during Angular’s configuration phase. Angular makes the Provider instance available to us by appending the word Provider to the Service name – PonyProvider in our case. The Provider instance can then be injected into the application’s configuration function:

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

app.config(['PonyProvider', function(PonyProvider) {
  PonyProvider.setColour('blue');
  // ...
});

Incidentally, the Provider instance itself can be injected with other Service Provider instances during Angular’s configuration phase, in much the same manner that dependency injection is performed on a Service.

Factory

Module.factory() offers the next most sophisticated way to define and register a Service. Using this technique, only the Provider’s $get() factory function is defined and registered:

ponyModule.factory('Pony', ['Cheese', function(Cheese) {
  return new Pony('blue', Cheese);
}]);

Here Service configurability (during Angular’s configuration phase) has been sacrifised in order to simplify Service registration.

Service

Module.service is the simplest technique for defining and registering a Service:

ponyModule.service('Pony', ['Cheese', function(Cheese) {
  this.colour: 'blue',
  // ...
}]);

Angular will call new on the Service constructor function for us. Slightly more configurability has been lost again, though the Service definition and registration is simpler. In the above use of Module.service() we have set a Pony‘s colour within the Module.service() function.

How flexible you require Service configuration will likely drive which of the above three techniques you employ. Module.service will likely be sufficient for defining and registering the Services used by most applications.

Object Oriented JavaScript – Quick Reference

Object Definition and Creation

Constructor-based Creation

var Example = function(val) {
    this.foo = val;
}

var example = new Example('something');

// Although it's unusual to see to this technique, new instances of
// Example may be created using Example's built-in constructor property:
var anotherExample = new example.constructor('something else');

JSON-based Creation

var example = {
    foo: 'something'
};

Non-shared Member Attributes

var Example = function() {
    // Each instance of Example gets its own copy of the foo() function.
    this.foo = function() { ... };
};

Shared Member Attributes

var Example = function() {};

// Add a shared foo() function attribute to all past and future instances
// of Example.
Example.prototype.foo = function() { ... };

Note that when declaring a shared function on an object’s prototype, any constructor-scoped varaibles will not be accessible from within the shared function – e.g. foo, declared inside the Example constructor function, will not be directly available from within foo().

Function Access to the Parent ‘this’

var Example = function() {
    var that = this;
    this.foo = '';

    var bar = function(val) {
        // Because inner functions have their own 'this' attribute, the
        // parent object's 'this' attribute is obscured. A common
        // workaround is to assign 'this' to a variable (conventionally
        // named 'that' at parent scope:
        that.foo = val;
    }
 };

Object Inheritance

JavaScript is a very flexible language and although it does not have the classical inheritance mechanisms of, say, Java and C++, there are a number of commonly used JavaScript idioms that are used to provide object inheritance. Two common techniques are shown below.

Start with a base object, Animal:

var Animal = function() { ... };
Animal.prototype.getLegCount = function() { ... };

Prototype Chaining

var Cat = function() { ... };
Cat.prototype.meow = function() { ... };

// Prototype chaining allows Cat to inherit from Animal.
Cat.prototype = new Animal();

// New instances of Cat are created using the ‘new’ operator.
var fluffy = new Cat();

Parasitic Inheritance

var Dog = function() {
    var that = new Animal();

    // parasitic extension of Animal...
    that.woof = function() { ... };

    return that;
};

// New instances of Dog are created using the 'new' operator.
var spot = new Dog();

Because the `Dog` constructor function returns an object, the new operator will use that object as its result, assigning it to the variable spot, above (see Step 9 of Construct in ECMAScript Language Specification).