While angular might look like just a cool way to build web applications, the core of angular is actually an HTML compiler. The default HTML transformations that this compiler provides are useful for building generic apps, but you can also use them to create a domain-specific language for building specific types of web applications.
The compiler allows you to add behavior to existing HTML through widgets, directives, and text markup.
All of this compilation happens in the web browser, meaning no server is involved.
This section describes the steps that angular's HTML compiler goes through. If you use
ng:autobind
in your application, this compilation process happens automatically when the
application is initialized (e.g. when the user loads the app in a browser). If you're an advanced
user using manual bind mode, you can decide when and how often the compilation happens.
First, a bit of background of what the compilation step is for. Every type of
widget
, markup
, and
directive
in angular is defined with a compile function, and that
compile function returns an optional link function. Here is the relationship between the two:
Note that angular's built-in widgets, markup, and directives have predefined compile and link functions that you don't need to modify. However, if you're writing your own widgets, markup, or directives, you write compile and link functions. Refer to the Compiler API for more information.
When the HTML compiler compiles a page, it goes through 3 phases: Compile, Create Root Scope, and Link.
Note that while the compile function is executed exactly once, the link function can be executed multiple times: once for each iteration in a repeater.
The compilation process is best understood through example. Let's say that in your namespace my,
you want to create a new DOM element
If we want this HTML source:
<div ng:init="salutation='Hello'; name='World'"> <my:greeter salutation="salutation" name="name"/> </div>
To produce this DOM:
<div ng:init="salutation='Hello'; name='World'"> <my:greeter salutation="salutation" name="name"/> <span class="salutation">Hello</span> <span class="name">World</span>! </my:greeter> </div>
Write this widget definition (assuming you've already declared the my namespace 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(compiler.text(' ')); linkElement.append(nameSpan); linkElement.append(compiler.text('!')); this.$watch(salutationExp, function(value){ salutationSpan.text(value); }); this.$watch(nameExp, function(value){ nameSpan.text(value); }); }; });
Note: For more about widgets, see Widget
.
Here are the steps that the compiler goes through for the page that contains this widget definition:
If you define your own widgets, markup, or directives, you need to access the compiler API. This section describes the methods on the compiler that you can call.
Note: As of 12 August 2010, these methods are subject to change.
Recall that the compile function's this is a reference to the compiler.
compile(element)
- returns linker
- Invoke new instance of compiler to compile a DOM element
and return a linker function. You can apply the linker function to the original element or a
clone of the original element. The linker function returns a scope.comment(commentText)
- returns element
- Create a comment element.element(elementName)
- returns element
- Create an element by name.text(text)
- returns element
- Create a text element.descend([set])
- returns descend
- State Get or set the current descend state. If true the
compiler will descend to children elements.directives([set])
- returns directive
- State Get or set the current directives processing
state. The compiler will process directives only when directives set to true.