Introduction
Pretty quickly after working through the basic exercises available on many sites, I hit upon the need for providers to clean things up and prevent a fat controller. This is done via injection, which is a great idea as it decouples the code, the entity being injected in to can use the stuff the provider provides without being aware of how the provider implements the functionality. Injection has the added benefit of making unit tests easier to achieve in isolation as you can inject mock services. One of the things I am less keen on is the way the names of the providers are often used, which had me confused at best, I’ve seen the following all under the umbrella terms “services” or “providers”:
- Service – Which caused some of the confusion, when someone is saying service do they mean provider?
- Factory – Very like a service, the differences and similarities between service and factory is what this article is about
- Provider – All the other services (except value) are recipes over provider – so provider is the most flexible and complex way of declaring a provider.
- Constant – Which aren’t constant as you can modify them, but you do use these where you want to inject values
- Value – Are very like constants, but are used without injection
I’ll try to keep to the convention of using “Provider” to cover all these – the angular docs does this and I won’t be covering a “provider” providers.
At some point I intend to write a longer article investigating each of these, the main thrust of this article is the difference between service and factory, as I couldn’t find any description of this my poor little brain could process. If you are looking for an introduction to services, then you are going to have to look elsewhere, there are lots of very good articles around. If you want to cut to the chase, click here to go to the fundamental difference between service and factor
Testing the Differences
I’ve created a test harness which is the most basic angular app I could manage – the code outputs to console so you’ll need to open developer tools in your browser if you copy-paste into an html file. The code is not meant to be well written, but is hopefully easy to understand in one chunk.
A Service Provider
<!DOCTYPE html>
<html ng-app="myModule">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
</head>
<body>
<div ng-app="myModule" ng-controller="myController">
<h1>The relevant info is in the console</h1>
</div>
<script>
angular.module('myModule',[])
.service('myProvider', function (){
this.method = function(){
console.log('myProvider method called');
};
})
.controller('myController',function($scope,myProvider){
myProvider.method();
});
</script>
</body>
</html>
The most relevant code is that in italics – the service
‘s anonymous function is an object constructor function. The output is as expected, ‘myProvider method called’ is displayed when the controller executes the the method. The type in the anonymous function has been instantiated by the framework.
A Factory Provider Needs to Return a Function or Value a Service” Doesn’t
OK this is probably the bit you are looking for, if I take the code above and replace .service
with .factory
:
angular.module('myModule',[])
.factory('myProvider', function (){
this.method = function(){
console.log('myProvider method called');
};
})
The code fails, following the link in the error message, we find the error reference is “Provider ‘myProvider’ must return a value from $get factory method.” – the anonymous method doesn’t return anything and factories are required to do this. To sum up the difference – a factory must provide a value, whereas a service doesn’t have to. When a service
is injected the anonymous type constructor function is invoked with a new
statement (which effectively instantiates an object). When a factory
is injected the anonymous function must return a value – this can be a function, an object constructor function, or an object instance/value.
Getting the Factory to Work
Fixing the factory is simple – return an instance of an object:
.factory('myProvider', function (){
var Foo = function (){
this.method = function() {
console.log('myProvider method called');
};
};
return new Foo();
})
Outside of the extra return requirement using a factory brings, both factories and the services can both be made to do the same things so why use one over the other? The answer is service
is really syntactic sugar over the factory
provider, the as service
can simplify code:
var Foo = function (){
this.method = function() {
console.log('myProvider method called');
};
};
angular.module('myModule',[])
.factory('myFactory', function (){
return new Foo();
})
.service('myService', Foo)
.controller('myController',function($scope,myFactory, myService){
myFactory.method();
myService.method();
});
In my stub I have a “Foo” type declaration, I want to be able to access this in the controller via injection. Doing this in the factory is a bit more work than doing it via a service which is a only one-line call. The angular guide describes this as ” exactly the use-case that the Service recipe is the most suitable for.” though there are other circumstances I use it for discussed in the “actual” conclusion.
Conclusion
Why The Confusion?
This is a hard one to call. I think part of is the fact that the devs who wrote angular use “service” (and, actually, provider) as an umbrella term for several things including the service recipe (in the tutorial they describe this as like naming their offspring “child”, and that they expect to be punished). This certainly makes it hard to keep naming in discussions consistent and means concepts can be easily muddled – something I’ve certainly struggled with in this article. The other thing is that (excepting the restriction that factories return a value) they can be made to do the same things with varying degrees (normally very little) of cruft – the service is there to provide a way to write simpler code in certain circumstances but can be made to do everything a factory can. Because of the actual interchangeability of functionality I’ve seen examples using services and factories interchangeably too. Finally some examples obscure the service =”simpler” in the correct circumstances intention – type declarations get embedded in the provider (not necessarily a bad thing – it is effectively a reduced scope I suppose) which makes the service look much more like a factory and hides the services’s true intention.
Actual Conclusion
If you’ve got a cut-and-dried example like my last code snippet then certainly go for that. The other situation I use services over factories for (and bear in mind I’m pretty inexperienced when it comes to angular) is when I know I’m going to want to a ready-instantiated single instance of a class at injection time. Why “single instance”? Because the providers are single instances themselves and as the service’s type in the anonymous function is new’ed up: this results in a shared instance across all injections and this feels a natural extension of the service class’s work. Alternatively, if you want multiple instances you can work around the single instance returned by a service, this but it feels a less natural fit in services than just using factories – a discussion for another day.
One thought on “Angular Providers – Factory or Service?”