AngularJS Services Dissected

AngularJS services are functions or objects that can hold behavior or state throughout application. They are used to implement shared behavior/reusable logic which can be used by other components in your AngularJS application. AngularJS services are singletons, means each service is instantiated only once, so each part of our application gets access to the same instance of the AngularJS service. AngularJS services are lazily instantiated, means Angular only instantiates a service when an application component who depends on it [another service, controller or directive e.g.], gets loaded.

Do note that AngularJS services are different than AngularJS controllers. Controllers are created and destroyed several times while navigating to different views, but services are instantiated only once and then reused everywhere in application.

Common use of Services : Communicating with Server, Repeated behavior, Reusable business logic, application-level stores, shared state, etc.

AngularJS services & Dependency Management

The whole AngularJS service concept is driven by AngularJS Dependency Injection system. Any service can be injected into another service, controller or directive, by just declaring it as a dependency, and AngularJS will do the rest.

AngularJS Built-in services

$log, $window, $location, $http are few examples of built-in services. A built-in AngularJS service name starts with $. For complete list, check out the AngularJS documentation.

The ‘Service’ word in AngularJS is bit overloaded. To avoid confusion, we should talk in terms of Provider. A Provider means someone who provides a value-added service to accomplish something. In AngularJs, The value, factory, service, constant, and provider methods are all Providers. They provide instructions to AngularJS about how to instantiate the different type of services. What differentiate them from each other is there intention & role in application. All the providers are instantiated only once, means they are all singletons. We will see all of them in detail.

An AngularJS service can be implemented as a factory, service, or provider. Choosing specially between factory and provider depends on your coding style and preference.

1. Factory

A Factory is created using module.factory function. It is useful if you follow a functional style of programming and you prefer to return functions and objects.

<html ng-app="myApp">
  <head>  
    <title>Factory Demo</title>  
  </head>
  <body ng-controller="AppController as ctrl">
   
    <label>Name :</label><input type="text" ng-model="ctrl.name" placeholder="Enter your name"/><br/><br/>  
 
    <span ng-bind="ctrl.message"></span> <br/><br/>  
 
    <button ng-click="ctrl.hello()"> Hello Message </button>  
    <button ng-click="ctrl.bye()"> Bye Message </button>  
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js">
    </script>  
    <script>
        angular.module('myApp',[])
        .factory('GreetingService', [function() {
            return {
                    sayHello : function(name) {
                          return "Hello " + name;
                     },
                    sayBye : function(name) {
                          return "Bye " + name;
                     }
            }
        }])
        .controller('AppController', ['GreetingService', function(GreetingService) {
             var self = this;
             self.name='';
             self.message='';
             self.hello = function() {
                  self.message = GreetingService.sayHello(self.name);
             };
         
             self.bye = function(name) {
                  self.message = GreetingService.sayBye(self.name);
             };
         
        }]);  
        </script>
  </body>
</html>

Live Demo

In this case, service definition function of factory returns an object [with two methods that can be invoked], which becomes the public API for our service.

2. Service

A Service is created using module.service function. It is useful if you follow a Class/OO style of programming, where we define classes and types instead of functions and objects. With service, the function definition is actually a class/type, and AngularJS calls new on it to create an instance of it. But remember. only one instance will be created, as we know that AngularJS services are singletons.

<html ng-app="myApp">
  <head>  
    <title>Factory Demo</title> 
    <style>body{font-family:"Arial";background-color:#E2E2DC}</style> 
  </head>
  <body ng-controller="AppController as ctrl">
   
    <label>Name :</label><input type="text" ng-model="ctrl.name" placeholder="Enter your name"/><br/><br/>  
 
    <span ng-bind="ctrl.message"></span> <br/><br/>  
 
    <button ng-click="ctrl.hello()"> Hello Message </button>  
    <button ng-click="ctrl.bye()"> Bye Message </button>  
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js">
    </script>  
    <script>
        angular.module('myApp',[])
          .service('GreetingService', [function() {
                this.sayHello = function(name) {
                    return "Hello " + name;
                };
                     
                this.sayBye = function(name) {
                    return "Bye " + name;
                };
        }])
        .controller('AppController', ['GreetingService', function(GreetingService) {
             var self = this;
             self.name='';
             self.message='';
             self.hello = function() {
                  self.message = GreetingService.sayHello(self.name);
             };
         
             self.bye = function(name) {
                  self.message = GreetingService.sayBye(self.name);
             };
         
        }]);  
        </script>
  </body>
</html>

Live Demo

Take special note that our service definition function is now a JavaScript class function. It doesn’t return anything. AngularJS will perform new GreetingService() (with possible dependencies injected in) , cache it, and then return that instance to all components that depends on GreetingService. Note that since new was used to instantiate the service, the keyword this is valid and refers to the instance.

Interestingly, nothing changes in Controller’s code and in HTML compare to previous Factory example. Only difference between these two examples are use of Factory vs Service or i can say ‘return from function’ vs ‘new service’.

3. Provider

Creating an AngularJS Service using provider is not a very common approach, but comes handy when you want to provide a configuration for your service before it can be used. A provider is used to create a configurable service object. In this approach you usually provide the service configuration using module.config function. Provider includes a $get function which gets executed in run phase. It is the return value from the $get function [the service which you configured based on your requirement] that will be cached and injected when the service is requested.

<html ng-app="myApp">
  <head>  
    <title>Service Demo</title> 
    <style>body{font-family:"Arial";background-color:#E2E2DC}</style> 
  </head>
  <body ng-controller="AppController as ctrl">
   
    <label>Name :</label><input type="text" ng-model="ctrl.name" placeholder="Enter your name"/><br/><br/>  
 
    <span ng-bind="ctrl.message"></span> <br/><br/>  
 
    <button ng-click="ctrl.hello()"> Hello Message </button>  
    <button ng-click="ctrl.bye()"> Bye Message </button>  
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js">
    </script>  
    <script>
    function MessagingService(queueType) {
        
        this.getQueueType = function() {
            return queueType;
        };
        
        this.sayHello = function(name) {
            return "Hello " + name +", Sent using "+ queueType;
        };
                     
        this.sayBye = function(name) {
            return "Bye " + name +", Sent using "+ queueType;
        };
      
    } 
    
    angular.module('myApp',[])
        .provider('MessagingService', function() {
              var env='';
              this.setEnvironment = function(environment) {
                  env = environment;
              };
              // This function gets any injected dependencies, not the provider above.
              this.$get = [function() {
                  var queueType = '';
                  if (env==='DEVELOPMENT') {
                      queueType = 'activeMq';
                  }else{
                      queueType = 'WebSphereMq';
                  }
                  return new MessagingService(queueType);
              }];
        })
        .config(['MessagingServiceProvider', function(MessagingServiceProvider) {
            //Set the environment to a different value to see different behavior.
            MessagingServiceProvider.setEnvironment('DEVELOPMENT');
            //MessagingServiceProvider.setEnvironment('UAT');
        }])
        .controller('AppController', ['MessagingService', function(MessagingService) {
             var self = this;
             self.name='';
             self.message='';
             self.hello = function() {
                  self.message = MessagingService.sayHello(self.name);
             };
         
             self.bye = function(name) {
                  self.message = MessagingService.sayBye(self.name);
             };
         
        }]);  
        </script>
  </body>
</html>

Live Demo

In above provider setup, we have a provider with a set function, which can be used in module.config function to set some configuration. This updated configuration will eventually be used while creating the actual service instance. This instance will be created and returned via $get function. It’s the output from $get which will be injected into our controller.

4. Constant & Value

Angular provides us ways to define data that remains globally available while not really polluting the global namespace. Constant and Values are our options to define globally available data, which can be injected as a dependency into other service or controller.

Constant & Value are similar with few differences:

– A constant can be injected everywhere. The Value of a constant is not meant to be changed, and should never be changed.

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

app.constant('PI', 3.14);

app.controller('AppController', ['PI', function(PI) {
    var self = this;
    self.r = 2;
    
    self.getArea = function(){
        return PI * r * r;
    }
}]);

– a Value can be changed. Unlike Constant, A value can not be injected into config phase of application.

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

app.value('loggedinUser', 'SAM');

app.controller('AppController', ['loggedinUser', function(loggedinUser) {
    var self = this;
    self.message = 2;
    
    self.printMessage = function(){
        return 'Welcome '+loggedinUser;
    }
}]);

In above Value example, loggedinUser remain same for all the session, so it’s a good candidate to be declared as VALUE.

That’s it. In the next post AngularJS $http service example-server communication, we will develop a full-fledged live example for server communication using $http service. Stay tune.