UNPKG

knowhow-server

Version:

A personal workflow engine that can manage and use any network connected host

434 lines (418 loc) 27.7 kB
<a href="http://github.com/angular/angular.js/tree/v1.2.9/src/ng/compile.js#L21" class="view-source btn btn-action"><i class="icon-zoom-in"> </i> View source</a><a href="http://github.com/angular/angular.js/edit/master/src/ng/compile.js" class="improve-docs btn btn-primary"><i class="icon-edit"> </i> Improve this doc</a><h1><code ng:non-bindable="">$compile</code> <div><span class="hint">service in module <code ng:non-bindable="">ng</code> </span> </div> </h1> <div><h2 id="description">Description</h2> <div class="description"><div class="ng-compile-page"><p>Compiles an HTML string or DOM into a template and produces a template function, which can then be used to link <a href="api/ng.$rootScope.Scope"><code><code>scope</code></code></a> and the template together.</p> <p>The compilation is a process of walking the DOM tree and matching DOM elements to <a href="api/ng.$compileProvider#methods_directive"><code>directives</code></a>.</p> <div class="alert alert-warning"> <strong>Note:</strong> This document is an in-depth reference of all directive options. For a gentle introduction to directives with examples of common use cases, see the <a href="guide/directive">directive guide</a>. </div> <h4 id="description_comprehensive-directive-api">Comprehensive Directive API</h4> <p>There are many different options for a directive.</p> <p>The difference resides in the return value of the factory function. You can either return a &quot;Directive Definition Object&quot; (see below) that defines the directive properties, or just the <code>postLink</code> function (all other properties will have the default values).</p> <div class="alert alert-success"> <strong>Best Practice:</strong> It&#39;s recommended to use the &quot;directive definition object&quot; form. </div> <p>Here&#39;s an example directive declared with a Directive Definition Object:</p> <pre class="prettyprint linenums"> var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { priority: 0, template: '&lt;div&gt;&lt;/div&gt;', // or // function(tElement, tAttrs) { ... }, // or // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, replace: false, transclude: false, restrict: 'A', scope: false, controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } // or // return function postLink( ... ) { ... } }, // or // link: { // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... } }; return directiveDefinitionObject; }); </pre> <div class="alert alert-warning"> <strong>Note:</strong> Any unspecified options will use the default value. You can see the default values below. </div> <p>Therefore the above can be simplified as:</p> <pre class="prettyprint linenums"> var myModule = angular.module(...); myModule.directive('directiveName', function factory(injectables) { var directiveDefinitionObject = { link: function postLink(scope, iElement, iAttrs) { ... } }; return directiveDefinitionObject; // or // return function postLink(scope, iElement, iAttrs) { ... } }); </pre> <h5 id="description_comprehensive-directive-api_directive-definition-object">Directive Definition Object</h5> <p>The directive definition object provides instructions to the <a href="api/ng.$compile"><code>compiler</code></a>. The attributes are:</p> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>priority</code></h6> <p>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 <code>priority</code> is used to sort the directives before their <code>compile</code> functions get called. Priority is defined as a number. Directives with greater numerical <code>priority</code> are compiled first. Pre-link functions are also run in priority order, but post-link functions are run in reverse order. The order of directives with the same priority is undefined. The default priority is <code>0</code>.</p> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>terminal</code></h6> <p>If set to true then the current <code>priority</code> will be the last set of directives which will execute (any directives at the current priority will still execute as the order of execution on same <code>priority</code> is undefined).</p> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>scope</code></h6> <p><strong>If set to <code>true</code>,</strong> then a new scope will be created for this directive. If multiple directives on the same element request a new scope, only one new scope is created. The new scope rule does not apply for the root of the template since the root of the template always gets a new scope.</p> <p><strong>If set to <code>{}</code> (object hash),</strong> then a new &quot;isolate&quot; scope is created. The &#39;isolate&#39; scope differs from normal scope in that it does not prototypically inherit from the parent scope. This is useful when creating reusable components, which should not accidentally read or modify data in the parent scope.</p> <p>The &#39;isolate&#39; scope takes an object hash which defines a set of local scope properties derived from the parent scope. These local properties are useful for aliasing values for templates. Locals definition is a hash of local scope property to its source:</p> <ul> <li><p><code>@</code> or <code>@attr</code> - bind a local scope property to the value of DOM attribute. The result is always a string since DOM attributes are strings. If no <code>attr</code> name is specified then the attribute name is assumed to be the same as the local name. Given <code>&lt;widget my-attr=&quot;hello {{name}}&quot;&gt;</code> and widget definition of <code>scope: { localName:&#39;@myAttr&#39; }</code>, then widget scope property <code>localName</code> will reflect the interpolated value of <code>hello {{name}}</code>. As the <code>name</code> attribute changes so will the <code>localName</code> property on the widget scope. The <code>name</code> is read from the parent scope (not component scope).</p> </li> <li><p><code>=</code> or <code>=attr</code> - set up bi-directional binding between a local scope property and the parent scope property of name defined via the value of the <code>attr</code> attribute. If no <code>attr</code> name is specified then the attribute name is assumed to be the same as the local name. Given <code>&lt;widget my-attr=&quot;parentModel&quot;&gt;</code> and widget definition of <code>scope: { localModel:&#39;=myAttr&#39; }</code>, then widget scope property <code>localModel</code> will reflect the value of <code>parentModel</code> on the parent scope. Any changes to <code>parentModel</code> will be reflected in <code>localModel</code> and any changes in <code>localModel</code> will reflect in <code>parentModel</code>. If the parent scope property doesn&#39;t exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You can avoid this behavior using <code>=?</code> or <code>=?attr</code> in order to flag the property as optional.</p> </li> <li><p><code>&amp;</code> or <code>&amp;attr</code> - provides a way to execute an expression in the context of the parent scope. If no <code>attr</code> name is specified then the attribute name is assumed to be the same as the local name. Given <code>&lt;widget my-attr=&quot;count = count + value&quot;&gt;</code> and widget definition of <code>scope: { localFn:&#39;&amp;myAttr&#39; }</code>, then isolate scope property <code>localFn</code> will point to a function wrapper for the <code>count = count + value</code> expression. Often it&#39;s desirable to pass data from the isolated scope via an expression and to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is <code>increment(amount)</code> then we can specify the amount value by calling the <code>localFn</code> as <code>localFn({amount: 22})</code>.</p> </li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>controller</code></h6> <p>Controller constructor function. The controller is instantiated before the pre-linking phase and it is shared with other directives (see <code>require</code> attribute). This allows the directives to communicate with each other and augment each other&#39;s behavior. The controller is injectable (and supports bracket notation) with the following locals:</p> <ul> <li><code>$scope</code> - Current scope associated with the element</li> <li><code>$element</code> - Current element</li> <li><code>$attrs</code> - Current attributes object for the element</li> <li><code>$transclude</code> - A transclude linking function pre-bound to the correct transclusion scope. The scope can be overridden by an optional first argument. <code>function([scope], cloneLinkingFn)</code>.</li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>require</code></h6> <p>Require another directive and inject its controller as the fourth argument to the linking function. The <code>require</code> takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the injected argument will be an array in corresponding order. If no such directive can be found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:</p> <ul> <li>(no prefix) - Locate the required controller on the current element. Throw an error if not found.</li> <li><code>?</code> - Attempt to locate the required controller or pass <code>null</code> to the <code>link</code> fn if not found.</li> <li><code>^</code> - Locate the required controller by searching the element&#39;s parents. Throw an error if not found.</li> <li><code>?^</code> - Attempt to locate the required controller by searching the element&#39;s parents or pass <code>null</code> to the <code>link</code> fn if not found.</li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>controllerAs</code></h6> <p>Controller alias at the directive scope. An alias for the controller so it can be referenced at the directive template. The directive needs to define a scope for this configuration to be used. Useful in the case when directive is used as component.</p> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>restrict</code></h6> <p>String of subset of <code>EACM</code> which restricts the directive to a specific directive declaration style. If omitted, the default (attributes only) is used.</p> <ul> <li><code>E</code> - Element name: <code>&lt;my-directive&gt;&lt;/my-directive&gt;</code></li> <li><code>A</code> - Attribute (default): <code>&lt;div my-directive=&quot;exp&quot;&gt; &lt;/div&gt;</code></li> <li><code>C</code> - Class: <code>&lt;div class=&quot;my-directive: exp;&quot;&gt;&lt;/div&gt;</code></li> <li><code>M</code> - Comment: <code>&lt;!-- directive: my-directive exp --&gt;</code></li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>template</code></h6> <p>replace the current element with the contents of the HTML. The replacement process migrates all of the attributes / classes from the old element to the new one. See the <a href="guide/directive#creating-custom-directives_creating-directives_template-expanding-directive">Directives Guide</a> for an example.</p> <p>You can specify <code>template</code> as a string representing the template or as a function which takes two arguments <code>tElement</code> and <code>tAttrs</code> (described in the <code>compile</code> function api below) and returns a string value representing the template.</p> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>templateUrl</code></h6> <p>Same as <code>template</code> 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.</p> <p>You can specify <code>templateUrl</code> as a string representing the URL or as a function which takes two arguments <code>tElement</code> and <code>tAttrs</code> (described in the <code>compile</code> function api below) and returns a string value representing the url. In either case, the template URL is passed through <a href="api/ng.$sce#methods_gettrustedresourceurl"><code>$sce.getTrustedResourceUrl</code></a>.</p> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>replace</code></h6> <p>specify where the template should be inserted. Defaults to <code>false</code>.</p> <ul> <li><code>true</code> - the template will replace the current element.</li> <li><code>false</code> - the template will replace the contents of the current element.</li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>transclude</code></h6> <p>compile the content of the element and make it available to the directive. Typically used with <a href="api/ng.directive:ngTransclude"><code>ngTransclude</code></a>. The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope. In a typical setup the widget creates an <code>isolate</code> scope, but the transclusion is not a child, but a sibling of the <code>isolate</code> scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-<code>isolate</code>) scope.</p> <ul> <li><code>true</code> - transclude the content of the directive.</li> <li><code>&#39;element&#39;</code> - transclude the whole element including any directives defined at lower priority.</li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>compile</code></h6> <pre class="prettyprint linenums"> function compile(tElement, tAttrs, transclude) { ... } </pre> <p>The compile function deals with transforming the template DOM. Since most directives do not do template transformation, it is not used often. Examples that require compile functions are directives that transform template DOM, such as <a href="api/ng.directive:ngRepeat"><code>ngRepeat</code></a>, or load the contents asynchronously, such as <a href="api/ngRoute.directive:ngView">ngView</a>. The compile function takes the following arguments.</p> <ul> <li><p><code>tElement</code> - template element - The element where the directive has been declared. It is safe to do template transformation on the element and child elements only.</p> </li> <li><p><code>tAttrs</code> - template attributes - Normalized list of attributes declared on this element shared between all directive compile functions.</p> </li> <li><p><code>transclude</code> - [<em>DEPRECATED</em>!] A transclude linking function: <code>function(scope, cloneLinkingFn)</code></p> </li> </ul> <div class="alert alert-warning"> <strong>Note:</strong> The template instance and the link instance may be different objects if the template has been cloned. For this reason it is <strong>not</strong> safe to do anything other than DOM transformations that apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration should be done in a linking function rather than in a compile function. </div> <div class="alert alert-error"> <strong>Note:</strong> The <code>transclude</code> function that is passed to the compile function is deprecated, as it e.g. does not know about the right outer scope. Please use the transclude function that is passed to the link function instead. </div> <p>A compile function can have a return value which can be either a function or an object.</p> <ul> <li><p>returning a (post-link) function - is equivalent to registering the linking function via the <code>link</code> property of the config object when the compile function is empty.</p> </li> <li><p>returning an object with function(s) registered via <code>pre</code> and <code>post</code> properties - allows you to control when a linking function should be called during the linking phase. See info about pre-linking and post-linking functions below.</p> </li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object"><code>link</code></h6> <p>This property is used only if the <code>compile</code> property is not defined.</p> <pre class="prettyprint linenums"> function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } </pre> <p>The 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.</p> <ul> <li><p><code>scope</code> - <a href="api/ng.$rootScope.Scope"><code>Scope</code></a> - The scope to be used by the directive for registering <a href="api/ng.$rootScope.Scope#methods_$watch"><code>watches</code></a>.</p> </li> <li><p><code>iElement</code> - instance element - The element where the directive is to be used. It is safe to manipulate the children of the element only in <code>postLink</code> function since the children have already been linked.</p> </li> <li><p><code>iAttrs</code> - instance attributes - Normalized list of attributes declared on this element shared between all directive linking functions.</p> </li> <li><p><code>controller</code> - a controller instance - A controller instance if at least one directive on the element defines a controller. The controller is shared among all the directives, which allows the directives to use the controllers as a communication channel.</p> </li> <li><p><code>transcludeFn</code> - A transclude linking function pre-bound to the correct transclusion scope. The scope can be overridden by an optional first argument. This is the same as the <code>$transclude</code> parameter of directive controllers. <code>function([scope], cloneLinkingFn)</code>.</p> </li> </ul> <h6 id="description_comprehensive-directive-api_directive-definition-object_pre-linking-function">Pre-linking function</h6> <p>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.</p> <h6 id="description_comprehensive-directive-api_directive-definition-object_post-linking-function">Post-linking function</h6> <p>Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.</p> <p><a name="Attributes"></a></p> <h5 id="description_comprehensive-directive-api_attributes">Attributes</h5> <p>The <a href="api/ng.$compile.directive.Attributes"><code>Attributes</code></a> object - passed as a parameter in the <code>link()</code> or <code>compile()</code> functions. It has a variety of uses.</p> <p>accessing <em>Normalized attribute names:</em> Directives like &#39;ngBind&#39; can be expressed in many ways: &#39;ng:bind&#39;, <code>data-ng-bind</code>, or &#39;x-ng-bind&#39;. the attributes object allows for normalized access to the attributes.</p> <ul> <li><p><em>Directive inter-communication:</em> All directives share the same instance of the attributes object which allows the directives to use the attributes object as inter directive communication.</p> </li> <li><p><em>Supports interpolation:</em> Interpolation attributes are assigned to the attribute object allowing other directives to read the interpolated value.</p> </li> <li><p><em>Observing interpolated attributes:</em> Use <code>$observe</code> to observe the value changes of attributes that contain interpolation (e.g. <code>src=&quot;{{bar}}&quot;</code>). Not only is this very efficient but it&#39;s also the only way to easily get the actual value because during the linking phase the interpolation hasn&#39;t been evaluated yet and so the value is at this time set to <code>undefined</code>.</p> </li> </ul> <pre class="prettyprint linenums"> function linkingFn(scope, elm, attrs, ctrl) { // get the attribute value console.log(attrs.ngModel); // change the attribute attrs.$set('ngModel', 'new value'); // observe changes to interpolated attribute attrs.$observe('ngModel', function(value) { console.log('ngModel has changed value to ' + value); }); } </pre> <p>Below is an example using <code>$compileProvider</code>.</p> <div class="alert alert-warning"> <strong>Note</strong>: Typically directives are registered with <code>module.directive</code>. The example below is to illustrate how <code>$compile</code> works. </div> <p> <h4 id="description_source">Source</h4> <div source-edit="compile" source-edit-deps="angular.js script.js" source-edit-html="index.html-286" source-edit-css="" source-edit-js="script.js-285" source-edit-json="" source-edit-unit="" source-edit-scenario="scenario.js-287" source-edit-protractor=""></div> <div class="tabbable"><div class="tab-pane" title="index.html"> <pre class="prettyprint linenums" ng-set-text="index.html-286" ng-html-wrap="compile angular.js script.js"></pre> <script type="text/ng-template" id="index.html-286"> <div ng-controller="Ctrl"> <input ng-model="name"> <br> <textarea ng-model="html"></textarea> <br> <div compile="html"></div> </div> </script> </div> <div class="tab-pane" title="script.js"> <pre class="prettyprint linenums" ng-set-text="script.js-285"></pre> <script type="text/ng-template" id="script.js-285"> angular.module('compile', [], function($compileProvider) { // configure new 'compile' directive by passing a directive // factory function. The factory function injects the '$compile' $compileProvider.directive('compile', function($compile) { // directive factory creates a link function return function(scope, element, attrs) { scope.$watch( function(scope) { // watch the 'compile' expression for changes return scope.$eval(attrs.compile); }, function(value) { // when the 'compile' expression changes // assign it into the current DOM element.html(value); // compile the new DOM and link it to the current // scope. // NOTE: we only compile .childNodes so that // we don't get into infinite loop compiling ourselves $compile(element.contents())(scope); } ); }; }) }); function Ctrl($scope) { $scope.name = 'Angular'; $scope.html = 'Hello {{name}}'; } </script> </div> <div class="tab-pane" title="ngScenario e2e test"> <pre class="prettyprint linenums" ng-set-text="scenario.js-287"></pre> <script type="text/ng-template" id="scenario.js-287"> it('should auto compile', function() { expect(element('div[compile]').text()).toBe('Hello Angular'); input('html').enter('{{name}}!'); expect(element('div[compile]').text()).toBe('Angular!'); }); </script> </div> </div><h4 id="description_demo">Demo</h4> <div class="well doc-example-live animate-container" ng-embed-app="compile" ng-set-html="index.html-286" ng-eval-javascript="script.js-285"></div> </div></div> <h2 id="usage">Usage</h2> <div class="usage"><pre class="prettyprint linenums">$compile(element, transclude, maxPriority);</pre> <h4 id="usage_parameters">Parameters</h4><table class="variables-matrix table table-bordered table-striped"><thead><tr><th>Param</th><th>Type</th><th>Details</th></tr></thead><tbody><tr><td>element</td><td><a href="" class="label type-hint type-hint-string">string</a><a href="" class="label type-hint type-hint-domelement">DOMElement</a></td><td><div class="ng-compile-page"><p>Element or HTML string to compile into a template function.</p> </div></td></tr><tr><td>transclude</td><td><a href="" class="label type-hint type-hint-function">function(angular.Scope[, cloneAttachFn]</a></td><td><div class="ng-compile-page"><p>function available to directives.</p> </div></td></tr><tr><td>maxPriority</td><td><a href="" class="label type-hint type-hint-number">number</a></td><td><div class="ng-compile-page"><p>only apply directives lower then given priority (Only effects the root element(s), not their children)</p> </div></td></tr></tbody></table><h4 id="usage_returns">Returns</h4><table class="variables-matrix"><tr><td><a href="" class="label type-hint type-hint-function">function(scope[, cloneAttachFn])</a></td><td><div class="ng-compile-page"><p>a link function which is used to bind template (a DOM element/tree) to a scope. Where:</p> <ul> <li><code>scope</code> - A <a href="api/ng.$rootScope.Scope"><code>Scope</code></a> to bind to.</li> <li><p><code>cloneAttachFn</code> - If <code>cloneAttachFn</code> is provided, then the link function will clone the <code>template</code> and call the <code>cloneAttachFn</code> function allowing the caller to attach the cloned elements to the DOM document at the appropriate place. The <code>cloneAttachFn</code> is called as: <br> <code>cloneAttachFn(clonedElement, scope)</code> where:</p> <ul> <li><code>clonedElement</code> - is a clone of the original <code>element</code> passed into the compiler.</li> <li><code>scope</code> - is the current scope with which the linking function is working with.</li> </ul> </li> </ul> <p>Calling the linking function returns the element of the template. It is either the original element passed in, or the clone of the element if the <code>cloneAttachFn</code> is provided.</p> <p>After linking the view is not updated until after a call to $digest which typically is done by Angular automatically.</p> <p>If you need access to the bound view, there are two ways to do it:</p> <ul> <li><p>If you are not asking the linking function to clone the template, create the DOM element(s) before you send them to the compiler and keep this reference around. <pre class="prettyprint linenums"> var element = $compile('&lt;p&gt;{{total}}&lt;/p&gt;')(scope); </pre> </li> <li><p>if on the other hand, you need the element to be cloned, the view reference from the original example would not point to the clone, but rather to the original template that was cloned. In this case, you can access the clone via the cloneAttachFn: <pre class="prettyprint linenums"> var templateElement = angular.element('&lt;p&gt;{{total}}&lt;/p&gt;'), scope = ....; var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) { //attach the clone to DOM document at the right place }); //now we have reference to the cloned DOM via `clonedElement` </pre> </li> </ul> <p>For information on how the compiler works, see the <a href="guide/compiler">Angular HTML Compiler</a> section of the Developer Guide.</p> </div></td></tr></table></div> </div>