Many developers ask this question, trying to understand this dependency injection, other differences, advantages and disadvantages of these AngularJS objects. In this article I will try to explain in details everything we know about the providers, services and factories.
Factory Provider
- Gives us the function’s return value ie. You create an object, add properties to it, then return that same object. When you pass this service into your controller, those properties on the object will now be available in that controller through your factory (hypothetically)
- Singleton
- Reusable components
- Can use other dependencies
- Usually used when the service instance requires complex creation logic
- Used for non configurable services
- If you’re using an object, you could use the factory provider
Service Provider
- Gives us the instance of a function (object). You instantiated with the ‘new’ keyword and you will add properties to ‘this’ and the service will return ‘this’. When you pass the service into your controller, those properties on ‘this’ will now be available on that controller through your service (hypothetically)
- Singleton and will only be created once
- Reusable components
- Dependencies are injected as constructor arguments
- Used for simple creation logic
- If you’re using a class you could use the service provider
Services
Syntax:module.service('serviceName', function);
Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassToService()Factories
Syntax:module.factory('factoryName', function);
Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factoryProviders
Syntax:module.provider('providerName', function);
Result: When declaring providerName as an injectable argument you will be provided with (new ProviderFunction()).$get(). The constructor function is instantiated before the $get method is called – ProviderFunction is the function reference passed to module.provider
Providers have the advantage that they can be configured during the module configuration phase.
Example:provide.value('variable', 123); function Controller(variable) { expect(variable).toEqual(123); }In this case the injector simply returns the value as is. But what if you want to compute the value? Then use a factory:
provide.factory('myfactory', function(variable) { return variable * 2; }); function Controller(myfactory) { expect(myfactory).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(name) { this.greet = function() { return 'Hello ' + name; } }Then to instantiate you would have to write
provide.factory('greeter', function(name) { return new Greeter(name); });Then we could ask for ‘greeter’ in controller like this
function Controller(greeter) { expect(greeter instanceof Greeter).toBe(true); expect(greeter.greet()).toEqual('Hello John'); }But that is way too wordy. A shorter way to write this would be provider.service(‘greeter’, Greeter); But what if 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(name) { this.greet = function() { return salutation + ' ' + name; } } this.$get = function(name) { return new Greeter(name); }; });Then we can do this:
angular.module('abc', []).config(function(greeter2Provider) { greeter2Provider.setSalutation('Hola'); }); function Controller(greeter2) { expect(greeter2.greet()).toEqual('Hola John'); }As a side note, service, factory, and value are all derived from provider.
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; }); };