The Magic

Exclusive offer: get 50% off this eBook here
Dependency Injection with AngularJS

Dependency Injection with AngularJS — Save 50%

Design, control, and manage your dependencies with AngularJS dependency injection with this book and ebook

$17.99    $9.00
by Alex Knol | December 2013 | Open Source

It is time we explain some of the inner workings of Angular. Angular does some neat things for us. It saves us from having to write a bunch of boilerplate code. In this article written by Alex Knol author of the book Dependency Injection with AngularJS, we will see the magic of Angular.

Dependency Injection is baked into AngularJS and heavily used throughout. Another feature is a built-in subset of a jQuery functionality called jQLite. It contains all the necessary functions to make AngularJS run without jQuery and has the exact same interface. If jQuery is available in your application, it will be used instead. Angular also takes the burden of bootstrapping your application, which will be covered later in this article.

(For more resources related to this topic, see here.)

Application flow

In the following diagram, from the Angular manual, you find a comprehensive schematic depiction of the program flow inside Angular:

After the browser loads the HTML and parses it into a DOM, the angular.js script file is loaded. This can be added before or at the bottom of the <body> tag, although adding it at the bottom is preferred. Angular waits for the browser to fire the DOMContentLoaded event. This is similar to the way jQuery is bootstrapped, as illustrated in the following code:

$(document).ready(function(){ // do jQuery })

In the Angular.js file, towards the end, after the entire code has been parsed by the browser, you will find the following code:

jqLite(document).ready(function() { angularInit(document, bootstrap); });

The preceding code calls the function that looks for various flavors of the ng-app directive that you can use to bootstrap your Angular application.

['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app']

Typically, the ng-app directive will be the HTML tag, but in theory, it could be any tag as long as there is only one of them. The module specification is optional and can tell the $injector service which of the defined modules to load.

//index.html <!doctype html> <html lang="en" ng-app="tempApp"> <head> …... // app.js ….. angular.module('tempApp', ['serviceModule']) …..

In turn, the $injector service will create $rootscope, the parent scope of all Angular scopes, as the name suggests. This $rootscope is linked to DOM itself as a parent to all other Angular scopes. The $injector service will also create the $compile service that will traverse the DOM and look for directives. These directives are searched for within the complete list of declared Angular internal directives and custom directives at hand. This way, it can recognize directives declared as an element, as attributes, inside the class definition, or as a comment. Now that Angular is properly Bootstrapped, we can actually start executing some application code. This can be done in a variety of ways, shown as follows:

  • In the initial examples, we started creating some Angular code with curly braces using some built-in Angular functions
  • It is also possible to define a controller to control a specific part of the HTML page, as we have shown in the first tempCtrl code snippet
  • We have also shown you how to use Angular's built-in router to manage your application using client-side routing

As you can see, Angular extends the capabilities of HTML by providing a clever way to add new directives. The key ingredient here is the $injector service, which provides a way to look up for dependencies and create $rootscope.

Different ways of injecting

Let's look a bit more at how $injector does its work. Throughout all the examples in this book, we have used the array-style notation to define our controllers, modules, services, and directives.

// app/ controllers.js tempApp.controller('CurrentCtrl', ['$scope', 'reading', function ($scope, reading) { $scope.temp = 17; ...

This style is commonly referred to as annotation. Each injected value is annotated in the same order inside an array. You may have looked through the AngularJs website and may have seen different ways of defining functions.

// angularJs home page JavaScript Projects example functionListCtrl($scope, Project) { $scope.projects = Project.query(); }

So, what is the difference and why are we using another way of defining functions? The first difference you may notice is the definition of all the functions in the global scope. For reference, let's call this the simple injection method. The documentation states that this is a concise notation that really is only suited for demo applications because it is nothing but a potential clash waiting to happen. Any other JS library or framework you may have included could potentially have a function with the same name and cause your software to malfunction by executing this function instead of yours. After assigning the Angular module to a variable such as tempApp, we will chain the methods to that variable like we have done in this book so far; you could also just chain them directly as follows:

angular.module('tempApp').controller('CurrentCtrl', function($scope) {})

These are essentially the same definitions and don't cause pollution in the global scope. The second difference that you may have noticed is in the way the dependencies are injected in the function. At the time of writing this book, most, if not all of the examples on the AngularJs website use the simple injection method. The dependencies are just parameters in the function definitions. Magically, Angular is able to figure out which parameter is what by the name because the order does not matter. So the preceding example could be rewritten as follows, and it would still function correctly:

// reversedangularJs home page JavaScript Projects example functionListCtrl( Project, Scope ) { $scope.projects = Project.query(); }

This is not a feature of the JavaScript language, so it must have been added by those smart Angular engineers. The magic behind this can be found in the injector. The parameters of the function are scanned, and Angular extracts the names of the parameters to be able to resolve them.

The problem with this approach is that when you deploy a wonderful new application to production, it will probably be minified and even obfuscated. This will rename $scope and Project to something like a and b. Even Angular will then be unable to resolve the dependencies. There are two ways to solve this problem in Angular. You have seen one of them already, but we will explain it further. You can wrap the function in an array and type the names of the dependencies as strings before the function definition in the order in which you supplied them as arguments to the function.

// app/ controllers.js tempApp.controller('CurrentCtrl', ['$scope', 'reading', function ($scope, reading) { $scope.temp = 17; .......

The corresponding order of the strings and the function arguments is significant here. Also, the strings should appear before the function arguments.

If you prefer the definition without the array notation, there is still some hope. Angular provides a way to inform the injector service of the dependencies you are trying to inject.

varCurrentCtrl = function($scope, reading) { $scope.temp = 17; $scope.save = function() { reading.save($scope.temp); } }; CurrentCtrl.$inject = ['$scope', 'reading']; tempApp.controller('CurrentCtrl', CurrentCtrl);

As you can see, the definition is a bit more sizable, but essentially the same thing is happening here. The injector is informed by filling the $inject property of the function with an array of the injected dependencies. This is where Angular will then pick them up from.

To understand how Angular accomplishes all of this, you should read this excellent blog post by Alex Rothenberg. Here, he explains how all of this works internally. The link to his blog is as follows:

http://www.alexrothenberg.com/2013/02/11/the-magic-behind-angularjs-dependency-injection.html.

Angular cleverly uses the toString() function of objects to be able to examine in which order the arguments were specified and what their names are.

There is actually a third way to specify dependencies called ngmin, which is not native to Angular. It lets you use the simple injection method and parses and translates it to avoid minification problems.

https://github.com/btford/ngmin

Consider the following code:

angular.module('whatever').controller('MyCtrl', function
($scope, $http) { ... });

ngmin will turn the preceding code into the following:

angular.module('whatever').controller('MyCtrl', ['$scope',
'$http', function ($scope, $http) { ... }]);

 

Summary

In this article, we started by looking at how AngularJS is bootstrapped. Then, we looked at how the injector works and why minification might ruin your plans there. We also saw that there are ways to avoid these problems by specifying dependencies differently.

Resources for Article:


Further resources on this subject:


Dependency Injection with AngularJS Design, control, and manage your dependencies with AngularJS dependency injection with this book and ebook
Published: December 2013
eBook Price: $17.99
Book Price: $29.99
See more
Select your format and quantity:

About the Author :


Alex Knol

Alex Knol is a lifelong tech geek with a passion for automation. After spending some years away from software development, around the beginning of this century, he took up PHP development based on his early experiences with C and Pascal. Surprisingly, he has never really used web tools, but applications instead, to make websites, such as the platform that's driving kaizegine.com. Having built various applications using web technologies and frameworks, such as Symfony, he discovered AngularJS at the beginning of 2008, while searching for a way to structure frontend application code and make development easy. He used AngularJS, among other technologies, for a job-matching project in the Netherlands and, more recently, for an online website designer named Risingtool.com.

Books From Packt


AngularJS Directives
AngularJS Directives

Mastering Web Application Development with AngularJS
Mastering Web Application Development with AngularJS

Instant AngularJS Starter
Instant AngularJS Starter

JBoss Weld CDI for Java Platform
JBoss Weld CDI for Java Platform

Mastering Ninject for Dependency Injection
Mastering Ninject for Dependency Injection

Instant Dependency Management with RequireJS How-to
Instant Dependency Management with RequireJS How-to

Apache Maven Dependency Management
Apache Maven Dependency Management

Java EE 6 with GlassFish 3 Application Server
Java EE 6 with GlassFish 3 Application Server


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
n
A
7
F
1
E
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software