AngularJS – Service VS Factory VS Provider

Design pattern is very important if you want to build a manageable and scalable application. In AngularJS, we could develop module, which is also regarded as a dependency, for specific feature and it could be injected to the controller whenever it is needed. This dependency injection design help us to build clean and well structured application and reduce redundant code.

There are different ways to create the dependency. Most common terms are service, factory and provider which are all singleton and you can find a lot of discussion online about their differences, when and how to use them. Here are some notes which summarize the AngularJS documentation about writing Provider.
 

 

1. When a dependency is injected to the controller, the injector from AngularJS framework will register a recipe such that the injected controller could make use of the type provided by the dependency.
 

2. They are 5 different kinds of recipes which are:

  • Provider recipe
  • Value recipe
  • Factory recipe
  • Service recipe
  • Constant recipe

 

3. Provider recipe is the most verbose and comprehensive. It is the fundamental recipe to build dependency. The other 4 recipes are just syntactic sugar on top of the Provider recipe.
 

4. The following section will look into each recipe and give more thorough details.
 

 

Value recipe

The simplest way to create dependency. Since it is the simplest one, we could only provide a string from it.

Example: Build a module such that it could provide the controller a client id.
index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <title>AngularJS Value Recipe Example</title>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
  <script src="js/main.js"></script>
</head>
<body>
  <div ng-controller="MainController">
    I need to know the client id and it is {{ clientId }}.
  </div>
</body>
</html>

 

js/main.js

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

// Create a dependency called clientId
app.value('clientId', 'abc1234567890')

app.controller('MainController', ['$scope', 'clientId', function MainController($scope, clientId) {
  $scope.clientId = clientId;
}]);

 

 

Factory recipe

While Value recipe only provides a string literal, Factory recipe could do exactly the same.
js/main.js

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

// Create a dependency called clientId
// app.value('clientId', 'abc1234567890')
app.factory('clientId', function clientIdFactory() {
  return 'abc1234567890';
});

app.controller('MainController', ['$scope', 'clientId', function MainController($scope, clientId) {
  $scope.clientId = clientId;
}]);

 

As you can see, we could use the return keyword to provide the string literal to the controller. We could also provide any type to the controller including:

  • Primitive type including integer, string literal…
  • Object literal
  • Function
  • Instance of a custom type

 

Much more than that, Factory recipe is more powerful compared to Value recipe because:

  • Ability to use other services (have dependencies)
  • Allow logical operation before return (initialization)
  • Allow delay/lazy loading (not to be covered in this post – reference)

 

Example: Build a dependency called apiToken which provides the controller the token and it depends on the clientId dependency.
index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <title>AngularJS Factory Recipe Example</title>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
  <script src="js/main.js"></script>
</head>
<body>
  <div ng-controller="MainController">
    I need to know the api token and it is {{ apiToken }}.
  </div>
</body>
</html>

 

js/main.js

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

// Create a dependency called clientId
app.value('clientId', 'abc1234567890')

// Create a dependency called apiToken which depends on clientId
app.factory('apiToken', ['clientId', function apiTokenFactory(clientId) {
  // Initialization before return
   var encrypt = function(data1, data2) {
    // NSA-proof encryption algorithm:
    return (data1 + ':' + data2).toUpperCase();
  };

  var secret = 'this_is_the_secret_string';
  var apiToken = encrypt(clientId, secret);

  // This factory provides you the apiToken
  return apiToken;
}]);

app.controller('MainController', ['$scope', 'apiToken', function MainController($scope, apiToken) {
  $scope.apiToken = apiToken;
}]);

 

 

Service recipe

In the Factory recipe, we could inject any type to the controller including instance of custom type. This is very useful for developers who would like to stick on Object Oriented Programming. Let’s say we have defined a Counter.

function Counter(apiToken) {
  this.apiToken = apiToken;
  this.count = 0;

  this.inc = function() {
    this.count++;
  }

  this.dec = function() {
    this.count--;
  }
}

 

We could use the Factory recipe to return a counter instance together with the new keyword.

// Create a dependency called counter which depends on apiToken
app.factory('counter', ['apiToken', function counterFactory(apiToken) {
  return new Counter(apiToken);
}]);

 

When we need to inject a new instance of a custom type, we could use Service recipe which follows a design pattern called Constructor Injection. The Service recipe is a bit simpler as depicted below.

// Create a dependency called counter which depends on apiToken
// app.factory('counter', ['apiToken', function counterFactory(apiToken) {
//   return new Counter(apiToken);
// }]);
app.service('counter', ['apiToken', Counter]);

 

Example: Build a dependency called counter which depends on apiToken and provide the instructor a instance of Counter.
index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <title>AngularJS Service Recipe Example</title>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
  <script src="js/main.js"></script>
</head>
<body>
  <div ng-controller="MainController">
    I should have a counter which has been counted 3 times. (Count = {{ count }})
  </div>
</body>
</html>

 

js/main.js

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

// Counter
function Counter(apiToken) {
  this.apiToken = apiToken;
  this.count = 0;

  this.inc = function() {
    this.count++;
  }

  this.dec = function() {
    this.count--;
  }
}

// Create a dependency called clientId
app.value('clientId', 'abc1234567890')

// Create a dependency called apiToken which depends on clientId
app.factory('apiToken', ['clientId', function apiTokenFactory(clientId) {
  // Initialization before return
   var encrypt = function(data1, data2) {
    // NSA-proof encryption algorithm:
    return (data1 + ':' + data2).toUpperCase();
  };

  var secret = 'this_is_the_secret_string';
  var apiToken = encrypt(clientId, secret);

  // This factory provides you the apiToken
  return apiToken;
}]);

// Create a dependency called counter which depends on apiToken and provide a instance of Counter
app.service('counter', ['apiToken', Counter]);

app.controller('MainController', ['$scope', 'counter', function MainController($scope, counter) {
  counter.inc();
  counter.inc();
  counter.inc();
  counter.inc();
  counter.dec();
  $scope.count = counter.count;
}]);

 

 

Provider recipe

Provider recipe is the most powerful recipe but in most cases, the other recipes are good enough so using Provider recipe will be too much. The only use case of Provider recipe is when you want to build a dependency which is used in multiple applications and you want to allow application-wide configuration of the dependency before it is injected to the controller.

Example: Build a dependency called counter which depends on apiToken and provide the constructor an instance of Counter. But unlike the Service recipe example, we could decide the initial count value of the counter in the app.config().
index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <title>AngularJS Provider Recipe Example</title>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
  <script src="js/main.js"></script>
</head>
<body>
  <div ng-controller="MainController">
    I should have a counter which has been counted 10 + 3 times . (Count = {{ count }})
  </div>
</body>
</html>

 

js/main.js

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

// Counter
function Counter(apiToken, count) {
  this.apiToken = apiToken;
  this.count = count;

  this.inc = function() {
    this.count++;
  }

  this.dec = function() {
    this.count--;
  }
}

// Create a dependency called clientId
app.value('clientId', 'abc1234567890')

// Create a dependency called apiToken which depends on clientId
app.factory('apiToken', ['clientId', function apiTokenFactory(clientId) {
  // Initialization before return
   var encrypt = function(data1, data2) {
    // NSA-proof encryption algorithm:
    return (data1 + ':' + data2).toUpperCase();
  };

  var secret = 'this_is_the_secret_string';
  var apiToken = encrypt(clientId, secret);

  // This factory provides you the apiToken
  return apiToken;
}]);

// Create a dependency called counter which depends on apiToken and provide a instance of Counter
// The counter instance is configurable on application level
app.provider('counter', function CounterProvider() {
  // Default count is zero without app level configuration
  this.initialCount = 0;

  // Setter for configuration in app.config()
  this.setInitialCount = function(count) {
    this.initialCount = count;
  }

  // Define the connterFactory in the this.$get
  this.$get = ['apiToken', function counterFactory(apiToken) {
    return new Counter(apiToken, this.initialCount);
  }];
})

// Application level configuration for the counter provider
app.config(['counterProvider', function(counterProvider) {
  counterProvider.setInitialCount(10);
}]);

app.controller('MainController', ['$scope', 'counter', function MainController($scope, counter) {
  counter.inc();
  counter.inc();
  counter.inc();
  counter.inc();
  counter.dec();
  $scope.count = counter.count;
}]);

 

First we modified the Counter constructor so it now takes a count as the second input parameter.

Second, we define the counter Provider recipe which defines the setter for app.config() and also the counterFactory in this.$get method. This method is a factory function just like the one we used in Factory recipe.

Finally, we configure the initialCount in the app.config() so the injected counter will start counting from 10 instead of the default 0. You can comment the app.config() part and see what happens to the injected counter.

 

Constant recipe

From the Provider recipe example, we could configure the dependency in app.config(). It is regarded as the configuration phase inside the AngularJS application life cycle which is executed before the run phase. In the configuration phase, the app has no idea about other dependencies. For example, the following example WILL NOT WORK.

// Create a dependency called initialCount
app.value('initialCount', 100);

...

// Application level configuration for the counter provider
app.config(['counterProvider', 'initialCount', function(counterProvider, initialCount) {
  counterProvider.setInitialCount(initialCount);
}]);

 

That means we got to have some dependencies which are available for both configuration and run phases and that’s why we have the Constant recipe. The following example works as expected.

// Create a constant dependency called initialCount which is available for both configuration and run phases
app.constant('initialCount', 100);

...

// Application level configuration for the counter provider
app.config(['counterProvider', 'initialCount', function(counterProvider, initialCount) {
  counterProvider.setInitialCount(initialCount);
}]);

 

Done =)

References:
Advertisements

4 thoughts on “AngularJS – Service VS Factory VS Provider”

  1. This is the best way of explanation so far found in Internet for the title Factory vs Service vs Provider. Thank u so much.

    I am a beginner in Angular js and very curious to know? What is the difference from above example? With respect to example posted, even new keyword can return us the instance of Counter from Factory (ie return new Counter(apiToken); ). Then whats that Service role. Even Service returns same instance of Object like how Factory returned.

    It would be really helpful if you could share me the explanation using JSFIDDLE demo.
    If I am not wrong both Factory & Service mentioned above are giving us same instance of COUNTER. And these are just two different methodology that can be used in our application.

    Am i Correct. Correct me.

    Like

    1. In my opinion, factory and service actually could serve the same purpose but just the syntax is different. Both of them will return a singleton. It is more about the context which determines whether u should use a factory or service.

      In the following example, i got 2 controllers and both of them need the counter and display the count value. since it is a singleton, both controllers will share the same counter. In this case, i will use service

      But if i want individual counter for different controllers, i would use a counter factory (which is a singleton) and ask for a new instance of counter.

      This is what my preference and my interpretation on how to use them, but there exists other way of explanations and usages. hope it helps. =)

      Like

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s