<html ng-app> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> </head> <body> <div> The message is: {{message}} </div> </body> </html>

We have not defined the message property on the $rootScope and instead of throwing an error, the expression fails silently causing nothing to display for the message. Although the above expression is simple, a lot of functionality is thrown to us by the framework. AngularJs has compiled our html along with the expression and has produced what is known as a live view. It is live view because any change in model (through the scope) will be propagated to the view and any changes in view will be propagated to the model. This is two way databinding. We will test the model to view databinding first and through the console to understand how to change the model imperatively. When the following is executed through the console, the message will be displayed in the view automatically.

var injector = angular.element(document).injector(); var rootScope = injector.get("$rootScope"); rootScope.$apply(function(){rootScope.message = "Hello World!";})

Although we have talked about $rootScope we have not got hold of it yet. The $rootScope is not exposed by the AngularJS to the outside. AngularJS uses Dependency Injection and we can ask the injector for known services or objects to it (this is for demonstration purpose only. AngularJS will automatically fulfil our dependencies as we see later). We cant directly change the model from outside. Instead we have to use the $apply method on the scope to change the model and make AngularJS aware of it.

ngModel directive is used for propagating the view change to the model as follows.

<html ng-app> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> </head> <body> <div> The message is: {{message}} <br> <input ng-model="message"> </div> </body> </html>

Managing an application with directives and $rootScope alone will be cumbersome. The solution is controllers. Controller augments the $scope object with initial properties and behaviors. The first requirement for a controller is the scope object and for that we can use the ngController directive.

<html ng-app> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </head> <body> <div ng-controller="HelloController"> The message is: {{message}} <br> <input ng-model="message"> </div> </body> </html>

function HelloController($scope){ $scope.message = "Hello World!"; }

ngController, behind the scene creates a new scope inherited from the current scope ($rootScope here)through the $new method on the current scope. This newly created scope is then applied (using the javascript apply) against the specified controller function. When further directives and controllers are added, the scopes will imitate the DOM like tree structure with $rootNode as the base.

The controller we have just created lives in the global namespace and it feels like entirely detached from the AngularJS. The solution is to use the concept of modules. AngularJS is a web application framework and modules are the building blocks of well structured AngularJS application. A large scale AngularJS application may contain several modules like service, directive, and filter modules. It is the duty of an application level module to co-ordinate the different modules. In contrast to this pattern, an AngularJS application may start its life as a single application level module.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope){ $scope.message = "Hello World!"; console.log($scope.$parent); });

The inclusion of AngularJS script makes the angular namespace object available globally. A utility method on angular namespace object called module makes it easy to create a new module. The first parameter to the module method is the name of the module and if the second parameter of dependencies array is provided, it will create a module. If the second parameter is omitted, module method will try to retrieve the module of given name instead of creating a new one so we are passing an empty array as our first module does not have any dependencies.

Now our application is completely broken as our newly created module is not loaded by AngularJS. The fix is trivial, as ngApp directive accepts the module name to load during the initialization process.

<html ng-app="messageApp"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </head> <body> <div ng-controller="HelloController"> The message is: {{message}} <br> <input ng-model="message"> </div> </body> </html>

Back to our javascript code, AngularJS is automatically fulfilling our request of $scope through the facilities of Dependency Injection. Behind the scenes, AngularJS is using the injector to satisfy the requirements. Let’s ask for a thing that the AngularJS injector is not aware of, say the time at which our application has started.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope, startTime){ $scope.message = "Hello World!"; console.log($scope.$parent); });

startTime is our requirement or dependency that AngularJS is not aware of and hence it responds by the error message Error: Unknown provider: startTimeProvider <- startTime. The error message tells that AngularJS does not know how to cook a startTime object and we have to give the recipe of creating startTime. The simplest solution here is to create startTime ourself and then pass it to the AngularJS. value method on the module is just for that purpose.

var app = angular.module("messageApp", []); app.value("startTime", new Date()); app.controller("HelloController", function HelloController($scope, startTime){ $scope.message = "Hello World!"; console.log($scope.$parent); $scope.startedTime = startTime; });

<html ng-app="messageApp"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </head> <body> <div ng-controller="HelloController"> The message is: {{message}} <br> <input ng-model="message"> <br> Application Started At: {{startedTime}} </div> </body> </html>

Any object created by the injector is known as service. In the above code $scope and startTime are examples for services. Any service managed by AngularJS requires a unique name and that is why we have to pass the name as first parameter for the value method. value method is not that powerful as we ourself are creating the object and if this object has dependencies we have to fulfil them ourselves.

When running the above code our time display appears to be cryptic and this is a good time to introduce the concept of filters in AngularJS.

<html ng-app="messageApp"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </head> <body> <div ng-controller="HelloController"> The message is: {{message}} <br> <input ng-model="message"> <br> Application Started At: {{startedTime | date:'medium'}} </div> </body> </html>

Filters are used to format expressions. In the above case, date filter has formatted the data. For formatting the date we have passed ‘medium’ as the parameter to date filter by using the : as separator. Now we will update the application by displaying the elapsed seconds since starting the application.

<html ng-app="messageApp"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </head> <body> <div ng-controller="HelloController"> The message is: {{message}} <br> <input ng-model="message"> <br> Application Started At: {{startedTime | date:'medium'}} <br> Elapsed: {{ elapsed }} seconds </div> </body> </html>

var app = angular.module("messageApp", []); app.value("startTime", new Date()); app.controller("HelloController", function HelloController($scope, startTime){ $scope.message = "Hello World!"; console.log($scope.$parent); $scope.startedTime = startTime; var intervalId; intervalId = setInterval(function(){ $scope.$apply(function(){ var elapsedMilliSeconds = (new Date().getTime() - $scope.startedTime.getTime()); $scope.elapsed = Math.round(elapsedMilliSeconds / 1000); }); }, 2000); });

We are using the plain old setInterval method of javscript and wrapping the elapsed time assignment inside the $apply method of the scope object in order to convey the assignment to the AngularJS application. Although the example works fine, we are measuring the time when the javascript file is loaded and not the actual start up of the AngularJS application. Module expose config and run methods to hook in to the configuration phase and aplication startup phase. We will revert the code to utilize these hooks.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope, startTime){ $scope.message = "Hello World!"; console.log($scope.$parent); $scope.startedTime = startTime; var intervalId; intervalId = setInterval(function(){ $scope.$apply(function(){ var elapsedMilliSeconds = (new Date().getTime() - $scope.startedTime.getTime()); $scope.elapsed = Math.round(elapsedMilliSeconds /1000); }); }, 2000); }); //app.run(function($provide){ // $provide.value("startTime", new Date()); // Will not work as $provide could not be injected in run phase //}); app.config(function($provide){ $provide.value("startTime", new Date()); });

We are now exposed to differences of run and config blocks. We could not inject $provide to run handler as it is too late to provide recipe for object creation. Only values and constants could be injected in run phase. So we will override the service value in run phase, instead of using the $provide.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope, startTime){ $scope.message = "Hello World!"; console.log($scope.$parent); $scope.startedTime = startTime; var intervalId; intervalId = setInterval(function(){ $scope.$apply(function(){ var elapsedMilliSeconds = (new Date().getTime() - $scope.startedTime.getTime()); $scope.elapsed = Math.round(elapsedMilliSeconds /1000); }); }, 2000); }); app.run(function(startTime){ // startTime = new Date(); re-assignment is not going to work as pointed out by llia choly in comments startTime.setTime((new Date()).getTime()); // call setTime method to update the new time }); app.config(function($provide){ $provide.value("startTime", new Date()); });

Another way to provide recipe of object creation is the constant method. We will introduce MILLIS_IN_SECONDS constant to our application. One distinguishing feature of constant is that it could be injected in to the configuration phase which is not possible with the values.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope, startTime, MILLIS_IN_SECONDS){ $scope.message = "Hello World!"; $scope.startedTime = startTime; var intervalId; intervalId = setInterval(function(){ $scope.$apply(function(){ var elapsedMilliSeconds = (new Date().getTime() - $scope.startedTime.getTime()); $scope.elapsed = Math.round(elapsedMilliSeconds / MILLIS_IN_SECONDS); }); }, 2000); }); app.run(function(startTime){ //startTime = new Date(); startTime.setTime((new Date()).getTime()); }); app.config(function($provide, MILLIS_IN_SECONDS ){ $provide.value("startTime", new Date()); console.log(MILLIS_IN_SECONDS); }); app.constant("MILLIS_IN_SECONDS", 1000);

When we have an object creation function, factory is the way to register that recipe. With the factory method we register a factory along with a name. A factory is just a method used to create an object.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope, startTime, elapsedEstimator){ $scope.message = "Hello World!"; console.log($scope.$parent); $scope.startedTime = startTime; var intervalId; intervalId = setInterval(function(){ $scope.$apply(function(){ $scope.elapsed = elapsedEstimator.elapsed(); }); }, 2000); }); app.run(function(startTime){ //startTime = new Date(); startTime.setTime((new Date()).getTime()); }); app.config(function($provide, MILLIS_IN_SECONDS ){ $provide.value("startTime", new Date()); console.log(MILLIS_IN_SECONDS); }); app.constant("MILLIS_IN_SECONDS", 1000); app.factory("elapsedEstimator", function(startTime, MILLIS_IN_SECONDS){ return { elapsed: function(){ var elapsedMilliSeconds = (new Date().getTime() - startTime.getTime()); var elapsed = Math.round(elapsedMilliSeconds / MILLIS_IN_SECONDS); return elapsed; }}; });

Since function is first class citizen in javascript we can register a function returning function as a factory also. factory method is the most widely used dependency registration mechanism in AngularJS since it is very flexible.

It is time to examine the final dependency registration utility method service.

var app = angular.module("messageApp", []); app.controller("HelloController", function HelloController($scope, startTime, elapsedEstimator){ $scope.message = "Hello World!"; console.log($scope.$parent); $scope.startedTime = startTime; var intervalId; intervalId = setInterval(function(){ $scope.$apply(function(){ $scope.elapsed = elapsedEstimator.elapsed(); }); }, 2000); }); app.run(function(startTime){ //startTime = new Date(); startTime.setTime((new Date()).getTime()); }); app.config(function($provide, MILLIS_IN_SECONDS ){ $provide.value("startTime", new Date()); console.log(MILLIS_IN_SECONDS); }); app.constant("MILLIS_IN_SECONDS", 1000); app.service("elapsedEstimator", ElapsedEstimator ); function ElapsedEstimator(startTime, MILLIS_IN_SECONDS ){ this.elapsed = function(){ var elapsedMilliSeconds = (new Date().getTime() - startTime.getTime()); var elapsed = Math.round(elapsedMilliSeconds / MILLIS_IN_SECONDS); return elapsed; } }

ElapsedEstimator constructor has two dependencies and hence it could not be registered as a value (startTime parameter will be available only later in the lifecycle of the application). This constructor could be easily registered by service method and all of its dependencies will be fulfilled automatically.