Click here to Skip to main content
15,867,308 members
Articles / Web Development / HTML

Angular Tutorial - Part 5: Understanding and Implementing Services

Rate me:
Please Sign up or sign in to vote.
4.98/5 (26 votes)
9 Jul 2015CPOL8 min read 38.2K   2.4K   33   8
In this article, we will discuss about the services in Angular.

Introduction

In this article, we will discuss about the services in Angular. We will see how and why services are useful. We will try to use some built in services and create our own service in Angular.

Link to complete series:

  1. Angular Tutorial - Part 1: Introduction to Angular.js
  2. Angular Tutorial - Part 2: Understanding Modules and Controllers
  3. Angular Tutorial - Part 3: Understanding and using Directives
  4. Angular Tutorial - Part 4: Understanding and Implementing Filters
  5. Angular Tutorial - Part 5: Understanding and Implementing Services
  6. Angular Tutorial - Part 6: Building and Validating Data Entry Forms
  7. Angular Tutorial - Part 7: Understanding Single Page Applications and Angular Routing

Background

In our web application, we will always have some business logic and server communication to fetch/save the data to the server. What is the best place to do such kind of things. We could write this code in controller and have a working application but should we write this code in the controller is the question.

There are two major problems if we put our business logic and server communication in the controllers. The first problem is that this piece of functionality will not be reusable, i.e., If we want to reuse some behaviour in other controllers, we will have to rewrite this code. The second problem is from the best practices perspective. If we put all this code in the controllers, then effectively we are violating the single responsibility principle as our controller should only be responsible for populating the $scope properties that are needed by the associated view. Also, there is no separation of concern if we put all the business logic on controller, we will end up having spaghetti code again in our controllers.

So how can we write our code in such a manner that we have a good separation of concerns, i.e., every business logic component is separate from each other and from the controller. Also, how can we use and reuse business logic components from the other parts of the application. The answer to this question is Angular services.

Angular lets us create reusable stateless components that can be used from other parts of the application. These are called services in Angular. A service is a singleton object that can be defined to contain any piece of business logic. They can then be used from other part of the application like controllers, directives, filters and perhaps other services.

So to look at the concept of the services more closely and understand the topic in a much better manner, let us introduce a service in our application. So far, we have created an application that shows a list of books on click of a button.

Image 1

The controller for this app looks as follows:

JavaScript
(function () {

    var booksController = function ($scope, $filter) {
        $scope.message = "List of books";

        $scope.books = [];

        $scope.fetchBooks = function () {
            $scope.books = [
                { ID: 1, BookName: "4 Test Books", AuthorName: "5 Test Author", ISBN: "5 TEST" },
                { ID: 2, BookName: "5 Test Books", AuthorName: "4 Test Author", ISBN: "1 TEST" },
                { ID: 3, BookName: "1 Test Books", AuthorName: "3 Test Author", ISBN: "2 TEST" },
                { ID: 4, BookName: "2 Test Books", AuthorName: "2 Test Author", ISBN: "4 TEST" },
                { ID: 5, BookName: "3 Test Books", AuthorName: "1 Test Author", ISBN: "3 TEST" }
            ];
        }
    }

    angular.module('myAngularApplication').controller('booksController', 
                                            ["$scope", "$filter", booksController]);

}());

What we are doing in the above controller is that we are populating the list of books with some hard coded values. But ideally, they should come from server. Let's say we want to introduce Angular service in this application. In fact, we will create two services for this application. One to get this hard coded list of sample books. The second service will fetch the similar list of books from server using a RESTful API. So let's get started.

Using the Code

Before we start creating the service for our application, let us understand a few basic things.

How to Create a Service

The first thing to remember is that there are four ways to create a service in Angular. Using any of these ways will give us a stateless singleton object that can be used across the application. Which method should be used largely depends on the pattern that we want to follow, what exactly this service is meant for and how we would want to use this service. We will not be discussing or comparing these approaches as that would be digressing from this article (perhaps a later article could cover this). In this article, we will be using the factory method to create our service which is the Angular implementation of factory pattern to create the service object.

What we need to do to create our service class is to use the factory method on the angular module and associate the service function with it. Let's create the skeleton for localBooksService which will return a hard coded list of books to our controller.

JavaScript
(function () {
    var localBooksService = function () {       
    }
    angular.module('myAngularApplication').factory('localBooksService', [localBooksService]);
}());

Now before we could go and write the internal implementation of this service, perhaps we should look at a JavaScript pattern that is used for implementation. It called the Revealing Module Pattern.

Understanding Revealing Module Pattern

From the best practices perspective (also the oops fundamentals), we should always encapsulate the internal implementation into a class and let the user see only the public abstraction. But since we are talking JavaScript here, there is no way we can put access specifier type of things in our service implementation. So how can this be achieved. This can be achieved by using a JavaScript pattern called revealing module pattern.

In this pattern, what we do is that we let the function return an object. So the caller of this function will get the instance of this object. So let's say we will return an object that will contain the list of books.

JavaScript
var localBooksService = function () {
    
    return {
        books: []
    };
}

Right now, this is just an empty array that we are returning. How can we have the actual list of books associated. Since inside this function, we can access the internal variables and functions, why not have this list of books as a function level variable and then return it to the user.

JavaScript
var localBooksService = function () {
    
    var _books = [];

    return {
        books: _books
    };
}

On the same lines, we can also have a function defined inside which can be revealed outside using this return object.

JavaScript
var localBooksService = function () {
    
    var _books = [];

    var _someFunction = function(){
        console.log("This is just a sample function");
    };

    return {
        books: _books,
        someFunction: _someFunction
    };
}

Implementing Our Service

Now with this revealing module pattern, we have achieved some level of encapsulation as the function will only be exposing the object that is being returned and can remain shielded from actual implementation. Let us now move the list of these hard coded books in our localBooksService and look at the implementation of our service.

JavaScript
(function () {

    var localBooksService = function () {
        var _books = [
                { ID: 1, BookName: "4 Test Books", AuthorName: "5 Test Author", ISBN: "5 TEST" },
                { ID: 2, BookName: "5 Test Books", AuthorName: "4 Test Author", ISBN: "1 TEST" },
                { ID: 3, BookName: "1 Test Books", AuthorName: "3 Test Author", ISBN: "2 TEST" },
                { ID: 4, BookName: "2 Test Books", AuthorName: "2 Test Author", ISBN: "4 TEST" },
                { ID: 5, BookName: "3 Test Books", AuthorName: "1 Test Author", ISBN: "3 TEST" }
        ];

        return {
            books: _books            
        };
    }

    angular.module('myAngularApplication').factory('localBooksService', [localBooksService]);

}());

Using the Service

Now that we have the service ready, let's see how we can use it from our controller. The first thing that we need to do is to pass the dependency of this service on our controller in a minification safe manner (this we saw in previous article). And then, we need to use the service to get the list of books instead of hard coded books. Let us see how our controller looks after these changes.

JavaScript
(function () {

    var booksController = function ($scope, $filter, localBooksService) {
        $scope.message = "List of books";

        $scope.books = [];

        $scope.fetchBooks = function () {
            $scope.books = localBooksService.books;
        }
    }

    angular.module('myAngularApplication').controller('booksController', 
                   ["$scope", "$filter", "localBooksService",  booksController]);

}());

Using Angular Built In Service

Angular also comes with a lot of built in services that we can use. A few of them are $location, $window, $resource and $http. We can look at Angular documentation to see what a specific service provides and how we can use them in our application. For this example, let us use the $http service. What we will do is that we will implement another service called remoteBooksService and will use this $http service inside that to fetch the books from the server.

Note: What I have done is that I have created an ASP.NET Web API project that can be used to perform the CRUD operations on a book database located on the server. Please find the API project attached to see the Web API details. Alternatively, we can create a simple REST based service using node or any other technology and in our Angular application, we just need to refer to the URL where that service is hosted.

Let's see how we can use the $http service in our own service. The first thing we need to do is to inject this service in our service. Once this is injected, we can use the get method of $http to retrieve the result from the server. My server API is running at: http://localhost:57386/api/Books.

JavaScript
(function () {

    var remoteBooksService = function ($http) {
        var _fetchBooks = function () {
            return $http.get('http://localhost:57386/api/Books');
        };

        return {
            fetchBooks: _fetchBooks
        };
    }

    angular.module('myAngularApplication').factory('remoteBooksService', ["$http", remoteBooksService]);

}());

Now let's inject this service in our controller and add one more function in our controller that will use this service to get the remote list of books. $http.get returns a promise and since we are directly returning that promise from our service, our controller needs to handle that promise and populate the list of books.

JavaScript
(function () {

    var booksController = function ($scope, $filter, localBooksService, remoteBooksService) {
        $scope.message = "List of books";

        $scope.books = [];

        $scope.fetchBooks = function () {
            $scope.books = localBooksService.books;
        }

        $scope.fetchBooksFromServer = function () {

            remoteBooksService.fetchBooks()
            .success(function (data, status, headers, config) {
                $scope.books = data;
            })
            .error(function (data, status, headers, config) {
                $scope.books = [];
                $scope.error = "Failed to retrieved items from server";
            });
        };
    }

    angular.module('myAngularApplication').controller('booksController', 
         ["$scope", "$filter", "localBooksService", "remoteBooksService",  booksController]);

}());

Now if we run the application and click on the fetch from remote, we will get the books list from the server.

Image 2

Note: The above shown approach to use the $http service is rather crude as our main focus was on looking at how we can use the service and create our own service that is using other services. The ideal solution for using $http would involve using the $Q defer API which I strongly recommend reading about. We will not be talking about it here as it's not in the scope of this article.

Point of Interest

In this article, we looked at the concept behind services in angular. We looked at how we can implement our own service and how we can reuse the built in Angular service by looking at an example usage of $http service. This has been written from a beginner's perspective. I hope this has been informative.

History

  • 10th July, 2015: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
PraiseVery good, simply explained article Pin
Prasad Bagade13-Nov-17 19:27
Prasad Bagade13-Nov-17 19:27 
Praise:) Pin
Member 1124779614-Jun-17 9:26
Member 1124779614-Jun-17 9:26 
Thank you so muchThumbs Up | :thumbsup:
Generalrecent implementation of angularjs don't work with code in sample Pin
Member 1246246120-Mar-17 8:06
Member 1246246120-Mar-17 8:06 
QuestionEncapsulation Pin
asfaya20-May-16 0:35
asfaya20-May-16 0:35 
GeneralMy vote of 5 Pin
D V L17-Mar-16 8:22
professionalD V L17-Mar-16 8:22 
BugExcellent series, but trouble with the downloads Pin
Member 119078503-Dec-15 10:55
Member 119078503-Dec-15 10:55 
QuestionUpload rest articles. Pin
Er Daljeet Singh14-Jul-15 20:27
professionalEr Daljeet Singh14-Jul-15 20:27 
GeneralMy vote of 5 Pin
Santhakumar Munuswamy @ Chennai10-Jul-15 21:58
professionalSanthakumar Munuswamy @ Chennai10-Jul-15 21:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.