(Comments)
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
// 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.
// 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.
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:
// 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'); }
// 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.
We develop web applications to our customers using python/django/angular.
Contact us at hello@cowhite.com
Comments