Understanding Providers, Services, and Factories in Angular

I’ve read quite a few posts (as well as questions posed) about the differences between services and factories in Angular. I’ve seen just as many attempts to explain it and even fell victim to trying to force an explanation for the difference myself. The answer is more simple than you may think and is evident if you browse the Angular source code and then re-read the documentation. When this clicked for me I had to share it because so many people seem to make more out of it than it is.

The biggest misconception I see is the idea that factories and services have anything to do with being a singleton. The reality is that both methods create singletons (unless you game them to generate new instances).

So here it is. I’m going to summarize then follow up with some examples;

  • Use a service when you want to pass a constructor function. The function will be invoked with the “new” operator and the result stored.
  • Use a factory when you want to return the object from a function (i.e. factory pattern). The function will be called and the result stored.
  • Use a provider when you want to be able to provide module-wide configuration for your object before making it available.

That’s it! It’s real simple. The key to note first is that factories and services end up with the same result, they just use different approaches. With the factory approach you can specify a function to resolve your dependencies and then return an object that uses them, like this:

app.factory(‘myAlertFactory’, [‘myAlert’, function (myAlert) {
return {
alert: function (message) {
myAlert.alert(message);
}
};
}]);

Notice that the outer function takes a dependency on a service called “myAlert”. Angular will wire that dependency, call your function and store the result. In this case I pass back an object with an alert method that “passes through” to the alert method on the myAlert service. Essentially I’ve created a “myAlertFactory” object I can use to reference that is a proxy to the underlying “myAlert” object.

The problem with the factory approach is that some languages like TypeScript lean you towards a more class-based approach, and other languages like CoffeeScript enforce it. You can’t just return an arbitrary object from the factory function, so instead you need a way to pass the type onto Angular (remember in JavaScript a custom type is really a constructor function).

This will work fine:

app.service(‘myAlertService’, MyAlertService);

The type is defined like this:

function MyAlertService(myAlert) {
this.alert = function (message) {
myAlert.alert(message);
};
}
MyAlertService.$inject = [‘myAlert’];

Notice that this is a constructor function. It also takes on a dependency, only this time I used a different method to annotate the class so Angular knows what to inject. The end result is exactly the same, so your choice of factory or service should be based on your preference for supplying the instance – do you prefer to create classes and pass the constructor function, or would you rather return something explicitly from a factory function? It’s your choice. The service and factory calls wire up the object and refer to how you prefer to make it, not how the app will consume it.

So what about provider? A provider is a special case that allows for configuration. If you don’t need module-wide configuration, go for a service or factory instead. Think of a provider as sitting on top of a service. The provider is an object that can handle configuration. The first time the service itself is needed, Angular will call the $get function on the provider. This will return an instance that is subsequently tracked like any other item that was wired up using a service or factory.

To illustrate, let’s implement the “myAlert” service that was passed into the two previous examples. The service does what you’d expect – it raises an alert – but it can be configured one time only to prepend a date. It will either use the message, or use the combination of the current date and the message. The provider looks like this:

function MyAlertProvider() {
var showTime = false;

    this.setShowTime = function (show) {
showTime = !! show;
};

    this.$get = [‘$window’,

    function ($window) {
return {
alert: function (message) {
var dateStamp = new Date();
if (showTime) {
$window.alert(dateStamp.toString() + “: ” + message);
} else {
$window.alert(message);
}
}
};
}];
}

It contains an internal variable for configuration, exposes a method to configure it, and supplies a $get method to generate the instance (in this case, we’re using the inline annotation to inject the $window service). Note the convention is to take the name you’re going to use for the service and append “Provider” to the end. Here is the set up for the provider. Notice it is named without the provider suffix:

var app = angular.module(‘myApp’, []);
app.provider(‘myAlert’, MyAlertProvider);

And here the module configures it to prepend the date. Notice the dependency requested is for the provider, not the service itself:

app.config([‘myAlertProvider’, function (myAlertProvider) {
myAlertProvider.setShowTime(true);
}]);

Finally I can take all of these items and expose them in a controller like this:

app.controller(‘MyController’, [
‘myAlert’,
‘myAlertService’,
‘myAlertFactory’,
‘$scope’, function (myAlert, myAlertService, myAlertFactory, $scope) {
$scope.alert = function () {
myAlert.alert(“This is an alert!”);
};
$scope.alertService = function () {
myAlertService.alert(“This is an alert!”);
};
$scope.alertFactory = function () {
myAlertFactory.alert(“This is an alert!”);
};
}]);

That’s it. The behavior of the alert calls depends on the one-time configuration of the provider. The service and factory proxies are identical despite the different way they were wired up. If I wanted to make the optional date a parameter and not a configuration option, I would do away with the provider and just use a service or a factory. The full working example is available to you at the following link. Try commenting out the .config call to see the default alert without dates added.

http://jsfiddle.net/jeremylikness/A6Cb2/

2075

The Right Solution for Your Needs.

We deliver a hybrid spectrum of Microsoft Cloud Platform and Azure solutions to government agencies and application developers who demand a modern, open and flexible cloud service platform. We offer trusted, transparent, and secure Infrastructure as a Service (IaaS) and Platform as a Service (PaaS) solutions for production business applications, Business Intelligence (BI), continuous data protection, application availability, test/development, and Software as a Service (SaaS)

Architected to meet your needs.

Deployed flawlessly.

Operated reliably 24x7x365.

Assess:

Rely on our team to map your existing environment to a corresponding Azure cloud.

Migrate:

Easily move from your existing environment to a public or private Microsoft cloud.

Re-platform:

Understand how to transform your applications to better take advantage of cloud capabilities.

Operate:

Our team actively manages all maintenance & optimization to keep your environment running at its best.

Why Microsoft Cloud Platform and Azure?

Microsoft has made major strides in the public cloud space over the past few years. They are gaining market momentum with companies and also the analysts community who recognize the more than USD15B investment made. At this point Azure has more data centers than AWS and Google Cloud combined. It spans an unparalleled global reach with 36 regions available and more being added. Azure offers companies wanting to put workload in the a public cloud with a secure, scalable and competitive option.

2111

Azure Certified for Hybrid Cloud.

Atmosera has developed core competencies and intellectual property to take full advantage of all Azure has to offer. All Atmosera Azure services receive the “Azure Certified for Hybrid Cloud” designation which confirms it passed Microsoft’s rigorous validation process under the Cloud OS Network (COSN) program. Customers benefit from knowing that their solution was carefully planned and executed using best practices and proven methods.

Stay Informed

Sign up for the latest blogs, events, and insights.

We deliver solutions that accelerate the value of Azure.
Ready to experience the full power of Microsoft Azure?

Atmosera is thrilled to announce that we have been named GitHub AI Partner of the Year.

X