15

I am just starting out with Angular. Reading the example of a service in the Google documentation, I just wonder why you would choose to use a service rather keeping the variables and function right in the controller?

angular.
 module('MyServiceModuleDI', []).
 factory('notify', function($window) {
    var msgs = [];
    return function(msg) {
      msgs.push(msg);
      if (msgs.length == 3) {
        $window.alert(msgs.join("\n"));
        msgs = [];
      }
    };
  });

function myController($scope, notify) {
  $scope.callNotify = function(msg) {
    notify(msg);
  };
}

When would you choose to use a service in this case?

p0pps
  • 586
  • 1
  • 4
  • 13

5 Answers5

31

In my opinions the main reasons are:

  • Persist and share data between Controllers.
    I.E: You create a service that fetchs data form a database, if you store it inside a controller, once you change to another Controller the data will be discarded (unless you store it in the $rootScope but this is not the best way to do it) , but if you keep it inside a service (services are singletons), the data will persist when you change controllers.

  • Abstract data access logic by creating an API that will be used by your controllers/directives/services.
    Keep business logic inside Controllers and data logic inside services.

  • DRY (Don't repeat yourself).
    I.E: You have a series of functions that you need in different controllers, without the service you would have to repeat your code in each controller, with a service you can create a single API for this functions and inject it in every Controller/Directive/Service you need.

Here is an example:

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


//Here is the service Users with its functions and attributes
//You can inject it in any controller, service is a singleton and its data persist between controllers
myApp.factory('Users', function () {

    //data logic
    //fetch data from db and populate...
    var name = "John";
    var surname = "Doe" 

    function getName() { return name; }
    function getFullName() { return name + ' ' + surname; }
    function setName(newName) { name = newName; }

    //API
    return {
        getName: getName,
        getFullName: getFullName,
        setName: setName
    }
});

//An Util service with methods I will use in different controllers   
myApp.factory('Util', function () {

    //a bunch of useful functions I will need everywhere
    function daysInMonth (month,year) {
        return new Date(year, month+1,0).getDate();
    }

    return {
        daysInMonth: daysInMonth    
    };
});   

//Here I am injecting the User and Util services in the controllers   
myApp.controller('MyCtrl1', ['$scope', 'Users', 'Util', function ($scope, Users, Util) {

    $scope.user = Users.getFullName(); //"John Doe";
    Users.setName('Bittle');

    //Using Util service
    $scope.days = Util.daysInMonth(05,2013);
}]);

myApp.controller('MyCtrl2', ['$scope', 'Users', 'Util', function ($scope, Users, Util) {

    $scope.user = Users.getFullName(); //"Bittle Doe"; //The change that took place in MyCtrl1 hhas persisted.

}]);
Bertrand
  • 13,540
  • 5
  • 39
  • 48
  • this helped me - but how can I call a service function within a view with ng-click for instance? $scope functions work, but service functions don't …. ? – trainoasis Feb 11 '14 at 14:01
  • 1
    Yes, but the scope is the entry door. [Here is a JSBin](http://jsbin.com/picat/1/edit) with two examples, one is calling a service method and the other is using the service directly. Because functions are objects and in Javascript objects are passed around by reference, $scope.Users creates a reference to the Users service and makes it available in the view, the same for $scope.sayHello. – Bertrand Feb 13 '14 at 10:56
  • Thank you, very nice example – trainoasis Feb 13 '14 at 12:45
  • Im just not sure how factory function works with sayHello: sayHello. What if I had plenty of functions in there? – trainoasis Feb 13 '14 at 13:12
  • 1
    I figured it out: but unfortunately I need to change some $scope variables (for ng-show) in this factory, so this is not handy in this case – trainoasis Feb 13 '14 at 13:23
  • 2
    The factory is using the [module pattern](http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html), put inside the service's returned object the methods you want to make public, [see example](http://jsbin.com/picat/4/edit). – Bertrand Feb 13 '14 at 13:26
8

Based on my experience, services come in handy in the following scenarios:

  1. When you wish to share information between two or more controllers
    One may use $rootScope to also communicate between controllers, but as the common pitfalls section of the documentation suggests, it should be avoided as much as possible since it is a global scope. Using services,we can define setter and getter methods that can be easily used to exchange data between controllers.

  2. When a functionality is to be used multiple times
    Lets say that you have a functionality which repeats across all the templates that you have - say something in which you need to repeatedly convert the currency from USD to Euro and display the amount to the user. Here you can assume the "amount" to be anything from Purchasing Flight tickets, buying some books online - anything money related.
    This functionality will be used across all your templates to display the amount always in Euro to the customer - but in your database / model, the amount is stored in Euro.
    Thus, you can create a service that converts the amount from USD to Euro. Any controller can call it and use it. Your functionality is now located in one single place instead across controllers. So, in the future if you decide to make changes and display the amount in Pounds, you need to make the change only in one location and it will be reflected across all the controllers making use of it.

There are some other use cases but only these currently come to my mind right now. The most frequent use case that I find using services myself is point #1 - passing data between controllers.

callmekatootie
  • 10,989
  • 15
  • 69
  • 104
2

When you want to keep a variable in memory (why not, a user session for instance) during navigation (differents partials with diffents controller are called). You have to keep in mind :

  • Controllers are re-initialized each time you call them.

  • Services are constructed only one time and are always available. So you can persist any information you need.

vpoulain
  • 740
  • 1
  • 7
  • 18
1

Apart from the benefits listed above, it also helps you divide your application structure into independent components, which make it more understandable and testable as well.

Imagine having to test similar functionality at multiple places rather than having it defined/debugged at a central location and used elsewhere (multiple times).

akskap
  • 803
  • 6
  • 12
0

Also remind Angular services are singleton objects(it is very important so we can share it easily through project) which get instantiated only once during the lifetime of an application. They contain methods that maintain data throughout the life of an application, i.e. data does not get refreshed and is available all the time. The main objective of a service is to organize and share business logic, models, or data and functions with different components of an Angular application.