mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
163 lines
6.9 KiB
Text
163 lines
6.9 KiB
Text
@workInProgress
|
|
@ngdoc overview
|
|
@name Developer Guide: Compiler
|
|
@description
|
|
|
|
#Compiler
|
|
|
|
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.
|
|
|
|
# The compilation process
|
|
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
|
|
{@link angular.widget widget}, {@link angular.markup markup}, and
|
|
{@link angular.directive 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:
|
|
|
|
* **compile function** - registers a listener for the widget, markup, or directive's expression.
|
|
This function is called exactly once.
|
|
* **link function** - sets up the listener. This function can be called multiple times, once per
|
|
cloned DOM element (e.g. repeating element).
|
|
|
|
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.
|
|
|
|
## 1. Compile Phase
|
|
|
|
* Recursively traverse the DOM, depth-first.
|
|
* Look for a matching compile function of type widget, then markup, then directive.
|
|
* If a compile function is found then execute it.
|
|
* When the compile function completes, it should return a link function. Aggregate this link
|
|
function with all link functions returned previously by step 1c.
|
|
* Repeat steps 1c and 1d for all compile functions found. The result of the compilation step is
|
|
the aggregate link function, which comprises all of the individual link functions.
|
|
|
|
## 2. Create Root Scope
|
|
|
|
* Inject all of the services into the root scope.
|
|
|
|
## 3. Link Phase
|
|
|
|
* Execute the aggregate link function with the root scope. The aggregate link function calls all
|
|
the individual link functions that were generated in the compile phase.
|
|
* If there are any clones of the DOM caused by repeating elements, call the link function multiple
|
|
times, one for each repeating item.
|
|
|
|
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.
|
|
|
|
# Example
|
|
|
|
The compilation process is best understood through example. Let's say that in your namespace my,
|
|
you want to create a new DOM element <my:greeter/>, which should display a greeting.
|
|
|
|
If we want this HTML source:
|
|
|
|
<pre>
|
|
<div ng:init="salutation='Hello'; name='World'">
|
|
<my:greeter salutation="salutation" name="name"/>
|
|
</div>
|
|
</pre>
|
|
|
|
To produce this DOM:
|
|
|
|
<pre>
|
|
<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>
|
|
</pre>
|
|
|
|
Write this widget definition (assuming you've already declared the my namespace in the page):
|
|
|
|
|
|
<pre>
|
|
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);
|
|
});
|
|
};
|
|
});
|
|
</pre>
|
|
|
|
Note: For more about widgets, see {@link angular.widget Widget}.
|
|
|
|
## Compilation process for this example
|
|
|
|
Here are the steps that the compiler goes through for the page that contains this widget definition:
|
|
|
|
### Compile Phase
|
|
|
|
* Recursively traverse the DOM depth-first.
|
|
* Find the angular.widget definition.
|
|
* Find and execute the widget's compileElement function, which includes the following steps:
|
|
* 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)).
|
|
* Extract the salutation and name HTML attributes as angular expressions.
|
|
* Return the aggregate link function, which includes just one link function in this example.
|
|
|
|
### Link Phase
|
|
|
|
* Execute the aggregate link function, which includes the following steps:
|
|
* Create a <span> element set to the salutation class
|
|
* Create a <span> element set to the name class.
|
|
* Add the span elements to the linkElement. (Note: be careful not to add them to the
|
|
compileElement, because that's the template.)
|
|
* Set up watches on the expressions. When an expression changes, copy the data to the
|
|
corresponding spans.
|
|
|
|
|
|
## Compiler API
|
|
|
|
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.
|
|
|