Angular JS : Module, Controllers, Services and Dependency Injection

In the previous post we saw some basic angular directives. All the code was in a single file. Lets build a small app and  structure it a bit and learn few new concepts. Lets see the code first – index.html:


<!DOCTYPE html>
<html lang="en-us" ng-app="angularApp">
<head>
<title>AngularJS Demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://code.angularjs.org/1.4.8/angular.min.js"></script>
<script src="../js/main.js"></script>
</head>
<body>

<header>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand">AngularJS Demo</a>
</div>
</div>
</nav>
</header>

<div class="container">

<div ng-controller="mainController">

<h1>{{name}}</h1>

</div>

</div>

</body>
</html>

main.js


// MODULE
var myApp = angular.module('angularApp', []);

// CONTROLLERS
myApp.controller('mainController', function ($scope) {

$scope.name="John";

});

To define an AngularJS app, we first need to define an angular.module. An Angular module is simply a collection of functions that are run when the application is “booted”. So in our html we have the ng-app=”angularApp” in out <html> tag. You can keep this in the body or anywhere else also. In your main.js we have
var myApp = angular.module(‘angularApp‘, []);
angular is the global angular object. Above line creates the Angular module named angularApp. (Don’t worry about the second argument – the empty array, [] – for now). The name has to be the same one given in ng-app in html.
In this example the view is the div element and everything inside it. The div element contains ng-controller attribute with the value mainController. Angular sees this custom attribute in the DOM and look for that controller function named – mainController.

myApp.controller(‘mainController’, function ($scope) {
Above line declares a function mainController which takes in $scope parameter. $scope is a service provided by angular. All angularJs services starts with a $ sign. So angular JS saw this $scope and recognized it and passed the $scope object via dependency Injection.  This $scope is the middle piece between your view and controller. Now inside this controller we have the $scope object, we then added a property ‘name’ to it and gave it some value. This property can now be accessed in that particular div.

di1

So how did angular passed the $scope object?. Lets look into the following code:


function testFunction(arg1,arg2,arg3){
console.log("test");
}

console.log(testFunction);

If you load this and see the console:

di2

Notice that you get the whole function as a string. So one can slice up this string to know what all parameter names are passed. Thats exactly what angular does. If you do a
console.log(angular.injector().annotate(testFunction));
you will get all the parameter names in an array. angular then finds any parameter with a $ starting sign. If its present, angular realizes it as a service and try to find it in its definition or dependencies and if it finds it it passes it to it.

There are many other services also, like the $log , $ filter etc. which can be passed to our controllers. Changing main.js


// MODULE
var myApp = angular.module('angularApp', []);

// CONTROLLERS
myApp.controller('mainController', function ($scope, $log, $filter) {

$log.info("Inside main controller");
$scope.name="John";
$log.debug("Before=="+$scope.name);
$scope.name=$filter('uppercase')($scope.name);
$log.debug("After=="+$scope.name);
});

Now we have injected 3 services in our controller. Angularjs will inject these so we can use them in our function.

di3

This is one of the way angular does dependency injection. There is another way, but before seeing that lets see minification first.
Minification in JavaScript, is the process of removing all unnecessary characters from source code without changing its functionality. These unnecessary characters usually include white space characters, new line characters, comments, changing variable names to shorter ones etc to shorten the size of files. Its always a good practice to minify your js files for production. Lets minify our main.js code


// MODULE
var myApp = angular.module('angularApp', []);

// CONTROLLERS
myApp.controller('mainController', function ($scope, $log) {

$log.info("Inside main controller");
$scope.name="John";

});

Minified code (I used http://jscompress.com/ you can use any):


var myApp=angular.module("angularApp",[]);myApp.controller("mainController",function(n,o){o.info("Inside main controller"),n.name="John"});

Notice that with all white spaces it also changed the variable names, so there is no $ sign, and we know that angular searches for these if it has to do a dependency injection. If you try to run above minified code, you will see

di4

In order to handle this, angularjs gave us another way to do dependency injection. Changing main.js:


// MODULE
var myApp = angular.module('angularApp', []);

// CONTROLLERS
myApp.controller('mainController', ["$scope", "$log",function ($scope, $log) {

$log.info("Inside main controller");
$scope.name="John";

}]);

So now the controller function takes an array as an second argument. In this array the last element is always a function that defines the controller and the previous elements are string variables that is suppose to be passed to the function. It has to be in the same order as they are passed in function. If we minify this code we get:


var myApp=angular.module("angularApp",[]);myApp.controller("mainController",["$scope","$log",function(n,o){o.info("Inside main controller"),n.name="John"}]);

This will run correctly. angular will map the 1st element to the first parameter of the function , 2nd element to 2nd parameter and so on.

di5

If your order doesn’t match it will pass wrong object to your function and you will get errors since you be using those object differently. Its recommended to use this version so that you can minify your code for production release.

%d bloggers like this: