Sunday, 23 November 2014

Angular.js

Preface

Angular.js is a JavaScript Framework.

Directives

Angular Directive is a JavaScript code that is attached to something, and invoked when something happens. Angular is based on those directives. Each directive has a unique name that identifies it. There are built-in directives and you can also write custom directives for your app.

Angular uses camelCase for the unique ID that identifies a directive. For example, there is a built-in directive called "ngApp" (and not ng-app, NgApp, etc.).

Attributes

A very convenient way to use directives is to attach them to HTML Elements through HTML Attributes.

For each directive that exists (either built-in or one that we created), there is a matching HTML Attribute, with the same sequence of letters, but is capitalized with "spinal-case".

For example, for the "ngApp" directive there is a matching attribute "ng-app"

When Angular.js is bootstrapped it traverses over the HTML DOM, and searches for these attributes. It then invokes the corresponding directives that these attributes represent.

This is why Angular directives and Angular attributes are used interchangeably.

Angular uses:

  • camelCase for directives
  • spinal-case for attributes.

Example: attaching the "ngApp" directive with an attribute:

<html ng-app="store"> [...] </html>

Modules

Angular works in the context of a Module. A module encapsulates the JavaScript code that we use with angular. An Angular.js module is attached to a specific HTML Element, so that it will effect only that element.

Example:

var app = angular.module('store', []);

Two-Way Binding

Using a module achieves angular a great JavaScript feature. Angular uses a two-way binding, which means that data is binded from the HTML DOM to Angular.js JavaScript code, but also on the opposite direction, from Angular.js JavaScript code to the HTML DOM. In other words, any change in the data of the JavaScript will be automatically reflected in all the places where the HTML DOM refers to it, and also any change in the data of the HTML DOM will be automatically reflected in all the places where the JavaScript code is binded to.

"ngApp" Directive

The "ngApp" directive binds a module to an HTML element and boostraps Angular.js

Example: binding the "store" module

<html ng-app="store"> [...] </html>

"ngController" Directive

A Controller is a javascript code that resides on an Angular module. You use a controller to define different functionality and behaviours to different parts of the modules HTML.

A Controller is bound to a specific HTML DOM element, The element and its children will be affected by their bound controller.

It is usually bound by angular's "ng-controller" attribute.

Example: Module and Controller

(function(){ var app = angular.module('store', [ ]); app.controller('StoreController', function(){ this.product = gem; }); var gem = { name: 'Full Name', price: 2.95, description: 'Desc...' } })();
<!DOCTYPE html> <html ng-app="store"> <head> <link rel="stylesheet" type="text/css" href="bootsrap.min.css" /> </head> <body ng-controller="StoreController as store"> <div> <h1>{{store.product.name}}</h1> <h2>${{store.product.price}}</h2> <p>{{store.product.description}}</p> </div> <script type="text/javascript" src="angular.min.js"></script> <script type="text/javascript" src="app.js"></script> </body> </html>

Expression Binding

Expression bindings are evaluated by Angular and replaced with the evaluated result.

Angular expression is a JavaScript-like code snippet that is evaluated by Angular in the context of the current model scope, rather than within the scope of the global context (window).

Rather than a one-time insert, a binding will result in efficient continuous updates whenever the result of the expression evaluation changes.

An expression is denoted by double-curlies "{{ }}"

Example: String Concatenation Expression Binding 1

Nothing here {{'yet' + '!'}}

After the expression is processed by Angular, the HTML will contain the text: "Nothing here yet!".

Example: String Concatenation Expression Binding 2

<p>I am {{"hello" + " you"}}</p> ==> <p>hello you</p>

Example: Numeric Operation Expression Binding

<p>I am {{4 + 6}}</p> ==> <p>I am 10</p>

See more expressions at http://docs.angularjs.org/guide/expression

"ngClass" Directive

Binds a CSS class to an HTML Element with expression binding.

"ngClick" Directive

Binds a click event to an HTML Element.

"ngHide" Directive

Hides an HTML Element according to a condition that is evaluated with expression binding.

"ngInit" Directive

Runs JavaScript initialization before an HTML Element is evalauated.

"ngModel" Directive

Binds model data to an HTML Element.

Example 1:

<input ng-model="review.terms" type="checkbox" /> I agree to the terms

Example 2:

<input ng-model="review.color" type="color" value="red" /> <input ng-model="review.color" type="color" value="blue" /> <input ng-model="review.color" type="color" value="green" />

"ngRepeat" Directive

Example:

<li ng-repeat="product in store.products"> [...] </li>

"ngShow" Directive

The opposite of the "ng-hide" attribute. Shows an HTML Element according to a condition that is evaluated with expression binding.

Filters

Filters are used to format the output on the HTML. The most common filters are:

  • currency
  • date
  • uppercase
  • lowercase
  • limitTo
  • orderBy

Internationalization (i18n) and Localization (L10n)

Angular.js "$locale" service

It provides localization rules for various angular components. It works good in formatting of numbers, datetime and currency. It is used through the built-in angular filters.

It does not support localization of strings.

ECMScript (ES) i18n API drawback

ECMScript i18n API is supported only partially just by several browsers

angular-translate drawback

It misses all features that angular built-in interpolation brings (filters etc').

angular-gettext drawback

You loose all of the dynamics that angular provides, like two-way binding, and using angular features within directives.

angular-localization

Well, to use localization features in angular you need of a solution that is part of the ingilar framework.

You can use the angular-localization plugin written by Rahul Doshi, From the following URL:

http://doshprompt.github.io/angular-localization/

Automatic Bootstrapping ("ngApp" directive)

A very convenient way to bootstrap angular is to use the "ng-app" attribute. Angular will tie the module to the HTML element where the ng-app attribute resides, and it will traverse over the HTML from the element and downwards in the DOM tree and process it. For more information read more about the ngApp built-in directive.

Manual Bootstrapping

Manual bootstrapping does exactly what is done when you use the "ng-app" attribute. Using this attribute bootstraps angular automatically. The bootstrap process has two major phases:

  • Compile Phase - The "$compile" service traverses over the HTML DOM, starting from the root element, and looks for directives. For every directive it finds, it checks if it has a "$compile" function and than runs it.

    Each $compile function actually yanks out the content of the Angular.js bindings from the HTML template and replaces it with a placeholder, to make it possible to further compile the HTML DOM.

    The compile phase is the place to write code that changes the template. In this phase the $scope is not attached yet, so you cannot access the application data.

  • Linking Phase - Once we have located all the directives we can link them together.

    Every directive has a linking function. It actually creates the Angular.js View, which is a live HTML DOM that knows to react to events. So when the linking function runs we have created all the bindings. The linking function does not yet change anything on the screen because we have to kick the rootScope to tell him that we are ready to render the live view.

    But the linking function actually binds the template to the data. The compile function cannot do it because it does not have a scope.

Lets see an example of a bootstrap process:

//Bootsrapping is done after the HTML DOM is loaded window.onload = function() { //The root HTML DOM element of the angular application var $rootElement = angular.element(window.document); //The modules in the app. var modules = [ //The "ng" built-in module must be included 'ng', //Define our custom module. 'myApp', //Define our root element function($provide) { $provide.value('$rootElement', $rootElement); } ]; //A root injector var $injector = angular.injector(modules); //The "$compile" service. var $compile = $injector.get('$compile'); //Get a collection of the link functions //"Compile Phase". var compositeLinkFn = $compile($rootElement); //Attach the link functions to the scope //"Linking Phase" var $rootScope = $injector.get('$rootScope'); compositeLinkFn($rootScope); //We invoke the angular framework (go button) $rootScope.$apply(); }
'use strict'; var myApp = angular.module('myApp', []);

The "ng" module is a built-in module that must be always included.

We use an injector to get objects from angular.

We run the "Compile Phase":

$compile($rootElement)

We run the "Linking Phase":

compositeLinkFn($rootScope)

We kick the rootScope to render the live view:

$rootScope.$apply();

Custom Directive

We create a Custom Directive by invoking the "directive" function, of our module object.

The module's directive function must return:

  • A linking function:
    return function linkFn(scope, linkElement, attrs) { [...] }
  • A JSON with a compile function that encapsulates the linking function:

    return { compile: function compileFn(cElement, attrs) { [...] return function linkFn(scope, lElement, attrs) { [...] } } }
  • A JSON with a linking function only:

    return { link: function linkFn(scope, lElement, attrs) { [...] } }

For example, to create a 'demoGreet' custom directive for the "myApp" module:

'use strict'; myApp.directive('demoGreet', function($parse) { return function linkFn(scope, lElement, attrs) { console.log('linkingFn(', scope, lElement, attrs, ')'); lElement.text(Hello World); } });

On the HTML we refer to our directive with the same sequence of letters, but with a capitalization of spinal-case (dash-case):

<div demo-greet></div>

The Module's Directive Function

We have to distinguish between two scenarios when we attach a directive to an HTML Element:

  • Attaching a directive to a single instance without iteration (without ng-repeat):

    In this more simple scenario, the compile function and the linking function are run exactly once.

    In this more simple scenario the compile function and the link function refer to the same HTML element. Moreover, the cElement of the compile function and the lElement of the linking function are the same.

  • Attaching a directive to an iterator, (to an element that uses ng-repeat):

    In this advanced scenario, the compile function is run only once. It prepares the HTML template for iteration. On the other hand, the linking function is run per iteration, or in other words, per HTML element that is rendered by the ng-repeat directive.

    In this more advanced scenario, the cElement parameter of the compile function refers to HTML Element of the template. The lElement of the linking function, on the other hand, refers to the HTML Element of each iteration, or in other words, to the current HTML Element that is rendered by the iterator of ng-repeat.