AngularJS Service / Factory Tutorial with Example

1. Introduction to AngularJS Services

In AngularJS world, the services are singleton objects or functions that carry out specific tasks. It holds some business logic. Separation of concern is at the heart while designing an AngularJS application. Your controller must be responsible for binding model data to views using $scope. It does not contain logic to fetch the data or manipulating it.

For that we must create singleton objects called services. AngularJS can manage these service objects. Wherever we want to use the service, we just have to specify its name and AngularJS auto-magically inject these objects (more on this later).

Thus service is a stateless object that contains some useful functions. These functions can be called from anywhere; Controllers, Directive, Filters etc. Thus we can divide our application in logical units. The business logic or logic to call HTTP url to fetch data from server can be put within a service object.

Putting business and other logic within services has many advantages. First it fulfills the principle of separation of concern or segregation of duties. Each component is responsible for its own work making application more manageable. Second this way each component can be more testable. AngularJS provides first class support for unit testing. Thus we can quickly write tests for our services making them robust and less error prone.

Consider above diagram. Here we divide our application in two controllers: 1. Profile and 2. Dashboard. Each of these controllers require certain user data from server. Thus instead of repeating the logic to fetch data from server in each controller, we create a User service which hides the complexity. AngularJS automatically inject User service in both Profile and Dashboard controller. Thus our application becomes for modular and testable.

2. AngularJS internal services

AngularJS internally provides many services that we can use in our application. $http is one example (Note: All angularjs internal services starts with $ sign). There are other useful services such as $route, $window, $location etc.

These services can be used within any Controller by just declaring them as dependencies. For example:

module.controller('FooController', function($http){ //... }); module.controller('BarController', function($window){ //... });
Code language: JavaScript (javascript)

3. AngularJS custom services

We can define our own custom services in angular js app and use them wherever required.

There are several ways to declare angularjs service within application. Following are two simple ways:

var module = angular.module('myapp', []); module.service('userService', function(){ this.users = ['John', 'James', 'Jake']; });
Code language: JavaScript (javascript)

or we can use factory method

module.factory('userService', function() { var fac = {}; fac.users = ['John', 'James', 'Jake']; return fac; });
Code language: JavaScript (javascript)

Both of the ways of defining a service function/object are valid. We will shortly see the difference between factory() and service() method. For now just keep in mind that both these apis defines a singleton service object that can be used within any controller, filter, directive etc.

4. AngularJS Service vs Factory

AngularJS services as already seen earlier are singleton objects. These objects are application wide. Thus a service object once created can be used within any other services or controllers etc.

We saw there are two ways (actually four, but for sake of simplicity lets focus on 2 ways that are widely used) of defining an angularjs service. Using module.factory and module.service.

module.service( 'serviceName', function ); module.factory( 'factoryName', function );
Code language: JavaScript (javascript)

When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService(). This object instance becomes the service object that AngularJS registers and injects later to other services / controllers if required.

When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory.

In below example we define MyService in two different ways. Note how in .service we create service methods using this.methodname. In .factory we created a factory object and assigned the methods to it.

AngularJS .service

module.service('MyService', function() { this.method1 = function() { //.. } this.method2 = function() { //.. } });
Code language: JavaScript (javascript)

AngularJS .factory

module.factory('MyService', function() { var factory = {}; factory.method1 = function() { //.. } factory.method2 = function() { //.. } return factory; });
Code language: JavaScript (javascript)

5. Injecting dependencies in services

Angularjs provides out of the box support for dependency management.

In general the wikipedia definition of dependency injection is:

Dependency injection is a software design pattern that allows the removal of hard-coded dependencies and makes it possible to change them, whether at run-time or compile-time. …

We already saw in previous tutorials how to use angularjs dependency management and inject dependencies in controllers. We injected $scope object in our controller class.

Dependency injection mainly reduces the tight coupling of code and create modular code that is more maintainable and testable. AngularJS services are the objects that can be injected in any other Angular construct (like controller, filter, directive etc). You can define a service which does certain tasks and inject it wherever you want. In that way you are sure your tested service code works without any glitch.

Like it is possible to inject service object into other angular constructs, you can also inject other objects into service object. One service might be dependence on another.

Let us consider an example where we use dependency injection between different services and controller. For this demo let us create a small calculator app that does two things: squares and cubes. We will create following entities in AngularJS:

  1. MathService – A simple custom angular service that has 4 methods: add, subtract, multiply and divide. We will only use multiply in our example.
  2. CalculatorService – A simple custom angular service that has 2 methods: square and cube. This service has dependency on MathService and it uses MathService.multiply method to do its work.
  3. CalculatorController – This is a simple controller that handler user interactions. For UI we have one textbox to take a number from user and two buttons; one to square another to multiply.

Below is the code:

5.1 The HTML

<div ng-app="app"> <div ng-controller="CalculatorController"> Enter a number: <input type="number" ng-model="number" /> <button ng-click="doSquare()">X<sup>2</sup></button> <button ng-click="doCube()">X<sup>3</sup></button> <div>Answer: {{answer}}</div> </div> </div>
Code language: HTML, XML (xml)

5.2 The JavaScript

var app = angular.module('app', []); app.service('MathService', function() { this.add = function(a, b) { return a + b }; this.subtract = function(a, b) { return a - b }; this.multiply = function(a, b) { return a * b }; this.divide = function(a, b) { return a / b }; }); app.service('CalculatorService', function(MathService){ this.square = function(a) { return MathService.multiply(a,a); }; this.cube = function(a) { return MathService.multiply(a, MathService.multiply(a,a)); }; }); app.controller('CalculatorController', function($scope, CalculatorService) { $scope.doSquare = function() { $scope.answer = CalculatorService.square($scope.number); } $scope.doCube = function() { $scope.answer = CalculatorService.cube($scope.number); } });
Code language: JavaScript (javascript)

Thus in the above angularjs injected service object to another service and in turn injected final service object to the controller object. You can inject same service object in multiple controllers. As angularjs service object is inheritedly singleton. Thus only one service object will be created per application.

6. End to End application using AngularJS Service

Let us apply the knowledge that we acquired so far and create a ContactManager application. This is the same app that we built-in our last tutorial. We will add a service to it and see how we can divide the code between service and controllers. Following are some basic requirements of this application:

  1. User can add new contact (name, email address and phone number)
  2. List of contacts should be shown
  3. User can delete any contact from contact list
  4. User can edit any contact from contact list

Following is the HTML code which defines a FORM to save new contact and edit contact. And also it defines a table where contacts can be viewed.

6.1 The HTML

<div ng-controller="ContactController"> <form> <label>Name</label> <input type="text" name="name" ng-model="newcontact.name"/> <label>Email</label> <input type="text" name="email" ng-model="newcontact.email"/> <label>Phone</label> <input type="text" name="phone" ng-model="newcontact.phone"/> <br/> <input type="hidden" ng-model="newcontact.id" /> <input type="button" value="Save" ng-click="saveContact()" /> </form> <table> <thead> <tr> <th>Name</th> <th>Email</th> <th>Phone</th> <th>Action</th> </tr> </thead> <tbody> <tr ng-repeat="contact in contacts"> <td>{{ contact.name }}</td> <td>{{ contact.email }}</td> <td>{{ contact.phone }}</td> <td> <a href="#" ng-click="edit(contact.id)">edit</a> | <a href="#" ng-click="delete(contact.id)">delete</a> </td> </tr> </tbody> </table> </div>
Code language: HTML, XML (xml)

Next we add the AngularJS code to and life to our ContactManager application. We define a module ‘app’. This module is then used to create Service and Controller.

See in below code how ContactService is created. It has simple methods to save/delete/get the contact.

Note how the service object in injected in controller.

6.2 The JavaScript

var module = angular.module('app', []); module.service('ContactService', function () { //to create unique contact id var uid = 1; //contacts array to hold list of all contacts var contacts = [{ id: 0, 'name': 'Viral', 'email': 'hello@gmail.com', 'phone': '123-2343-44' }]; //save method create a new contact if not already exists //else update the existing object this.save = function (contact) { if (contact.id == null) { //if this is new contact, add it in contacts array contact.id = uid++; contacts.push(contact); } else { //for existing contact, find this contact using id //and update it. for (i in contacts) { if (contacts[i].id == contact.id) { contacts[i] = contact; } } } } //simply search contacts list for given id //and returns the contact object if found this.get = function (id) { for (i in contacts) { if (contacts[i].id == id) { return contacts[i]; } } } //iterate through contacts list and delete //contact if found this.delete = function (id) { for (i in contacts) { if (contacts[i].id == id) { contacts.splice(i, 1); } } } //simply returns the contacts list this.list = function () { return contacts; } }); module.controller('ContactController', function ($scope, ContactService) { $scope.contacts = ContactService.list(); $scope.saveContact = function () { ContactService.save($scope.newcontact); $scope.newcontact = {}; } $scope.delete = function (id) { ContactService.delete(id); if ($scope.newcontact.id == id) $scope.newcontact = {}; } $scope.edit = function (id) { $scope.newcontact = angular.copy(ContactService.get(id)); } })
Code language: PHP (php)

That’s All Folks

We saw that angularjs service/factory objects are. How to define our own custom service/factory object in angularjs. Also we saw how dependency injection works. In the end we created a simply calculator application that wrap up all the concepts.

I hope you liked this tutorial. Feel free to post your comment below.

In this ongoing series, I will try to publish more AngularJS articles on topics like angularjs $http service, AngularJS filters, AngularJS directives etc.

References

View Comments

  • Some great articles you have posted! Any article that you can refer to display grid with AngularJS service? Thanks!

  • Hi that is great quick start tutorial for AngularJS
    but tell me how i use that AngularJS to persist data in db
    and also tell me how you secure business logic from user side in AngularJS

    • Sorry you cant. This is a client side app framework. Only things which are not too sensitive must be coded in angular. You have the rest of the logic in the server side.
      Client side code can always be viewed in the devtools.
      But you can still make it really tough to understand for the person looking at your code by obfuscating it. Thats all I know!

  • Is there any particular reason not to pass the newcontact directly from the ng-click as a parameter of save()?

    [code]
    <input type="button" value="Save" ng-click="saveContact(newcontact)" class="btn btn-primary" />
    [/code]

    and

    [code]
    $scope.saveContact = function (newContact) {
    ContactService.save(newContact);
    }
    [/code]

    This seems to me to have better reusability and encapsulation. For example, you may want to be able to add a new contact from somewhere else without binding to the single input you already have.

    Anyway, I am honestly curious if there is any particular "Angular" reason to do it the way you did.

    • Also, I realize you clear the $scope.newcontact var after saving... if you use the variation I suggested, you can still do that in the ng-click:

      [code]
      <input type="button" value="Save" ng-click="saveContact(newcontact);newcontact={};" class="btn btn-primary" />
      [/code]

      • I personally consider it a good practice to write minimal code in HTML that's why I support his approach.

  • This is a great tutorial to start with anulgar's service & factory...
    Thanks a lot for giving a sweet & small expample...

  • Hi Viral, Have been following your tutorials on AngularJS. The explanation is very crisp and clear. Please keep posting more tutorials in the future.

  • Thank you for making the tutorial.
    One thing that seems to be missing, and was in fact the reason I read the tutorial, was an answer to the question of when to use a factory vs a service? Can you provide different use cases for when one would be preferable over the other? Seems like a factory could just as easily return a function, which would make it identical to a service (Is this correct).

  • Hi Viral,

    I am newbie to AngularJS and this article has helped me a lot in understanding concepts.

    I am trying to code something like :- I have a dropdown and when I select one value, it should in turn open another drop down and if not, the second dropdown should not be displayed.

    For ex. I have dropdown with values A, B, C and when I select C, I should see another select element with values in it. But when I select A or B, the second select is not visible. How can I achieve this?

    Thanks in advance.

    • You should look at ng-if, ng-show and ng-hide.

      These will allow you to control whether or not the second selection box displays by setting an expression on it, as follows...

      ...

      ng-if will add the element to the dom model if the condition is true. This means if the expression is false, the element does not even exist, so be careful if referencing it from elsewhere.
      ng-show will show the element only if the condition is true, hide when false. The element will always exist in the DOM.
      ng-hide is the exact reverse of show. Shows when the expression is false, hide when true.

      Happy Coding!

  • can you please post an example on using multiple filters with multiple input text boxes in angularjs

Share
Published by
Viral Patel
Tags: angularjs angularjs-service

Recent Posts

  • Java

Java URL Encoder/Decoder Example

Java URL Encoder/Decoder Example - In this tutorial we will see how to URL encode/decode…

4 years ago
  • General

How to Show Multiple Examples in OpenAPI Spec

Show Multiple Examples in OpenAPI - OpenAPI (aka Swagger) Specifications has become a defecto standard…

4 years ago
  • General

How to Run Local WordPress using Docker

Local WordPress using Docker - Running a local WordPress development environment is crucial for testing…

4 years ago
  • Java

Create and Validate JWT Token in Java using JJWT

1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact…

4 years ago
  • Spring Boot

Spring Boot GraphQL Subscription Realtime API

GraphQL Subscription provides a great way of building real-time API. In this tutorial we will…

4 years ago
  • Spring Boot

Spring Boot DynamoDB Integration Test using Testcontainers

1. Overview Spring Boot Webflux DynamoDB Integration tests - In this tutorial we will see…

5 years ago