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 >>

Sunday, May 18, 2014

AngularJS for Beginners: Module

Module can be considered as a container for different components like controllers, services, filters, directives etc. In all our previous examples, we used global namespace for declaring components such as controllers. This is not a good idea to use global namespace since it can cause collisions which are difficult to debug. Instead, we should use module to keep the global namespace clean. The benefit of using module is it makes unit testing easier by testing relevant modules only. 

An application can have several modules. Each module should contain code that implements a specific functionality. The modules of an application can be loaded in any order.  

The recommended way of creating multiple modules for an application:
  • A module for each feature.
  • A module for each reusable component (especially directives and filters).
  • An application level module which depends on the above modules and contains any initialization code.

Declaring a Module
We can declare a module using the angular.module() API method. We have to pass two parameters to the method. The first one is the name of the module. The second one is the list of dependencies. Here is the method signature: 
angular.module('name', [dependencies]);

This is the application of dependency injection. One module may rely on other modules or components to get data. For example, we can create a module without any dependency like the following:
var myModule = angular.module(' myModule ', []);

If the module 'myModule' relies on another module 'requiredModule', the declaration will become:

var myModule = angular.module('myModule', ['requiredModule']);

Creating a Controller in a Module
Here is how we can create a controller in a module:
 var myModule = angular.module('myModule', []);       
 myModule.controller('BooksController', function BooksController($scope)   
 {  
      // controller tasks will be defined below 
           
 });  
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.controller('BooksController',   
           function BooksController($scope) {  
                $scope.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'}  
                ];  

                $scope.add = function() {  
                     $scope.bookList.push({   
                          name: $scope.bookName,   
                          author: $scope.bookAuthor   
                     });  
                };  
           });
                      
       </script>  
 </body>  
 </html>   
The output will be same as our previous post:


[TOC]    << Previous    Next >>



Monday, May 12, 2014

AngularJS for Beginners: Scope, Controller

In AngularJS, a Controller is a JavaScript constructor function. This is used to add additional functionality to the scope of the view.

Scope
Now, what is Scope? Scope is an object that refers to the application model data. Scope is the object that works as the "Glue" between View and Controller. It holds the model data that is required to pass to the view. So, Scope is basically a kind of ViewModel.

When a new controller is created, AngularJS passes it a new child Scope object. This is available as a parameter ($scope) to the controller's constructor function.  AngularJS does this by using dependency injection here. A simple Controller function will look like the following:
    function MessageController($scope) {   
       $scope.textMsg = "Hello!";   
    }   
Controllers can be used in 2 ways: 1. Setting up the initial state of the $scope object. 2. Adding behavior to the $scope object.

Setting up the initial state of the $scope object
To set up initial state of a scope, we attach properties to the $scope object. The properties contain the view model. Let's use the same controller MessageController we have created in our previous example. Here we attach a property textMsg which contains a string value to the $scope:
    function MessageController($scope) {   
       $scope.textMsg = "Hello!";   
    }   
Each controller will be registered or attached to a template (view).  HTML elements (DOM) written with Angular-specific elements and attributes are called templates. All the $scope properties will be available to the template that the controller is registered. The 'ng-controller' directive is used to attach a controller to the view. See the following example:
      <div ng-controller=" MessageController ">  
            {{ textMsg }}  
      </div>  
In the above example, the controller MessageController is registered with the DOM element <div>. Therefore, the textMsg property is data-bound to the <div>.

In AngularJS, we can set any type including object on the $scope and show the object’s properties in the view. For example, let's create a person object with a single attribute name and set the $scope of our MessageController:
      function MessageController($scope) {  
           $scope.person = { name: "James" };  
      }  
We can access this person object in any child element of the <div> where the MessageController is registered. We can simply reference person.name in our view like the following:
      <div ng-controller=" MessageController ">  
            Hello {{ person.name }}  
      </div>  

Adding behavior to the $scope object
We have to add behavior to the scope in case of handling any event or executing any computation in the view. Behavior can be added to the scope by attaching functions to the $scope object. These functions then become available to be called from the template in which the controller is registered.  Here is an example of a controller that adds two methods to the scope:
      function CalulationController($scope) {  
           $scope.add = function(value) {   
                return value + 2;   
           };       
           $scope.subtract = function(value) {   
                return value - 2;   
           };       
      }  
If we attach the CalulationController to a <div>, the add and subtract methods can be invoked in the Angular expressions like the following:
      <div ng-controller=" CalulationController">  
            5 plus 2 is equal to {{ add(5) }}  
           <br>  
            5 minus 2 is equal to {{ subtract(5) }}            
      </div>  

ng-click
In order to specify custom behavior when a DOM element (button, link etc.) is clicked, the ng-click directive is used. The ng-click directive can bind the click event of the DOM element with any function specified in the $scope. Look at the following controller example:
      function CalulationController($scope) {  
           $scope.result = 0;  
           $scope.add = function(value) {   
                $scope.result += value;   
           };  
           $scope.subtract = function(value) {   
                $scope.result -= value;   
           };       
      }       
Let's attach the CalulationController to a <div> which contains two buttons. The click event of the buttons can be bound the scope functions add and subtract like the following:
      <div ng-controller="CalulationController">  
           <button ng-click="add(5)">Add 5</button>  
           {{ result }}  
           <br>  
           <button ng-click="subtract(5)">Subtract 5</button>  
           {{ result }}  
      </div>  

A small example
Here is a small example with the things we have learnt in this post:
 <!DOCTYPE html>  
 <html ng-app>  
 <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>             
           function BooksController($scope) {  
                $scope.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'}  
                ]; 
 
                $scope.add = function() {  
                     $scope.bookList.push({   
                          name: $scope.bookName,   
                          author: $scope.bookAuthor   
                     });  
                };  
           }                      
       </script>  
 </body>  
 </html>  

We should see something like the following in the browser:





If a new book name and author name is entered and Add button is clicked, the entry will be added in the list.

[TOC]    << Previous    Next >>