Angular JS factory vs service vs provider by example

I know this question has been asked and answers have been given. But I learn best through practical examples and I came across code that I didn't fully understand.

I'm referring to Angular Strap which is an awesome set of directives for cool user interactions: http://mgcrea.github.io/angular-strap/

I was looking at the code for the tooltip feature and saw that the author was using a provider to expose functionality. Could he have also used a service or a factory to do the same job? Or was a provider necessary?

Here is the link to the code: https://github.com/mgcrea/angular-strap/blob/master/src/tooltip/tooltip.js#L28

Thank you

Answers:

Answer

Short answer: The author chose Provider to make the defaults 'read-only'. The code could still work if they hadn't used Provider, but Provider is cleaner and 'safer'

Provider, Service, and Factory are all the same basic thing in Angular, just with different APIs; Provider can kinda be thought of as the 'base' element, but they all have the same end purpose: to create an Angular injectable. Each of those injectables has a Provider that provides the blueprint (Angular looks for a $get method), and a Singleton instance the provider generates. If you use Factory or Service, Angular does work behind the scenes so you don't need to know all the details; you'll just have a really boring Provider that only does the basics. However, if you use Provider yourself, you can put extra properties and functions on it in your declaration.

You can inject Providers into a module's config() method, which is run before any of the Singletons are created. Try looking here for a longer explanation.

In AngularStrap, the author puts a 'defaults' object on the Provider. The author expects you to modify that object in your module's config() method, and then Angular will generate the Singleton. However, the 'defaults' object is not on the Singleton, so you can't change the defaults once the app is 'running'. Even if you inject the Provider again somewhere and change 'default's again, Angular won't re-make your Singleton, so the defaults effectively become 'read-only'. This is a good practice to prevent code from making unwanted changes, especially when you have multiple people in the same code, or you know other people will be using your module.

You may see other code that doesn't work like that... maybe another app just uses a factory, and puts the 'defaults' object on that factory. It would still 'work', and the code would look a lot like it does currently. However, because 'defaults' would be directly on the Singleton, your code could change these settings at ANY point if somebody wrote code to do it. Now you've got to leave comments and documentation explaining when to change the defaults, when NOT to change the defaults, and so on; for 99% of cases, the defaults never need to change once the app is running, so using Provider and module.config() is safe and straightforward.

Answer

While the documentation is correct that there are special cases to use each I think it's also important to answer that they are all the same thing.

The factory is a specialized version of provider that in some cases let's you accomplish the same thing using less code. In turn a service and value are special cases of factory. And constant is a special case of value.

Here is an image that shows you at a glance what I mean:

providers factories value and service are the same thing
(source: simplygoodcode.com)

You can get more details on the blog the image is from: http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/

There's also another question on Stack Overflow with similiar details at: https://stackoverflow.com/a/33805462/984780

Answer

According to the official Angular Documentation:

There are five recipe types.

The most verbose, but also the most comprehensive one is a Provider recipe. The remaining four recipe types — Value, Factory, Service and Constant — are just syntactic sugar on top of a provider recipe.

So, in essence, building a Service and building a Provider are identical, assuming you don't need to access some of the advanced settings. They go on to say:

You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts.

and here is a table:

Features / Recipe type

                                 Factory  Service  Value  Constant  Provider
can have dependencies            yes      yes      no     no        yes 
uses type friendly injection     no       yes      yes*   yes*      no 
object available in config phase no       no       no     yes       yes** 
can create functions             yes      yes      yes    yes       yes 
can create primitives            yes      no       yes    yes       yes 

* at the cost of eager initialization by using new operator directly

** the service object is not available during the config phase, but the provider instance is.

Answer

Angular provides us with three ways to create and register our own service.

Factory

Service

Provider

1. Factory : When you’re using a Factory 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.

Example :

app.controller('myFactoryCtrl', function ($scope, myFactory) {
  $scope.artist = myFactory.getArtist()
});

app.factory('myFactory', function () {
  var _artist = '';
  var service = {}
  service.getArtist = function () {
    return _artist
  }
  return service;
});

2 Service: When you’re using Service, it’s instantiated with the ‘new’ keyword. Because of that, you’ll 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.

Example :

app.controller('myServiceCtrl', function ($scope, myService) {
  $scope.artist = myService.getArtist();
});

app.service('myService', function () {
  var _artist = '';
  this.getArtist = function () {
    return _artist;
  }
});

3 Provider : Providers are the only service you can pass into your .config() function. Use a provider when you want to provide module-wide configuration for your service object before making it available.

Example :

app.controller('myProviderCtrl', function ($scope, myProvider) {
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider('myProvider', function () {
  this._artist = '';
  this.thingFromConfig = '';

  //Only the properties on the object returned from $get are available in the controller.
  this.$get = function () {
    var that = this;
    return {
      getArtist: function () {
        return that._artist;
      },
      thingonConfig: that.thingFromConfig
    }
  }
});

app.config(function (myProviderProvider) {
  myProviderProvider.thingFromConfig = 'This was set in config()';
});

To read more about services click here

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.