Because Angular manages resources with a built-in module system, it also needs to provide client code with a way to access these container-managed resources. Angular does this with a creational pattern called dependency injection.

If you're unfamiliar with dependency injection, here's my best shot at a summary: You need a resource from Angular, the container. To get it, you write a function that declares a parameter with exactly the same name as the resource. The container detects your function, matches the parameter with the resource, makes an instance of the resource (or just grabs the singleton instance of it, as the case may be) and calls your function with this instance as the argument for your parameter. Since the container has the active role (as opposed to you actively requesting the instance of the resource in a statement), dependency injection is considered an inversion of control, colorfully described as an application of the Hollywood principle, "Don't call us, we'll call you."

I believe the creators of Angular chose dependency injection because of Google's long history with the Java platform, a static programming environment in which dependency injection greatly assists in type substitution at runtime. (Google has even gone so far as to create and maintain its own Guice dependency injection framework for Java.) In JavaScript, a more flexible, dynamic environment in which types may be modified at runtime, the simple, straight-forward service locator pattern has won tremendous mindshare via the CommonJS API, which is the require statement used in Node.js and browserify. What's more, it turns out that plain-vanilla dependency injection has a debilitating issue in client-side JavaScript, due to the modification of parameter names by minifiers. In order to cope with this issue, it is necessary either to introduce a compensating build tool or to learn about and use dependency annotations. We'll get to that in a moment, after looking first at the plain-vanilla form.

Implicit dependencies

Outside of this chapter, the examples in this book exclusively use the simplest form of Angular dependency injection, known as implicit dependencies. As explained above, we obtain a reference to an available resource simply by listing it as a parameter in our creational function. The first time we did this was with the $scope parameter that gives controller functions a reference to a container-managed scope instance. Angular's dependency injection system does the work of finding or instantiating the resource instance and passing it as an argument to our controller. Let's look again at how this works with a built-in resource, the $locale service.

Since some of the examples in this chapter use the module system, we need to declare a module.

angular.module('app', []);

We then load our app module by passing its name to the ng-app directive. Our choice of the name app is a convention, but not otherwise significant.

<body ng-app="app">
  <!-- Other examples to be inserted here. -->
</body>

We're ready to go with our first example. In addition to the familiar $scope parameter, we just add a $locale parameter. Angular will recognize and inject both. It knows to inject resources into this function because the function is a controller.

angular.module('app')
  .controller('LocaleController', function($scope, $locale) {
    $scope.locale = $locale.id;
  });

The body of our controller simply assigns the id property of the not-randomly-named $locale parameter to the randomly-named locale scope property.

<p ng-controller="LocaleController">
  Your locale is <strong ng-bind="locale"></strong>
</p>

You should see something similar to "Your locale is en-us" in the output. What happens if you add a parameter named myResource to the controller function? Does it break the example? Can you find the error in your browser's JavaScript console? Angular errors often display a helpful documentation link, such as http://errors.angularjs.org/1.5.5/$injector/unpr?p0=myResourceProvider%20%3C-%20myResource. For a great, short lesson on dependency injection troubleshooting, follow the link above and read the explanation.

Annotations

In a programming language such as Java, an annotation is metadata that is added to the source code but is ignored by the compiler. In the context of Angular's dependency injection, annotation apparently means declaring the resources you want to be injected in an explicit way that survives the shortening of your parameter names by minification. (An example of minification is the usage of the build tool UglifyJS.) Let's look at the ways that Angular lets us "annotate" our dependencies.

ng-annotate

An expedient way to counteract the mischief of one build task is with another build task. The ng-annotate build tool will annotate your dependencies for you, allowing you to continue to use the implicit dependencies form explained in the previous section. You simply need to run ng-annotate before you run your minifier. The core ng-annotate utility is for use on the command line, but there are wrappers for popular build tools and asset packagers, including grunt-ng-annotate, gulp-ng-annotate, browserify-ngannotate, and ng-annotate-webpack-plugin.

Inline annotation

The more common of the two annotation styles is known as inline annotation. It involves enclosing your controller function within an array, as follows.

angular.module('app')
  .controller('LocaleController', ['$scope', '$locale', function(s, l) {
    s.locale = l.id;
  }]);

In this example, I have simulated the effect of minification by changing the controller's parameter names from $scope and $locale to s and l, respectively. As you can imagine, Angular would not find resources named s and l if we were relying on the implicit dependencies approach. Since the array contains the real names of the resources, Angular is able to inject them.

$inject annotation

While the inline annotation style shown above is ugly, you are likely to find the alternative style even uglier. It involves setting a specially-named property, $inject, on your creational function. For this reason it is called $inject annotation.

var LocaleController = function(s, l) {
  s.locale = l.id;
};

LocaleController['$inject'] = ['$scope', '$locale'];

angular.module('app')
  .controller('LocaleController', LocaleController);

At least you know what your options are.

angular.injector

Hopefully by this point you have already added ng-annotate to your build, so that you can stick with the plain-vanilla style of implicit dependencies shown throughout this book. However, if not, I have a not-quite-serious suggestion: Write your own require function, and express your dependencies in the straightforward service locator pattern instead of using dependency injection. It is possible to do this by invoking the angular.injector function directly. The argument to angular.injector is simply an array listing the modules you want to search. The ng module must always be included and listed first.

var require = function(name) {
  return angular.injector(['ng','app']).get(name);
};

angular.module('app')
  .controller('LocaleController', ['$scope', function($scope) {
    var $locale = require('$locale');
    $scope.locale = $locale.id;
  }]);

Notice that the example still depends on dependency injection to pass in the correct scope object. Lest you conclude that this exception defeats the purpose of adopting a service locator approach, the next section will seek to illustrate one of the practical issues with annotation in a large-scale system.

Pitfalls

The example below looks forward to the next chapter, Services. While you may not yet be familiar with Angular's factory function, you can probably infer that it configures a component factory with the module system. Notice also that the $http service (discussed in the upcoming HTTP chapter) would be a very typical, real-life dependency injected into services such as these.

angular.module('app')
  .factory('fullPrice', ['$http', function($http) {
    return function() {
      // Use $http to fetch remote data.
      return 100;
    }
  }])
  .factory('discountPrice', ['$http', function($http) {
    return function() {
      // Use $http to fetch remote data.
      return 40;
    }
  }]);

The following example was inspired by a real-life Angular application. The dependencies have been changed to a laundry list of the built-in Angular services, but the length of the list is about the same.

angular.module('app')
  .controller('PriceController',
    ['$scope',
    '$anchorScroll',
    '$animate',
    '$cacheFactory',
    '$compile',
    '$controller',
    '$document',
    '$exceptionHandler',
    '$filter',
    '$http',
    '$httpBackend',
    '$interpolate',
    '$interval',
    'fullPrice',
    'discountPrice',
    '$locale',
    '$location',
    '$log',
    '$parse',
    '$q',
    '$rootElement',
    '$rootScope',
    '$sce',
    '$sceDelegate',
    '$templateCache',
    '$timeout',
    '$window',
    function(
      $scope,
      $anchorScroll,
      $animate,
      $cacheFactory,
      $compile,
      $controller,
      $document,
      $exceptionHandler,
      $filter,
      $http,
      $httpBackend,
      $interpolate,
      $interval,
      discountPrice,
      fullPrice,
      $locale,
      $location,
      $log,
      $parse,
      $q,
      $rootElement,
      $rootScope,
      $sce,
      $sceDelegate,
      $templateCache,
      $timeout,
      $window) {
        $scope.fullPrice = fullPrice();
        $scope.discountPrice = discountPrice();
  }]);

The body of PriceController is obviously abridged, as is the view below.

<table ng-controller="PriceController"> <tr> <td>Full price:</td> <td>{{fullPrice}}</td> </tr> <tr> <td>Discount price:</td> <td>{{discountPrice}}</td> </tr> </table>

The full price should always be greater than the discount price, but somehow they were switched. The problem is not in the view or the body of the controller. Can you find it? What does it tell you about hand-coding dependency annotations in the real world?

Conclusion

This is the second of three chapters that cover Angular's infrastructure for managing application code. The first, Modules, demonstrated how to set the stage on which the actors in your Angular story might play their roles. This chapter described in detail the mechanisms available for placing the actors where they need to be on that stage. The upcoming and final chapter on this topic, Services, explains how to create the actors themselves.

I hope you have been enjoying Angular Basics.
You can join the mailing list to hear about updates to the book.
Please also let me know what you liked and what I can improve.
And please share the word using the social buttons below!