Monday, May 26, 2014

AngularJS for Beginners: Service


What is Service?
Service is a simple object that can do some specific tasks. Angular service is stateless in general. Since having properties indicates some sort of state, the public members of a service should be functions instead of properties. Each service encapsulates some sort of functionality or contains some business logic.

Services are singleton objects. It means they are instantiated only once for an app. Services are lazy loaded (created only when necessary). So, service is a stateless singleton object that contains some useful functions. Components like Controllers, Directive and Filters etc. can use the functions of a service.

Why Service is used
Services follow two important object oriented design principles: 1. Single Responsibility Principle (SRP) and 2. Dependency Inversion Principle (DIP).

The Single Responsibility Principle states that every object should have a single responsibility. We can use the example of a controller here. The responsibility of a controller is to bind model data to views using the scope. It should not contain the logic to fetch or update the data. If a controller is also responsible for fetching and updating data, this is the violation of the SRP principle. Data fetching or manipulation logic or any other business logic should be implemented in a separate service. That service can be injected into a controller or any other component afterwards.

Dependency Injection follows the Dependency Inversion Principle. The DIP states that objects should depend on abstractions, not concretions. In JavaScript, we can consider any parameter of a function (constructor function or other) as an abstraction because any object can be passed in for that parameter. This is how dependency injection is used in AngularJS. The controllers, directives, filters and other services can take in any external dependencies (i.e. services) as parameters during construction. This makes the code loosely coupled and each component becomes more manageable and testable.  

How Service is created
There are five different Angular module’s methods for creating custom services:
  • factory()
  • service()
  • constant()
  • value()
  • provider()
I will cover the first two of them.

Factory method:
The most common and quick way to create a custom service is to use the module’s factory method:
 var myModule = angular.module('myModule', []);  
 myModule.factory('myService', function() {  
   var serviceInstance = {}; 
 
   // .................  

   return serviceInstance;  
 });  
In the above code, we have created a custom service named ‘myService’. The first parameter of the factory method represents the name our service, and the second parameter represents a function. The object ‘serviceInstance’ returned by that function will become our custom service. In this example, an empty object is returned, so our service does not do anything now. However, it is now registered with the AngularJS app using the name ‘myService’. Let’s add some functionality to our service:
 var myModule = angular.module('myModule', []);  
 myModule.factory('myService', function() {  
   var serviceInstance = {}; 
 
   serviceInstance.task1 = function() {  
      // ..............  
   }  

   serviceInstance.task2 = function() {  
      // ..............   
   } 
 
   return serviceInstance;   
 });  

Service method:
If we want to create a custom service using a constructor function, we can use module’s service method:
 var myModule = angular.module('myModule', []);  
 myModule.service('myService', function() { 
 
   this.task1 = function() {  
      // ..............  
   }  

   this.task2 = function() {  
      // ..............   
   }  

 });  
In the above code, we have created a custom service named ‘myService’. The first parameter of the service method represents the name our service, and the second parameter represents the constructor function. The service method will use the new keyword when the service instance will be created. The keyword this is used to define the functions of our service here.

How service is used
If we want to use a service for a component, we have to identify it as a dependency for that component. Here a component can be a controller, a directive, a filter or another service. All we have to do is to inject the service by adding it as a parameter in the definition of the component.

To inject a service in a controller, we have to pass the name of the service as a parameter to the controller function:
 var myModule = angular.module('myModule', []);  
 myModule.controller('myController', function($scope, myService) {  
   myService.task1();  
   myService.task2();       
 }  
Here the service 'myService' is injected in the controller 'myController'. Now we can execute any methods that we define in our service 'myService'.

Built-in Service
AngularJS provides many built-in services that can be used in our application. For example, $http is a built-in service. AngularJS built-in services start with a $ sign. The other useful services are $route, $window, $location etc.

The built-in services can be used by declaring them as dependencies i.e. injecting them as parameters (like the same way used for custom services): 
 var myModule = angular.module('myModule', []);  
 myModule.controller('myController', function($scope, $http) {  
   //...  
   $http.get(...);       
 });  
Here the $http service is injected in the controller 'myController'

Complete example
Here is the complete example:
 <!DOCTYPE html>  
 <html ng-app="myModule">  
 <head>  
    <title>Learning AngularJS</title>  
    <script src="angular.min.js"></script>  
 </head>  
 <body>  
      <div ng-controller="BooksController">  
           <br>  
           List of books:  
           <br>                  
           <ul>  
                <li ng-repeat="book in bookList">  
                     {{book.name}} -- {{book.author | uppercase}}   
                </li>  
           </ul>  
           Book name: <input type="text" ng-model="bookName" />  
           Author: <input type="text" ng-model="bookAuthor" /> <br>  
           <button ng-click="add()">Add</button>  
      </div>  
        
      <script>        
           var myModule = angular.module('myModule', []);       
             
           myModule.factory('myService', function () {  
                var bookList = [  
                     {name:'The Tempest',   
                          author:'William Shakespeare'},  
                     {name:'Gitanjali',   
                          author:'Rabindranath Tagore'},  
                     {name:'Harry Potter',   
                          author:'J. K. Rowling'},  
                     {name:'The Da Vinci Code',   
                          author:'Dan Brown'},  
                     {name:'A Brief History of Time',   
                          author:'Stephen Hawking'},  
                     {name:'Tell Me Your Dreams',   
                          author:'Sidney Sheldon'}  
                ];  
                  
                var serviceInstance = {};  
                  
                serviceInstance.getBooks = function () {  
                     return bookList;  
                };  
                  
                serviceInstance.addBook =   
                     function (bookName, bookAuthor) {  
                          bookList.push({   
                               name: bookName,   
                               author: bookAuthor   
                          });  
                     };  
                  
                return serviceInstance;                 
           });            
             
             
           myModule.controller('BooksController',   
                function BooksController($scope, myService) {  
             
                     $scope.bookList = myService.getBooks();  
                  
                     $scope.add = function() {  
                          myService.addBook(  
                               $scope.bookName,   
                               $scope.bookAuthor  
                          );  
                     };  
           });                      
       </script>  
 </body>  
 </html>  
The output will be same as our previous post:



[TOC]    << Previous    Next >>

No comments:

Post a Comment