|
| 1 | +@workInProgress |
| 2 | +@ngdoc overview |
| 3 | +@name Developer Guide: Compiler |
| 4 | +@description |
| 5 | + |
| 6 | +#Compiler |
| 7 | + |
| 8 | +While angular might look like just a cool way to build web applications, the core of angular is |
| 9 | +actually an HTML compiler. The default HTML transformations that this compiler provides are useful |
| 10 | +for building generic apps, but you can also use them to create a domain-specific language for |
| 11 | +building specific types of web applications. |
| 12 | + |
| 13 | +The compiler allows you to add behavior to existing HTML through widgets, directives, and text |
| 14 | +markup. |
| 15 | + |
| 16 | +All of this compilation happens in the web browser, meaning no server is involved. |
| 17 | + |
| 18 | +# The compilation process |
| 19 | +This section describes the steps that angular's HTML compiler goes through. If you use |
| 20 | +`ng:autobind` in your application, this compilation process happens automatically when the |
| 21 | +application is initialized (e.g. when the user loads the app in a browser). If you're an advanced |
| 22 | +user using manual bind mode, you can decide when and how often the compilation happens. |
| 23 | + |
| 24 | +First, a bit of background of what the compilation step is for. Every type of |
| 25 | +{@link angular.widget widget}, {@link angular.markup markup}, and |
| 26 | +{@link angular.directive directive} in angular is defined with a compile function, and that |
| 27 | +compile function returns an optional link function. Here is the relationship between the two: |
| 28 | + |
| 29 | + * **compile function** - registers a listener for the widget, markup, or directive's expression. |
| 30 | + This function is called exactly once. |
| 31 | + * **link function** - sets up the listener. This function can be called multiple times, once per |
| 32 | + cloned DOM element (e.g. repeating element). |
| 33 | + |
| 34 | +Note that angular's built-in widgets, markup, and directives have predefined compile and link |
| 35 | +functions that you don't need to modify. However, if you're writing your own widgets, markup, or |
| 36 | +directives, you write compile and link functions. Refer to the Compiler API for more information. |
| 37 | + |
| 38 | +When the HTML compiler compiles a page, it goes through 3 phases: Compile, Create Root Scope, and |
| 39 | +Link. |
| 40 | + |
| 41 | +## 1. Compile Phase |
| 42 | + |
| 43 | + * Recursively traverse the DOM, depth-first. |
| 44 | + * Look for a matching compile function of type widget, then markup, then directive. |
| 45 | + * If a compile function is found then execute it. |
| 46 | + * When the compile function completes, it should return a link function. Aggregate this link |
| 47 | + function with all link functions returned previously by step 1c. |
| 48 | + * Repeat steps 1c and 1d for all compile functions found. The result of the compilation step is |
| 49 | + the aggregate link function, which comprises all of the individual link functions. |
| 50 | + |
| 51 | +## 2. Create Root Scope |
| 52 | + |
| 53 | + * Inject all of the services into the root scope. |
| 54 | + |
| 55 | +## 3. Link Phase |
| 56 | + |
| 57 | + * Execute the aggregate link function with the root scope. The aggregate link function calls all |
| 58 | + the individual link functions that were generated in the compile phase. |
| 59 | + * If there are any clones of the DOM caused by repeating elements, call the link function multiple |
| 60 | + times, one for each repeating item. |
| 61 | + |
| 62 | +Note that while the compile function is executed exactly once, the link function can be executed |
| 63 | +multiple times: once for each iteration in a repeater. |
| 64 | + |
| 65 | +# Example |
| 66 | + |
| 67 | +The compilation process is best understood through example. Let's say that in your namespace my, |
| 68 | +you want to create a new DOM element <my:greeter/>, which should display a greeting. |
| 69 | + |
| 70 | +If we want this HTML source: |
| 71 | + |
| 72 | +<pre> |
| 73 | +<div ng:init="salutation='Hello'; name='World'"> |
| 74 | + <my:greeter salutation="salutation" name="name"/> |
| 75 | +</div> |
| 76 | +</pre> |
| 77 | + |
| 78 | +To produce this DOM: |
| 79 | + |
| 80 | +<pre> |
| 81 | +<div ng:init="salutation='Hello'; name='World'"> |
| 82 | + <my:greeter salutation="salutation" name="name"/> |
| 83 | + <span class="salutation">Hello</span> |
| 84 | + <span class="name">World</span>! |
| 85 | + </my:greeter> |
| 86 | +</div> |
| 87 | +</pre> |
| 88 | + |
| 89 | +Write this widget definition (assuming you've already declared the my namespace in the page): |
| 90 | + |
| 91 | + |
| 92 | +<pre> |
| 93 | +angular.widget('my:greeter', function(compileElement){ |
| 94 | + var compiler = this; |
| 95 | + compileElement.css('display', 'block'); |
| 96 | + var salutationExp = compileElement.attr('salutation'); |
| 97 | + var nameExp = compileElement.attr('name'); |
| 98 | + return function(linkElement){ |
| 99 | + var salutationSpan = angular.element('<span class="salutation"></span'); |
| 100 | + var nameSpan = angular.element('<span class="name"></span>'); |
| 101 | + linkElement.append(salutationSpan); |
| 102 | + linkElement.append(compiler.text(' ')); |
| 103 | + linkElement.append(nameSpan); |
| 104 | + linkElement.append(compiler.text('!')); |
| 105 | + this.$watch(salutationExp, function(value){ |
| 106 | + salutationSpan.text(value); |
| 107 | + }); |
| 108 | + this.$watch(nameExp, function(value){ |
| 109 | + nameSpan.text(value); |
| 110 | + }); |
| 111 | + }; |
| 112 | +}); |
| 113 | +</pre> |
| 114 | + |
| 115 | +Note: For more about widgets, see {@link angular.widget Widget}. |
| 116 | + |
| 117 | +## Compilation process for this example |
| 118 | + |
| 119 | +Here are the steps that the compiler goes through for the page that contains this widget definition: |
| 120 | + |
| 121 | +### Compile Phase |
| 122 | + |
| 123 | + * Recursively traverse the DOM depth-first. |
| 124 | + * Find the angular.widget definition. |
| 125 | + * Find and execute the widget's compileElement function, which includes the following steps: |
| 126 | + * Add a style element with attribute display: block; to the template DOM so that the browser |
| 127 | + knows to treat the element as block element for rendering. (Note: because this style element |
| 128 | + was added on the template compileElement, this style is automatically applied to any clones |
| 129 | + of the template (i.e. any repeating elements)). |
| 130 | + * Extract the salutation and name HTML attributes as angular expressions. |
| 131 | + * Return the aggregate link function, which includes just one link function in this example. |
| 132 | + |
| 133 | +### Link Phase |
| 134 | + |
| 135 | + * Execute the aggregate link function, which includes the following steps: |
| 136 | + * Create a <span> element set to the salutation class |
| 137 | + * Create a <span> element set to the name class. |
| 138 | + * Add the span elements to the linkElement. (Note: be careful not to add them to the |
| 139 | + compileElement, because that's the template.) |
| 140 | + * Set up watches on the expressions. When an expression changes, copy the data to the |
| 141 | + corresponding spans. |
| 142 | + |
| 143 | + |
| 144 | +## Compiler API |
| 145 | + |
| 146 | +If you define your own widgets, markup, or directives, you need to access the compiler API. |
| 147 | +This section describes the methods on the compiler that you can call. |
| 148 | + |
| 149 | +Note: As of 12 August 2010, these methods are subject to change. |
| 150 | + |
| 151 | +Recall that the compile function's this is a reference to the compiler. |
| 152 | + |
| 153 | + * `compile(element)` - returns `linker` - Invoke new instance of compiler to compile a DOM element |
| 154 | + and return a linker function. You can apply the linker function to the original element or a |
| 155 | + clone of the original element. The linker function returns a scope. |
| 156 | + * `comment(commentText)` - returns `element` - Create a comment element. |
| 157 | + * `element(elementName)` - returns `element` - Create an element by name. |
| 158 | + * `text(text)` - returns `element` - Create a text element. |
| 159 | + * `descend([set])` - returns `descend` - State Get or set the current descend state. If true the |
| 160 | + compiler will descend to children elements. |
| 161 | + * `directives([set])` - returns `directive` - State Get or set the current directives processing |
| 162 | + state. The compiler will process directives only when directives set to true. |
| 163 | + |
0 commit comments