Developer Guide: Angular HTML Compiler: Extending the Angular Compiler

Let's say that we want to create a new DOM element called <my:greeter/> that displays a greeting. We want this HTML source:

   <div ng:init="s='Hello'; n='World'">
      <my:greeter salutation="s" name="n"></my:greeter>
  </div>

to produce this DOM:

<div ng:init="s='Hello'; n='World'">
<my:greeter salutation="s" name="n"/>
  <span class="salutation">Hello</span>
  <span class="name">World</span>!
</my:greeter>
</div>

That is, the new <my:greeter></my:greeter> tag's salutation and name attributes should be transformed by the compiler such that two <span> tags display the values of the attributes, with CSS classes applied to the output.

The following code snippet shows how to write a following widget definition that will be processed by the compiler. Note that you have to declare the namespace my in the page:

angular.widget('my:greeter', function(compileElement){
  var compiler = this;
  compileElement.css('display', 'block');
  var salutationExp = compileElement.attr('salutation');
  var nameExp = compileElement.attr('name');
  return function(linkElement){
    var salutationSpan = angular.element('<span class="salutation"></span');
    var nameSpan = angular.element('<span class="name"></span>');
    linkElement.append(salutationSpan);
    linkElement.append(' ');
    linkElement.append(nameSpan);
    linkElement.append('!');
    this.$watch(salutationExp, function(value){
      salutationSpan.text(value);
     });
    this.$watch(nameExp, function(value){
    nameSpan.text(value);
    });
  };
});

Note: For more about widgets, see Understanding Angular Widgets and the widget API reference page.

Compilation process for <my:greeter>

Here are the steps that the compiler takes in processing the page that contains the widget definition above:

Compile Phase

  1. Recursively traverse the DOM depth-first.
  2. Find the angular.widget definition.
  3. Find and execute the widget's compileElement function, which includes the following steps:
    1. Add a style element with attribute display: block; to the template DOM so that the browser knows to treat the element as block element for rendering. (Note: because this style element was added on the template compileElement, this style is automatically applied to any clones of the template (i.e. any repeating elements)).
    2. Extract the salutation and name HTML attributes as angular expressions.
  4. Return the aggregate link function, which includes just one link function in this example.

Link Phase

  1. Execute the aggregate link function, which includes the following steps:
    1. Create a element set to the salutation class
    2. Create a element set to the name class.
  2. Add the span elements to the linkElement. (Note: be careful not to add them to the compileElement, because that's the template.)
  3. Set up watches on the expressions. When an expression changes, copy the data to the corresponding spans.

Related Topics

Related API