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.
|