AngularJS Dependency Injection And Dolphins
Adam Klein
Last updated on Mar 6, 2016

Have you ever found yourself asking: should I use a value? a factory? a service? a provider?! Ask yourself 3 questions:

  • Do I need to inject it in the config phase?
  • Does it have dependencies?
  • Am I a dolphin?

Then reduce which type of service you need to use:

  • Service <= not needed in config phase, has dependencies
  • Value <= not needed in config phase, has no dependencies
  • Constant <= needed in config phase, has no dependencies
  • Provider <= needed in config phase, has dependencies
  • Factory <= You are a dolphin

Notice that if you answer yes to the third question you don’t need to ask yourself the other questions - optimizing the algorithm :)

The reasoning behind

Angular modules have a config phase, that runs before the app is bootstrapped. During that phase you can only inject constants or providers. You cannot inject a service or a value:

  angular.module('app', [])
    .config(function(Constant, Provider) {
      // ...
    })
    .controller(function(Service, Value, ...) {
    })
  ;

Constants and values can't inject dependencies. Thus, they are simpler to define:

angular.module('app', [])
  .constant('PI', Math.PI)
  .value('Temperature', 27.5)

In most cases, there's no real justification for using a value over a constant. The main advantage I found, is that you can override it in tests, in order to mock it.

Why not factory?

To understand why you never need to use a factory, you need to know how the injector instantiates our services.

For a service, it's something like this:

service = new Service(dependency1, dependency2, ...)

For a factory, it's something like this:

factory = Factory(dependency1, dependency2, ...)

In Javascript a constructor function can ignore the fact that it was called with new operator, and act as a regular function, returning whatever it likes. For example:

function Service() {
  return { value: 3 };
}
var service = new Service();
// service.value === 3;

function AnotherService() {
  this.value = 3;
}
var anotherService = new AnotherService();
// anotherService.value === 3;

However, if it hasn't been called with new, you can't use it as a constructor, but you have to return a value. For example:

function Factory() {
  this.value = 3;
}
factory = Factory();
// factory === undefined;

Thus, you can replace all your factories with services, and everything will work the same way, but not the other way around.

*disclaimer: There's only thing you can't return from a constructor function invoked with new is a primitive value (string, integer, etc.). So the only case it will make sense to use a factory is for defining primitive values that require dependencies.

Hope you enjoyed the guide!

Back to all articles

© 500Tech. Building high-quality software since 2012.