@ngdoc overview @name angular.module.ng.$compileProvider.directive @description Directives are a way to teach HTML new tricks. During DOM compilation directives are matched against the HTML and executed. This allows directives to register behavior, or transform the DOM. Angular comes with a built in set of directives which are useful for building web applications but can be extended such that HTML can be turned into a declarative domain specific language (DSL). # Invoking directives from HTML Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and `data-ng-bind`. The directives can be placed in element names, attributes, class names, as well as comments. Here are some equivalent examples of invoking `ngBind`.
Directives can be invoked in many different ways, but are equivalent in the end result as shown in the following example.
# Compilation process, and directive matching Compilation of HTML happens in three phases: 1. First the HTML is parsed into DOM using the standard browser API. This is important to realize because the templates must be parsable HTML. This is in contrast to most templating systems that operate on strings, rather then on DOM elements. 2. The compilation of the DOM is performed by the call to {@link angular.module.ng.$compile $compile()} method. The method traverses the DOM and matches the directives. If a match is found it is added to the list of directives associated with the given DOM element. Once all directives for a given DOM element have been identified they are sorted by priority and their `compile()` functions are executed. The directive compile function has a chance to modify the DOM structure and is responsible for producing a `link()` function explained next. The {@link angular.module.ng.$compile $compile()} method returns a combined linking function, which is a collection of all of the linking functions returned from the individual directive compile functions. 3. Link the template with scope by calling the liking function returned from the previous step. This in turn will call the linking function of the individual directives allowing them to register any listeners on the elements and set up any {@link angular.module.ng.$rootScope.Scope#.watch watches} with the {@link angular.module.ng.$rootScope.Scope scope}. The result of this is a live binding between the scope and the DOM. A change in the scope is reflected in the DOM.Hello {{username}}!
var $compile = ...; // injected into your code var scope = ...; var html = ''; // Step 1: parse HTML into DOM element var template = angular.element(html); // Step 2: compile the template var linkFn = $compile(template); // Step 3: link the compiled template with the scope. linkFn(scope);## Reasons behind the compile/link separation At this point you may wonder why is the compile process broken down to a compile and link phase. To understand this, lets look at a real world example with repeater:
Hello {{user}}, you have these actions:
var $compileProvider = ...;
$compileProvider.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
priority: 0,
template: '',
templateUrl: 'directive.html',
restrict: 'EACM',
scope: false,
compile: function compile(tElement, tAttrs) {
return {
pre: function preLink(scope, iElement, iAttrs) { ... },
post: function postLink(scope, iElement, iAttrs) { ... }
}
},
link: function postLink(scope, iElement, iAttrs) { ... }
};
return directiveDefinitionObject;
});
In most cases you will not need such fine control and so the above can be simplified. All of the
different parts of this skeleton are explained in following sections. In this section we are
interested only isomers of this skeleton.
It is rare that you need `preLink` method since most directives use the `postLink` method.
Therefore the above can be simplified as:
var $compileProvider = ...;
$compileProvider.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
compile: function compile(tElement, tAttrs) {
return function postLink(scope, iElement, iAttrs) { ... }
}
};
return directiveDefinitionObject;
});
Most directives concern themselves only with instances not with template transformations allowing
further simplification:
var $compileProvider = ...;
$compileProvider.directive('directiveName', function factory(injectables) {
return function postLink(scope, iElement, iAttrs) { ... }
});
## Factory method
The factory method is responsible for creating the directive. It is invoked only once, when the
{@link angular.module.ng.$compile compiler} matches the directive for the first time. You can
perform any initialization work here. The method is invoked using the {@link
http://localhost:8000/build/docs/api/angular.module.AUTO.$injector#invoke $injector.invoke} which
makes it injectable following all of the rules of injection annotation.
## Directive Definition Object
The directive definition object provides instructions to the {@link angular.module.ng.$compile
compiler}. The attributes are:
* `priority` - When there are multiple directives defined on a single DOM element, sometimes it
is necessary to specify the order in which the directives are applied. The `priority` is used
to sort the directives before their `compile` functions get called. Higher `priority` goes
first. The order of directives within the same priority is undefined.
* `terminal` - If set to true then the current `priority` will be the last set of directives
which will execute (this means that any directives at the current priority will still execute
as the order of execution on same `priority` is undefined).
* `scope` - If set to true, then a new scope will be created for this directive. It is an error
to have two directives on the same element both requesting new scope. The new scope rule does
not apply for the root of the template since the root of the template always gets a new scope.
* `restrict` - String of subset of `EACM` which restricts the directive to a specific directive
declaration style.
* `E` - Element name: `
function compile(tElement, tAttrs) { ... }
Compile function deals with transforming the template DOM. Since most directives do not do
template transformation, it is not used often. Examples which require compile functions are
directives which transform template DOM such as {@link
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} or load the contents
asynchronously such as {@link angular.module.ng.$compileProvider.directive.ng:view ng:view}. The
compile functions takes the following arguments.
* `tElement` - template element - The element where the directive has been declared. It is
safe to do template transformation on the element and child elements only.
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
between all directive compile functions. See {@link
angular.module.ng.$compileProvider.directive.Attributes Attributes}
NOTE: The template instance and the link instance may not be the same objects if the template has
been cloned. For this reason it is not safe to do anything other the DOM transformation.
Specifically listener registration as not allowed inside the compile function.
## Link function
function link(scope, iElement, iAttrs) { ... }
Compile function is responsible for registering DOM listeners as well as updating the DOM. It is
executed after the template has been cloned. This is where most of the directive logic will be
put.
* `scope` - {@link angular.module.ng.$rootScope.Scope Scope} - The scope to be used be the
directive for registering {@link angular.module.ng.$rootScope.Scope#.watch watches}.
* `iElement` - instance element - The element where the directive is to be used. It is safe to
manipulate the children of the element only in `postLink` function since the children have
already been linked.
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
between all directive linking functions. See {@link
angular.module.ng.$compileProvider.directive.Attributes Attributes}
### Pre link function
Executed before the child elements are linked. Not safe to do DOM transformation since the
compiler linking function will fail to locate the correct elements for linking.
### Post link function
Executed after the child elements are linked. Safe to do DOM transformation in here.
## Attributes
Attributes object is a way of accessing element attributes which:
* *normalize attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to
the attributes.
* *directive inter-communication:* All directives share the same instance of the attributes
object which allows the directives to use the attributes object as inter directive
communication.
* *supports interpolation:* Interpolation attributes are assigned to the attribute object
allowing other directives to read the interpolated value.
# Creating Widgets
It is often desirable to replace a single directive with a more complex DOM structure. This
allows the directives to become a short hand for reusable components from which applications
can be built.
Following is an example of building a reusable widget.