Difference between service and a factory in angularjs (With use cases)

(Comments)

Introduction

If you are a novice in angular and just starting out, then you might be confused by service and factory in angular. Even if you have been using angular in the past, then most probably one of the question peeving you must be the difference between service and factory and when to use them correctly. The forums and groups on angular are also filled with these questions, and although many reply, hardly any reply quenches our need to understand the difference between them. Today I'll try to explain and point out the differences between them.


Since the difference between them is so small and since if I just explain the difference then the blog would end before it fills even the smallest of the screens out there, I will also include the different use cases of factory/service in angular, which would enable us to milk every drop of potential from this very powerful feature of angular.


Lets start with the mandatory coding style or syntax for each first, before getting down the nitty gritty of the difference between them



Factory:

// Javascript
angular.module('myApp.view1', [])

    .factory('view1Factory', function () {
        var factory = {
            property1: 'value1',
            property2: 'value2',

            method1: function (){
                // do something here
                return 'some value';
            }
        };

        return factory;
    }

    .controller('View1Ctrl', ['$scope', 'view1Factory', function($scope, view1Factory) {
        $scope.property1 = view1Factory.property1; // value1
        $scope.property2 = view1Factory.property2; // value2

        $scope.somevalue = view1Factory.method1(); // some value
    }

Why do we return something? Why the variable factory? Lets get to that later, after we see the coding style for a typical service.



Service:

// Javascript
angular.module('myApp.view1', [])

    .service('view1Service', function () {
        this.property1 = 'value1';
        this.property2 = 'value2';

        this.method = function (){
                // do something here
                return 'some value';
            }
    }

    .controller('View1Ctrl', ['$scope', 'view1Service', function($scope, view1Service) {
        $scope.property1 = view1Factory.property1; // value1
        $scope.property2 = view1Factory.property2; // value2

        $scope.somevalue = view1Factory.method1(); // some value
    }

Right of the bat, you can see the obvious differences and sorry to dissapoint you but that's all the difference there is technically (if you think about it). Ok let me explain.


In services we can make use of the keyword this. We can use this this because what we define in a service is actually a body of factory instance. So essentially both of them are similar with service just being a convenience method that makes our code a bit shorter and cleaner.


This makes sense because if you check the source for a service in angular its just an instance of a factory:

// Javascript
function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
        return $injector.instantiate(constructor);
    }]);
}

The factory is said to be much versatile than a service, but you could do everything you could do in a factory using a service, if you declare a service like a factory and it would work just fine (it may break the code in some rare cases but never personally encountered such a situation, at least in most common cases).


Let me clarify something, I do not endorse using services like a factory nor do I myself do so, and this maybe just a hack albeit a very useless one, but just stating the fact.



Use cases

Now that we have cleared that out, lets see the ways we could use a factory and a service.


The most obvious and widely used use case for a service is to get, post or interact with a rest api.

// Javascript
angular.module('myApp.view1', [])

    .service('view1Service', function ($http) {
        this.getEmails = function getEmails() {
            return $http.get('/emails');
        };
    }

    .controller('View1Ctrl', ['$scope', 'view1Service', function($scope, view1Service) {
        $scope.mails = {};

        $scope.getMails = function(){
            view1Service.getEmails()
                .then(function success(response){
                        //do something
                        $scope.mails = response.data;
                    }, function error(response){
                        //do something
                    })
        }
    }

You could do this using a factory too but you would not be able to use this keyword and would have had to make an object with getEmails as its property (or method) and return it, as in the factory declaration above. But this is what service is essentially for, to reduce lines of code.


So the question arises when to use a factory? Well in all other cases where the return value is not an object, viz, closures, or creating constructors/instances ,etc.


Let me give you examples of both below:



Closures:

// Javascript
angular.module('myApp.view1', [])

    .factory('view1Factory', function ($http) {
        return function (someList){
            return function (someValue) {
                someList.forEach(function(item){
                    //Do something with 'somevalue' and 'item'
                });
            };
        };
    }

    .controller('View1Ctrl', ['$scope', 'view1Factory', function($scope, view1Factory) {
        var myFactory = view1Factory([{...},{...}]);
        var closure = myFactory('somevalue');
    }



Creating Instances:

// Javascript
angular.module('myApp.view1', [])

    .factory('view1Factory', function () {
        function Person(){
            this.first_name = 'First';
            this.last_name = 'Last';

            this.change_first_name = function (first_name) {
                this.first_name = first_name;
            };

            this.name = function () {
                return this.first_name + ' ' + this.last_name;
            };
        }

        Person.prototype.reverse_name = function () {
            return this.last_name + ' ' + this.first_name;
        };

        return Person;
    })

    .controller('View1Ctrl', ['$scope', 'view1Factory', function($scope, view1Factory) {
        var person1 = new view1Factory();
        var person2 = new view1Factory()

        person1.change_first_name('NewFirst');

        $scope.person1 = person1; // --> first_name: 'NewFirst',  last_name: 'Last'
        $scope.person2 = person2; // --> first_name: 'First',  last_name: 'Last'
    }


As you can see above, we can create prototype methods in factories and they are registered and also you could create it in any controller. Since the factory is singleton, it would reflect in the whole app, but the person is instantiated with the keyword new everytime so each of them would be different, each time you instantiate. So in other words this factory now returns a class and its properties and methods, which can be changed and accessed from across the app. To register new prototype method in a controller or anywhere outside the factory, we can do the following:

// Javascript   
.controller('SomeCtrl', ['$scope', 'view1Factory', function($scope, view1Factory) { // for controllers of other modules don't forget to add dependency to the module to access the factory
    view1Service.prototype.name_no_space = function () {
        return this.first_name+this.last_name;
    };
}

Note :This name_no_space() function will be available anywhere in the app only when the controller(if added in a controller) is run at least once. In usual cases this would mean accessing the page with the controller at least once. This applies if created in any other location (other than a controller), too.



Conclusion

  • You will get only one instance of factory and service across the app since both of them are singletons.
  • Service is just a convenience method that lets us code less when we have to return a object literal.
  • Factory can be used much more powerfully with great flexibility.

Comments

Recent Posts

Archive

2019
2018
2017
2016
2015
2014

Tags

Authors

Feeds

RSS / Atom