Custom Services

In the previous chapters we’ve learned about the builtin-services of AngularJS. In this tutorial we learn how to make components of our applications better reusable and readable by encapsulating them in services. They prevent us from having to much duplicate code in our controllers.

Controllers are, for memory consumption reasons, created whenever they are used and in the opposite removed, when they are no longer used. Services, in contrast, are singletons. They remain instantiated and can be used by different controllers, while the AngularJS-application keeps running.

AngularJS comes with five different types of services:

  • Constant
  • Value
  • Factory
  • Service
  • Provider

The first four of them are derived from the provider-object, providing certain simplifications, about which we will learn later in this tutorial. Note, that in this tutorial we set the variablenames to what kind of service-type they are (i.e. postsFactory), this is only for educational purpose, you should not name them like this in productive-code!

Constant

Constants can be used to define variables, which cannot be changed during the lifetime of an application. You can define them whenever you like, but the most obvious place is on the application-startup. The following example defines and consumes the PERSON-constant:

Example

var app = angular.module('app', []);
app.constant('PERSON', 'Miles Davis');
app.controller('myController', myController);
    
function myController($scope, PERSON)
{
	$scope.myConstant = PERSON;
}

Play with example »

Value

Values are almost the same as constants but with the slight difference, that they can be changed after their definition.

Example

var app = angular.module('app', []);
app.value('Person', 'Miles Davis');
app.controller('myController', myController);
    
function myController($scope, Person)
{
	$scope.myValue = Person;
}

Play with example »

Factory

Instead of duplicating code in our controllers, we can encapsulate this logic in factories. This makes our code better read-, maintain- and testable. Good candiates for factories are i.e. REST-service calls. The following example shows how to encapsulate the posts-RESTservice from the resource-tutorial in a factory with the name postsFactory:

Example

app.factory('postsFactory', function($resource){
	return $resource('http://jsonplaceholder.typicode.com/posts/', {});              
});

To use the postsFactory, we need to pass it to the controller, so that Angular can inject it for us.

app.controller('ctrl', ['$scope', 'postsFactory', function($scope, postsFactory) {
	$scope.loadPosts = function() {
		$scope.postings = postsFactory.query();
	};   
}]);

Play with example »

Service

Services are very similar to factories with the difference, that they return an instance of themselves, which means, we can access variables defined within service. The following example demonstrates this, by assigning the fullName-variable to the $scope.

Example

app.service('personService', function(){
	this.fullName = 'Miles Davis';              
});
        
app.controller('PostingsCtrl', ['$scope', 'personService', function($scope, personService) {
	$scope.personFullname = personService.fullName;
}]);

Play with example »

When to use factories, when services and when providers?
There are many discussion around this in the internet. The official AngularJS-documentation recommends us to use a factory if possible. One good reason to follow this recommondation is, that you can hide implementation-details from the factory-user, if you define "private"-variables. In case we need to configure a service on startup, we will use a provider, which is explained below.

Provider

The last kind is the plain provider-service. It is the most complex of all services, but it is the only one, which is configurable! The following example shows, how we can configure a variable on the application-startup with app.config. Note that you need to append "Provider" on the service-name you pass into the app.config!

Example

app.provider('dataService', function() {
	var url = 'not configured'
	return {
		setBaseUrl: function(value) {
			url = value;
		},
		$get: function() {
			return {
				getBaseUrl: function() {
					return url;
				}
			}
		}
	}
});
        
app.config(function(dataServiceProvider){
	dataServiceProvider.setBaseUrl('http://server/service/...');
});
        
app.controller('ctrl', ['$scope', 'dataService', function($scope, dataService) {
	$scope.dataServiceUrl = dataService.getBaseUrl();
}]);

Play with example »

Summary

Services are really great. Your code becomes automatically more readable, maintainable and testable! At first it might be confusing, that there are so many different kinds of services available, especially regarding factory and services! Consider to just use factories whenever possible, as recommended by the original AngularJS documentation!