Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using $injector vs injecting a service directly

Tags:

angularjs

I was wondering when would you use $injector.get('someService') vs injecting that service directly.

Basically, what is the difference of the two code below?

angular
    .module('myApp')
    .controller('MyController', MyController);

/** Difference of this **/
MyController.$inject = ['$rootScope', '$route']; // and more services
MyController($rootScope, $route)
{
    /* ... */
}

/** And this **/
MyController.$inject = ['$injector'];
MyController($injector)
{
    var $rootScope = $injector.get('$rootScope');
    var $route     = $injector.get('$route');
    /* and so on */
}

If you are not sure what your controller needs, or that you will update it in the future, and you have it refactored, then using $injector it is a lot easier to add/remove dependencies.

like image 518
Kousha Avatar asked Nov 23 '14 22:11

Kousha


1 Answers

The first approach uses dependency injection while the second uses service locator pattern. Dependency injection has the following advantages:

  • It makes a component's dependencies explicit. For example, you can look at the constructor function of a controller and immediately know what dependencies it needs. With service locator, you usually have no idea because the controller might invoke the service locator any time.

  • It makes unit test easier. For example you can use the $controller service to instantiate a controller and feed it with mock objects via the locals argument. That's certainly easier than having to define a bunch of AngularJS services or factories so that $injector can resolve them. It becomes worse when coupled with #1: you might not be aware of all dependencies a component needs in order to supply all the necessary mocks.

Service locator does offer some flexibility thought. For example, your code might use a service only if it exists, like this:

if ($injector.has('serviceA')) $injector.get('serviceA').doSomething() 
else someSomethingElse()

With dependency injection, if serviceA doesn't exist by the time your component is constructed, you'll get an error.

As to ease of refactoring, I don't think it's difficult to add/remove parameters to the constructor function. As pointed out in a comment to your question, tools like ngAnnotate will help make the declaration DRYer.

Therefore, I would just stick with dependency injection and only use service locator when absolutely necessary.

like image 113
Buu Nguyen Avatar answered Nov 04 '22 18:11

Buu Nguyen