Go back | Day 1

The short guide to service definitions

One of the most misunderstood components of Angular that beginners often ask is about the differences between the service(), factory(), and provide() methods. This is where we'll start the twenty-five days of Angular calendar.

The Service

In Angular, services are singleton objects that are created when necessary and are never cleaned up until the end of the application life-cycle (when the browser is closed). Controllers are destroyed and cleaned up when they are no longer needed.

This is why we can't dependably use controllers to share data across our application, especially when using routing.Services are designed to be the glue between controllers, the minions of data, the slaves of functionality, the worker-bees of our application.

Let's dive into creating service. Every method that we'll look at has the same method signature as it takes two arguments

  • name - the name of the service we're defining
  • function - the service definition function.

Each one also creates the same underlying object type. After they are instantiated, they all create a service and there is no functional difference between the object types.

factory()

Arguably the easiest way to create a service is by using the factory()method.

The factory() method allows us to define a service by returning an object that contains service functions and service data. The service definition function is where we place our injectable services, such as $http and $q.

angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
  var backendUrl = "http://localhost:3000";
  var service = {
    // our factory definition
    user: {},
    setName: function(newName) { 
      service.user['name'] = newName; 
    },
    setEmail: function(newEmail) {
      service.user['email'] = newEmail;
    },
    save: function() {
      return $http.post(backendUrl + '/users', {
        user: service.user
      });
    }
  };
  return service;
});

Using the factory() in our app

It's easy to use the factory in our application as we can simply inject it where we need it at run-time.

angular.module('myApp')
.controller('MainCtrl', function($scope, User) {
  $scope.saveUser = User.save;
});

When to use the factory() method

The factory() method is a great choice to use to build a factory when we just need a collection of methods and data and don't need to do anything especially complex with our service.

* We cannot use the factory() method when we need to configure our service from the .config() function.*

service()

The service() method, on the other hand allows us to create a service by defining a constructor function. We can use a prototypical object to define our service, instead of a raw javascript object.

Similar to the factory() method, we'll also set the injectables in the function definition:

angular.module('myApp.services')
.service('User', function($http) { // injectables go here
  var self = this; // Save reference
  this.user = {};
  this.backendUrl = "http://localhost:3000";
  this.setName = function(newName) {
    self.user['name'] = newName;
  }
  this.setEmail = function(newEmail) {
    self.user['email'] = newEmail;
  }
  this.save = function() {
    return $http.post(self.backendUrl + '/users', {
      user: self.user
    })
  }
});

Functionally equivalent to using the factory() method, the service() method will hold on to the object created by the constructor object.

Using the service() in our app

It's easy to use the service in our application as we can simply inject it where we need it at run-time.

angular.module('myApp')
.controller('MainCtrl', function($scope, User) {
  $scope.saveUser = User.save;
});

When to use the service() method

The service() method is great for creating services where we need a bit more control over the functionality required by our service. It's also mostly guided by preference to use this instead of referring to the service.

* We cannot use the service() method when we need to configure our service from the .config() function.*

provide()

The lowest level way to create a service is by using the provide() method. This is the only way to create a service that we can configure using the .config() function.

Unlike the previous to methods, we'll set the injectables in a defined this.$get() function definition.

angular.module('myApp.services')
.provider('User', function() {
  this.backendUrl = "http://localhost:3000";
  this.setBackendUrl = function(newUrl) {
    if (url) this.backendUrl = newUrl;
  }
  this.$get = function($http) { // injectables go here
    var self = this;
    var service = {
      user: {},
      setName: function(newName) {
        service.user['name'] = newName;
      },
      setEmail: function(newEmail) {
        service.user['email'] = newEmail;
      },
      save: function() {
        return $http.post(self.backendUrl + '/users', {
          user: service.user
        })
      }
    };
    return service;
  }
});

Using the provider() in our app

In order to configure our service, we can inject the provider into our .config() function.

angular.module('myApp')
.config(function(UserProvider) {
  UserProvider.setBackendUrl("http://myApiBackend.com/api");
})

We can use the service in our app just like any other service now:

angular.module('myApp')
.controller('MainCtrl', function($scope, User) {
  $scope.saveUser = User.save;
});

When to use the provider() method

The provider() method is required when we want to configure our service before the app runs. For instance, if we need to configure our services to use a different back-end based upon different deployment environments (development, staging, and production).

It's the preferred method for writing services that we intend on distributing open-source as well as it allows us to configure services without needing to hard-code configuration data.

The code for this entire snippet is available here.

Hope you enjoyed today's snippet. Stay tuned for tomorrow's and sign up for the newsletter for great Angular content every week.

Enjoy this snippet?

Check out our book that's heading to print this week at ng-book.com

The 600+ page book is packed full of Angular content written and designed to get you up to speed with Angular from beginner to expert.

Independently published with content just like what you've just read.

Brought to you by the team behind ng-newsletter