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

<pre>
  <span ng-bind="exp"></span>
  <span class="ng-bind: exp;"></span>
  <ng-bind></ng-bind>
  <!-- directive: ng-bind exp --!>
</pre>

Directives can be invoked in many different ways, but are equivalent in the end result as shown in
the following example.

<doc:example>
  <doc:source >
   <script>
     function Ctrl1($scope) {
       $scope.name = 'angular';
     }
   </script>
   <div ng-controller="Ctrl1">
     Hello <input ng-model='name'> <hr/>
     &ltspan ng:bind="name"&gt <span ng:bind="name"></span> <br/>
     &ltspan ng_bind="name"&gt <span ng_bind="name"></span> <br/>
     &ltspan ng-bind="name"&gt <span ng-bind="name"></span> <br/>
     &ltspan data-ng-bind="name"&gt <span data-ng-bind="name"></span> <br/>
     &ltspan x-ng-bind="name"&gt <span x-ng-bind="name"></span> <br/>
     &ltspan class="ng-bind: name;"&gt <span class="ng-bind: name;"></span> <br/>
   </div>
  </doc:source>
  <doc:scenario>
    it('should load template1.html', function() {
      expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular');
    });
  </doc:scenario>
</doc:example>

# String interpolation

During the compilation process the {@link angular.module.ng.$compile compiler} matches text and
attributes using the {@link angular.module.ng.$interpolate $interpolate} service to see if they
contain embedded expressions. These expressions are registered as {@link
angular.module.ng.$rootScope.Scope#.watch watches} and will update as part of normal {@link
angular.module.ng.$rootScope.Scope#.digest digest} cycle. An example of interpolation is shown
here:

<pre>
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
</pre>

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

<pre>
  var $compile = ...; // injected into your code
  var scope = ...;

  var html = '<div ng-bind='exp'></div>';

  // 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);
</pre>

## 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:

<pre>
  Hello {{user}}, you have these actions:
  <ul>
    <li ng:repeat="action in user.actions">
      {{action.description}}
    </li>
  </ul>
</pre>

The short answer is that compile and link separation is needed any time a change in model causes
a change in DOM structure such as in repeaters.

When the above example is compiled, the compiler visits every node and looks for directives. The
`{{user}}` is an example of {@link angular.module.ng.$interpolate interpolation} directive. {@link
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} is another directive. But {@link
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} has a dilemma. It needs to be
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
to save a clean copy of the `li` element for cloning purposes and as new `action`s are inserted,
the template `li` element needs to be cloned and inserted into `ul`. But cloning the `li` element
is not enough. It also needs to compile the `li` so that its directives such as
`{{action.descriptions}}` evaluate against the right {@link angular.module.ng.$rootScope.Scope
scope}. A naive method would be to simply insert a copy of the `li` elemnt and then compile it.
But compiling on every `li` element clone would be slow, since the compilation requires that we
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
repeater which needs to unroll 100 items we would quickly run into performance problem.

The solution is to break the compilation process into two phases the compile phase where all of
the directives are identified and sorted by priority, and a linking phase where any work which
links a specific instance of the {@link angular.module.ng.$rootScope.Scope scope} and the specific
instance of an `li` is performed.

{@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} works by preventing the
compilation process form descending into `li` element. Instead the {@link
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} directive compiles `li`
seperatly. The result of of the `li` element compilation is a linking function which contains all
of the directives contained in the `li` element ready to be attached to a specific clone of `li`
element. At runtime the {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat}
watches the expression and as items are added to the array it clones the `li` element, creates a
new {@link angular.module.ng.$rootScope.Scope scope} for the cloned `li` element and calls the
link function on the cloned `li`.

Summary:

  * *compile function* - The compile function is relatively rare in directives, since most
    directives are concerned with working with a specific DOM element instance rather then
    transforming the template DOM element. Any operation which can be shared among the instance of
    directives should be moved to the compile function for performance reasons.

  * *link function* - It is rare for the directive not to have a link function. Link function
    allows the directive to register listeners to the specific cloned DOM element instance as well
    as to copy content into the DOM from the scope.


# Writing directives (short version)

In this example we will build a directive which displays the current time.

<doc:example module="time">
  <doc:source>
   <script>
     function Ctrl2($scope) {
       $scope.format = 'M/d/yy h:mm:ss a';
     }

     angular.module('time', [], function($compileProvider) {
       // Register the 'myCurrentTime' directive factory method.
       // We inject $defer and dateFilter service since the factory method is DI.
       $compileProvider.directive('myCurrentTime', function($defer, dateFilter) {
         // return the directive link function. (compile function not needed)
         return function(scope, element, attrs) {
           var format,  // date format
               deferId; // deferId, so that we can cancel the time updates

           // used to update the UI
           function updateTime() {
             element.text(dateFilter(new Date(), format));
           }

           // watch the expression, and update the UI on change.
           scope.$watch(attrs.myCurrentTime, function(value) {
             format = value;
             updateTime();
           });

           // schedule update in one second
           function updateLater() {
             // save the deferId for canceling
             deferId = $defer(function() {
               updateTime(); // update DOM
               updateLater(); // schedule another update
             }, 1000);
           }

           // listen on DOM destroy (removal) event, and cancel the next UI update
           // to prevent updating time ofter the DOM element was removed.
           element.bind('$destroy', function() {
             $defer.cancel(deferId);
           });

           updateLater(); // kick of the UI update process.
         }
       });
     });

   </script>
   <div ng-controller="Ctrl2">
     Date format: <input ng-model='format'> <hr/>
     Current time is: <span my-current-time="format"></span
   </div>
  </doc:source>
  <doc:scenario>
  </doc:scenario>
</doc:example>


# Writing directives (long version)

The full skeleton of the directive is shown here:

<pre>
  var $compileProvider = ...;

  $compileProvider.directive('directiveName', function factory(injectables) {
    var directiveDefinitionObject = {
      priority: 0,
      template: '<div></div>',
      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;
  });
</pre>

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:

<pre>
  var $compileProvider = ...;

  $compileProvider.directive('directiveName', function factory(injectables) {
    var directiveDefinitionObject = {
      compile: function compile(tElement, tAttrs) {
        return function postLink(scope, iElement, iAttrs) { ... }
      }
    };
    return directiveDefinitionObject;
  });
</pre>

Most directives concern themselves only with instances not with template transformations allowing
further simplification:

<pre>
  var $compileProvider = ...;

  $compileProvider.directive('directiveName', function factory(injectables) {
    return function postLink(scope, iElement, iAttrs) { ... }
  });
</pre>


## 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: `<my-directive></my-directive>`
    * `A` - Attribute: `<div my-directive="exp"></div>`
    * `C` - Class: `<div class="my-directive: exp;"></div>`
    * `M` - Comment: `<!-- directive: my-directive exp -->`

  * `template` - replace the current element with the contents of the HTML. The HTML may have
    `<<content>>` string embedded in itself, in which case the current element content
    will be transferred there. The replacement process migrates all of the attributes / classes
    from the old element to the new one. See Creating Widgets section below for more information.

  * `templateURL` - Same as `template` but the template is loaded from the specified URL. Because
    the template loading is asynchronous the compilation/linking is suspended until the template
    is loaded.

  * `compile`: This is the compile function described in the section below.

  * `link`: This is the link function described in the section below. This property is used only
    if the `compile` property is not defined.

## Compile function

<pre>
  function compile(tElement, tAttrs) { ... }
</pre>

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

<pre>
  function link(scope, iElement, iAttrs) { ... }
</pre>

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


<doc:example module="zippyModule">
  <doc:source>
   <script>
     function Ctrl3($scope) {
       $scope.title = 'Lorem Ipsum';
       $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
     }

     angular.module('zippyModule', [], function($compileProvider) {
       $compileProvider.directive('zippy', function(){
         return {
           // This HTML will replace the zippy directive.
           replace: true,
           template: '<div>' +
                       '<div class="title"></div>' +
                       '<div class="body"><<content>></div>' +
                     '</div>',
           // The linking function will add behavior to the template
           link: function(scope, element, attrs) {
                 // Title element
             var title = angular.element(element.children()[0]),
                 // Opened / closed state
                 opened = true;

             // Watch the zippy-title attribute, copy changes to title element
             scope.$watch(
               function(){ return attrs.zippyTitle; },
               function(value) { return title.text(value); }
             );

             // Clicking on title should open/close the zippy
             title.bind('click', toggle);

             // Toggle the closed/opened state
             function toggle() {
               opened = !opened;
               element.removeClass(opened ? 'closed' : 'opened');
               element.addClass(opened ? 'opened' : 'closed');
             }

             // initialize the zippy
             toggle();
           }
         }
       });
     });

   </script>
   <style>
     .zippy {
       border: 1px solid black;
       display: inline-block;
       width: 250px;
     }
     .zippy.opened > .title:before { content: '▼ '; }
     .zippy.opened > .body { display: block; }
     .zippy.closed > .title:before { content: '► '; }
     .zippy.closed > .body { display: none; }
     .zippy > .title {
       background-color: black;
       color: white;
       padding: .1em .3em;
       cursor: pointer;
     }
     .zippy > .body {
       padding: .1em .3em;
     }
   </style>
   <div ng-controller="Ctrl3">
     Title: <input ng-model="title"> <br>
     Text: <textarea ng-model="text"></textarea>
     <hr>
     <div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>
   </div>
  </doc:source>
  <doc:scenario>
    it('should bind and open / close', function() {
      input('title').enter('TITLE');
      input('text').enter('TEXT');
      expect(element('.title').text()).toEqual('Details: TITLE...');
      expect(binding('text')).toEqual('TEXT');

      expect(element('.zippy').prop('className')).toMatch(/closed/);
      element('.zippy > .title').click();
      expect(element('.zippy').prop('className')).toMatch(/opened/);
    });
  </doc:scenario>
</doc:example>


