Created
August 6, 2013 12:02
-
-
Save kevcha/6163894 to your computer and use it in GitHub Desktop.
Difference between Factory, Services and Providers
@see https://groups.google.com/forum/#!msg/angular/56sdORWEoqg/b8hdPskxZXsJ => Miško Hevery answers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Lets look at the simplest scenario | |
provide.value('a', 123); | |
function Controller(a) { | |
expect(a).toEqual(123); | |
} | |
in this case the injector simple returns the value as is. But what if you want to compute the value. Then use a factory | |
provide.factory('b', function(a) { | |
return a*2; | |
}); | |
function Controller(b) { | |
expect(a).toEqual(246); | |
} | |
So factory is a function which is responsible for creating the value. Notice that the factory function can ask for other dependencies. But what if you want to be more OO and have a class called Greeter | |
function Greeter(a) { | |
this.greet = function() { | |
return 'Hello ' + a; | |
} | |
} | |
then to instantiate you would have to write | |
provide.factory('greeter', function(a) { | |
return new Greeter(a); | |
}); | |
Then we could ask for 'greeter' in controller like this | |
function Controller(greeter) { | |
expect(greeter instanceof Greeter).toBe(true); | |
expect(greeter.greet()).toEqual('Hello 123'); | |
} | |
But that is way too wordy a shorter way to write this would be | |
provider.service('greeter', Greeter); | |
But what it we wanted to configure the Greeter class before the injection then we could write | |
provide.provider('greeter2', function() { | |
var salutation = 'Hello'; | |
this.setSalutation = function(s) { | |
salutation = s; | |
} | |
function Greeter(a) { | |
this.greet = function() { | |
return salutation + ' ' + a; | |
} | |
} | |
this.$get = function(a) { | |
return new Greeter(a); | |
}; | |
}); | |
we can then do this | |
angular.module('abc', []).configure(function(greeter2Provider) { | |
greeter2Provider.setSalutation('Halo'); | |
}); | |
function Controller(greeter2) { | |
expect(greeter.greet()).toEqual('Halo 123'); | |
} | |
But it turns out that angular only understands provide.provider, all other ones are derived. | |
provider.service = function(name, Class) { | |
provider.provide(name, function() { | |
this.$get = function($injector) { | |
return $injector.instantiate(Class); | |
}; | |
}); | |
} | |
provider.factory = function(name, factory) { | |
provider.provide(name, function() { | |
this.$get = function($injector) { | |
return $injector.invoke(factory); | |
}; | |
}); | |
} | |
provider.value = function(name, value) { | |
provider.factory(name, function() { | |
return value; | |
}); | |
}; | |
Then => | |
On Friday, August 17, 2012 11:00:53 AM UTC-7, ben.clin...@gmail.com wrote: | |
In order to get this straight in my own head I have created a very simple demo which can be viewed at http://jsbin.com/ohamub/1/edit | |
There are comments in the code illustrating the primary differences but I will expand on them a bit here. As a note, I am just getting my head around this so if I say anything that is wrong please let me know. | |
Services | |
Syntax: module.service( 'serviceName', function ); | |
Result: When declaring serviceName as an injectable argument you will be provided the actual function reference passed to module.service. | |
NO, you will get an instance of the function. In other words new FunctionYouPassedToService(). | |
Usage: Could be useful for sharing utility functions that are useful to invoke by simply appending () to the injected function reference. Could also be run with injectedArg.call( this ) or similar. | |
Factories | |
Syntax: module.factory( 'factoryName', function ); | |
Result: When declaring factoryName as an injectable argument you will be provided the value that is returned by invoking the function reference passed to module.factory. | |
CORRECT | |
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances. | |
Providers | |
Syntax: module.provider( 'providerName', function ); | |
Result: When declaring providerName as an injectable argument you will be provided the value that is returned by invoking the $get method of the function reference passed to module.provider. | |
ALMOST | |
you will be provided with new ProviderFunction().$get(). The constructor function is instantiated before the $get method is called. | |
Usage: Could be useful for returning a 'class' function that can then be new'ed to create instances but that requires some sort of configuration before being injected. Perhaps useful for classes that are reusable across projects? Still kind of hazy on this one. | |
Providers have the advantage that they can be configured during the module configuration phase. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment