So far, we've been writing just one type of custom Angular JavaScript component in this book, which is the controller. Controllers are a specialized component type in Angular, as are filters and directives, which we'll cover soon. Angular also supports non-specialized components called services. The definition of a service in Angular is pretty loose, but a common trait is a lack of direct coupling with templates, which suggests kinship with the service layer pattern of classic enterprise architecture.

Angular's core ng module includes a number of built-in services, including $location, $log, $q, and $window, just to name a few. We will explore its $http service in the final chapter of this book, HTTP.

In a typical application, you will define your own services for any behavior that is shared among the specialized JavaScript components you create, such as controllers. Services can be stateful if needed. For example, if you need someplace to store the player's score in a game, you might create a score service in order to be able to retrieve and display the current score in multiple locations across your application. All services are singletons, meaning that no more than one instance of a particular service will exist during the lifetime of an Angular application.

A service in Angular can be an object, a function, or even a primitive; it's up to you. In fact, this chapter will not demonstrate anything more than a few rather simple services, since services can be just about any plain JavaScript. What it will cover is how to register your services with Angular. You do this using functions defined by the $provide service, but proxied by angular.Module. In order to register a service, you need a reference to a module. Let's declare a root application module now.

angular.module('app', []);

As explained in the Modules chapter, we load our application's root module by passing its name to the ng-app directive in our HTML document.

<body ng-app="app">
  <!-- Other examples to be inserted here. -->
</body>

Good, our module is ready.

Confusingly, Angular's $provide service offers five different functions for registering a service. These five functions can be grouped into two general approaches. The first approach is extremely simple. The second is more complicated.

Creating services without dependency injection

You may not need to inject any dependencies into your service. (Dependency injection was covered in the previous chapter. An example of an injected dependency would be the built-in $http service, which your service would use to fetch data from a remote backend.) But even if you don't need to inject your service with dependencies, you must still place it within a module in order to make it available for injection into other components. Being able to inject it is what makes it an Angular service; otherwise, it would just be plain JavaScript.

Change object values,services singletons to capitalized names (Score)? per oreilly book

There are two service functions that let us register services without dependencies: value and constant. The difference between value and constant in Angular is a bit esoteric. A constant is available during the bootstrapping of an Angular application, while a value is not. We won't cover constant in this book.

value

Let's say that we are writing a game in which the player receives a score that begins at 0. Using $provide's value function, we can register a numeric primitive with the name 'score' that will be available to controllers, services, and other components.

angular.module('app')
  .value('score', 0);

We can inject our score service by listing it as a parameter in a controller, as was explained in more depth in the previous chapter, Dependency Injection.

angular.module('app')
  .controller('ScoreController', function($scope, score) {
    $scope.score = score;
    $scope.increment = function() {
      $scope.score++;
    };
  });

The template for this example uses two instances of the ScoreController in order to prove the singleton nature of the score service.

<p ng-controller="ScoreController"> Score: {{score}} </p> <p ng-controller="ScoreController"> <button ng-click="increment()">Increment</button> </p>

I apologize, I have set us up to fail: This example does not work correctly. Clicking the Increment button does not change the value of score displayed by the first controller instance. This is not a scoping issue, but rather just the immutable nature of primitive value services. We can make the example work as intended by switching from the primitive to an object with a points property.

angular.module('app')
  .value('score', {points: 0});

We can use nearly the same controller definition, changing the statement $scope.score++ to $scope.score.points++.

angular.module('app')
  .controller('ScoreController', function($scope, score) {
    $scope.score = score;
    $scope.increment = function() {
      $scope.score.points++;
    };
  });

Similarly, in our template we must change the usages of score to score.points.

<p ng-controller="ScoreController"> Score: {{score.points}} </p> <p ng-controller="ScoreController"> <button ng-click="increment()">Increment</button> </p>

We've just used a service to share mutable data across our entire application. This is a big deal!

In additions to primitives and objects, Angular services can also be functions. Imagine that we need a stateless service that returns a random integer between 1 and 10.

angular.module('app')
  .value('randomScore', function() {
     return Math.ceil(Math.random() * 10);
  });

Injecting our new service is easy. We simply add its name, randomScore, to the parameters list for our controller.

angular.module('app')
  .controller('ScoreController', function($scope, score, randomScore) {
    $scope.score = score;
    $scope.increment = function() {
      $scope.score.points += randomScore();
    };
  });

We've now learned how to define services, and inject them as dependencies into a controller. But what if we also need to inject dependencies into our services?

Creating services with dependency injection

Our game always starts with a score of zero. This is reasonable, but let's say we would like this initial value to be a random number. How can we obtain a reference to the randomScore service when we first create the score object? The value function that we have been using is very simple. Whatever we pass to it is the complete, finished primitive, function, or object that Angular will later inject. Unfortunately, this does not give us any opportunity to inject dependencies.

Angular has a solution for us, of course. More than one, in fact. The first that we will look at is the object-oriented service function.

service

Because JavaScript supports an object-oriented programming style, it is possible to write an Angular service that accepts dependencies via constructor injection. We just need to write a constructor for our score service, rather than instantiate it using an object initializer ({}), as we did above. JavaScript constructors are capitalized, so we will name ours Score. The parameter list for this constructor declares its dependency on the randomScore service.

function Score(randomScore) {
  this.points = randomScore();
}

The service function accepts the constructor of the service rather than the service itself. When Angular later invokes the constructor with the new operator, its dependency injection mechanism will do so with randomScore as an argument.

angular.module('app')
  .service('score', Score);

Service instances created by Angular are lazy, meaning that the instance will only be created when it is a dependency of some component that is being rendered in a template.

factory

If your service is something other than an object, or for some reason you just need more flexibility than is available using an object constructor, you can use factory instead of service. The callback you pass to factory will be injected with any dependencies that you declare as parameters. You can do whatever you want inside it, but in the end it must return the primitive, function, or object that is the service. This type of creation callback is often referred to as a recipe in the official documentation.

angular.module('app')
  .factory('score', function(randomScore) {
     return  {points: randomScore()};
  });

This factory example is equivalent to the constructor and service combination we saw in the previous section.

decorator

If you need to modify an existing service, you can use the $provide service's decorator function. This function is not proxied by angular.Module and must instead be invoked directly on the $provide service. You get a reference to $provide by registering a callback with the config function.

angular.module('app') .config(function($provide) { $provide.decorator('score', function($delegate) { $delegate.points = 1000000; return $delegate; }); });

Your decorator can either return the original service that is passed in as the `` parameter, or a completely new service instance. Be cautious about unintended side-effects, of course!

Encapsulation

Let's say that as a result of abuse of the decorator function, above, we decide to restrict access to the points property. Fortunately, the factory function's injection wrapper provides us with a closure, giving us the opportunity to do some information hiding, or encapsulation.

By replacing the publicly-visible points property with a points variable that is local to the wrapper function, we can protect it from outside modification. The service object will now only expose function properties: an accessor, getPoints; and a restricted mutator, increment.

angular.module('app')
  .factory('score', function(randomScore) {
    var points = randomScore();
    return {
       increment: function() {
         return ++points;
       },
       getPoints: function() {
         return points;
       }
    };
  });

The controller needs to be changed slightly, to delegate increment to the service.

angular.module('app')
  .controller('ScoreController', function($scope, score) {
    $scope.score = score;
    $scope.increment = function() {
      $scope.score.increment();
    };
  });

The template also needs to be changed to bind to score.getPoints().

<p ng-controller="ScoreController"> Score: {{score.getPoints()}} </p> <p ng-controller="ScoreController"> <button ng-click="increment()">Increment</button> </p>

Since the increment method also returns the updated value of points, we can also expose it to the view in an expression. The results may surprise you, however. In the second line of the example above, change score.getPoints() to score.increment(), then click the button a few times. Can you figure out why the score is advancing so rapidly? That's correct: Angular often invokes bound properties and functions quite a few times before the rendering cycle is complete. This is good information to know, both for side-effect scenarios like this one, as well as performance tuning.

Conclusion

This concludes our three-chapter section on Angular's home-grown support for modular programming. It started with the Modules chapter, continued with the short chapter on Dependency Injection, and wrapped up with this chapter's coverage of services. Given that services are just plain old JavaScript, it may strike you as surprising that we needed a chapter on the topic, but we didn't even cover all there is to know. In addition to constant, value, service, factory, and decorator, there is yet a lower-level function, provider, that offers lifecycle hooks for more advanced configuration of your service.

In case you are questioning whether you actually need Angular's help in this area, keep in mind that you don't have to manage your entire codebase the Angular way. In fact, it looks as though Angular 2.0 will transition to ES6 Modules, as signaled by the "RIP angular.module" slide presented in the core team's keynote at ng-europe 2014. Meanwhile, you are only really required to place code in Angular modules when you need to make use of built-in or third-party components that are accessed through dependency injection. An alternative to dependency injection is demonstrated at the end of the previous chapter. Just keep in mind that Angular's unit testing support also leverages dependency injection, so you'll want to be sure to evaluate your usage of that as well.

There are, of course, some specialized components that you must register with Angular's module system, in order to make them available in templates. The filters covered in the next chapter are one example.

I hope you have been enjoying Angular Basics.
You can join the mailing list to hear about updates to the book.
Please also let me know what you liked and what I can improve.
And please share the word using the social buttons below!