Explicit Dependency Injection

Angular's dependency injection system uses function parameter's names to resolve dependencies for components. This can create an issue when minifying JavaScript assets.

To illustrate this issue let's late a look at a test controller:

function TestCtrl($scope, $log) {
  $scope.$watch('random-event', function() {
    $log.log('hello world')
  })
}

angular.module('test').controller('TestCtrl', TestCtrl)

Here, we're injecting two services into the controller: $scope and $log.

Now, let's minify this code using Uglify JS-- first install it:

npm install -g uglify-js

Then minify the file:

uglifyjs TestCtrl.js --compress --mangle > out.js

The resulting output should look something like this:

function TestCtrl(t,l){t.$watch("random-event",function(){l.log("hello world")})}angular.module("test").controller("TestCtrl",TestCtrl);

Notice how TestCtrl now accepts two parameters: t and l. Angular doesn't have any idea that these are actually supposed to be $scope and $log respectively and will therefor throw an error.

To rectify this problem, Angular allows you to add explicit dependency annotations. The first way uses array syntax to associate string representations of dependencies (strings won't get minified):

angular.module('test')
.controller('TestCtrl', ["$scope", "$log", function($scope, $log) {
  $scope.$watch('random-event', function() {
    $log.log('hello world')
  })
}])

Notice we're declaring the controller inline in this example.

We can also use the $inject property:

function TestCtrl($scope, $log) {
  $scope.$watch('random-event', function() {
    $log.log('hello world')
  })
}

TestCtrl.$inject = ["$scope", "$log"];

angular.module('test').controller('TestCtrl', TestCtrl)

Now if we minify the code again, the resulting code will look something like this:

function TestCtrl(t,l){t.$watch("random-event",function(){l.log("hello world")})}TestCtrl.$inject=["$scope","$log"],angular.module("test").controller("TestCtrl",TestCtrl);

Angular will use the list of strings in the $inject property to properly resolve the controllers dependencies.

Adding dependency annotations is a necessity when writing Angular applications, but they can be tedious to maintain. Fortunately, a wonderful tool called ng-annotate exists to automate this process for you. You can learn more about this tool with our guide to ng-annotate.