mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
docs(guide/directive,guide/compiler,): drastically improve
This commit is contained in:
parent
32ab648c79
commit
e69c287293
6 changed files with 1422 additions and 703 deletions
|
|
@ -3,7 +3,7 @@
|
|||
@fullName Missing Required Controller
|
||||
@description
|
||||
|
||||
This error occurs when {@link api/ng.$compile template compiler} tries process the directive that specifies the `require` option in a {@link guide/directive#writing-directives_directive-definition-object directive definition},
|
||||
This error occurs when {@link api/ng.$compile HTML compiler} tries to process a directive that specifies the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object `require` option} in a {@link api/ng.$compile#description_comprehensive-directive-api directive definition},
|
||||
but the required directive controller is not present on the current DOM element (or its ancestor element, if `^` was specified).
|
||||
|
||||
To resolve this error ensure that there is no typo in the required controller name and that the required directive controller is present on the current element.
|
||||
|
|
|
|||
|
|
@ -21,4 +21,5 @@ myModule.directive('directiveName', function factory() {
|
|||
});
|
||||
```
|
||||
|
||||
Please refer to the {@link guide/directive#writing-directives_directive-definition-object directive definition docs} to learn more about the api.
|
||||
Please refer to the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object
|
||||
`scope` option} of the directive definition documentation to learn more about the API.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
@fullName Non-Assignable Expression
|
||||
@description
|
||||
|
||||
This error occurs when a directive defines an isolate scope property that support two-way data-binding (using the `=` mode in the {@link guide/directive#writing-directives_directive-definition-object directive definition}) but the directive is used with an expression that is not-assignable.
|
||||
This error occurs when a directive defines an isolate scope property
|
||||
(using the `=` mode in the {@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object
|
||||
`scope` option} of a directive definition) but the directive is used with an expression that is not-assignable.
|
||||
|
||||
In order for the two-way data-binding to work, it must be possible to write new values back into the path defined with the expression.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,15 @@
|
|||
@name Developer Guide: HTML Compiler
|
||||
@description
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
|
||||
|
||||
If you're just getting started, we recommend the {@link tutorial/ tutorial} first.
|
||||
If you just want to create custom directives, we recommend the {@link guide/directive directives guide}.
|
||||
If you want a deeper look into Angular's compilation process, you're in the right place.
|
||||
</div>
|
||||
|
||||
|
||||
# Overview
|
||||
|
||||
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
|
||||
|
|
@ -27,9 +36,9 @@ All of this compilation takes place in the web browser; no server side or pre-co
|
|||
involved.
|
||||
|
||||
|
||||
# Compiler
|
||||
## Compiler
|
||||
|
||||
Compiler is an angular service which traverses the DOM looking for attributes. The compilation
|
||||
Compiler is an Angular service which traverses the DOM looking for attributes. The compilation
|
||||
process happens in two phases.
|
||||
|
||||
1. **Compile:** traverse the DOM and collect all of the directives. The result is a linking
|
||||
|
|
@ -44,7 +53,7 @@ for each item in a collection. Having a compile and link phase improves performa
|
|||
cloned template only needs to be compiled once, and then linked once for each clone instance.
|
||||
|
||||
|
||||
# Directive
|
||||
## Directive
|
||||
|
||||
A directive is a behavior which should be triggered when specific HTML constructs are encountered
|
||||
during the compilation process. The directives can be placed in element names, attributes, class
|
||||
|
|
@ -108,35 +117,260 @@ Here is a directive which makes any element draggable. Notice the `draggable` at
|
|||
</example>
|
||||
|
||||
|
||||
The presence of the `draggable` attribute on any element gives the element new behavior. The beauty of
|
||||
this approach is that we have taught the browser a new trick. We have extended the vocabulary of
|
||||
what the browser understands in a way which is natural to anyone who is familiar with HTML
|
||||
principles.
|
||||
The presence of the `draggable` attribute on any element gives the element new behavior.
|
||||
We extended the vocabulary of the browser in a way which is natural to anyone who is familiar with the principles of HTML.
|
||||
|
||||
|
||||
# Understanding View
|
||||
## Understanding View
|
||||
|
||||
There are many templating systems out there. Most of them consume a static string template and
|
||||
Most other templating systems consume a static string template and
|
||||
combine it with data, resulting in a new string. The resulting text is then `innerHTML`ed into
|
||||
an element.
|
||||
|
||||
<img src="img/One_Way_Data_Binding.png">
|
||||
|
||||
This means that any changes to the data need to be re-merged with the template and then
|
||||
`innerHTML`ed into the DOM. Some of the issues with this approach are: reading user input and merging it with data,
|
||||
clobbering user input by overwriting it, managing the whole update process, and lack of behavior
|
||||
expressiveness.
|
||||
`innerHTML`ed into the DOM. Some of the issues with this approach are:
|
||||
|
||||
Angular is different. The Angular compiler consumes the DOM with directives, not string templates.
|
||||
1. reading user input and merging it with data
|
||||
2. clobbering user input by overwriting it
|
||||
3. managing the whole update process
|
||||
4. lack of behavior expressiveness
|
||||
|
||||
Angular is different. The Angular compiler consumes the DOM, not string templates.
|
||||
The result is a linking function, which when combined with a scope model results in a live view. The
|
||||
view and scope model bindings are transparent. No action from the developer is needed to update
|
||||
the view. And because no `innerHTML` is used there are no issues of clobbering user input.
|
||||
view and scope model bindings are transparent. The developer does not need to make any special calls to update
|
||||
the view. And because `innerHTML` is not used, you won't accidentally clobber user input.
|
||||
Furthermore, Angular directives can contain not just text bindings, but behavioral constructs as
|
||||
well.
|
||||
|
||||
<img src="img/Two_Way_Data_Binding.png">
|
||||
|
||||
The Angular approach produces a stable DOM. This means that the DOM element instance bound to a model
|
||||
The Angular approach produces a stable DOM. The DOM element instance bound to a model
|
||||
item instance does not change for the lifetime of the binding. This means that the code can get
|
||||
hold of the elements and register event handlers and know that the reference will not be destroyed
|
||||
by template data merge.
|
||||
|
||||
|
||||
|
||||
## How directives are compiled
|
||||
|
||||
It's important to note that Angular operates on DOM nodes rather than strings. Usually, you don't
|
||||
notice this restriction because when a page loads, the web browser parses HTML into the DOM automatically.
|
||||
|
||||
However it's important to keep this in mind when calling `$compile` yourself, because passing it a string
|
||||
will fail. Instead, use `angular.element` to convert a string to DOM before passing elements into
|
||||
Angular's `$compile` service.
|
||||
|
||||
HTML compilation happens in three phases:
|
||||
|
||||
1. {@link api/ng.$compile `$compile`} traverses the DOM and matches directives.
|
||||
|
||||
If the compiler finds than an element matches a directive, then the directive is added to the list of
|
||||
directives that match the DOM element. A single element may match multiple directives.
|
||||
|
||||
2. Once all directives matching a DOM element have been identified, the compiler sorts the directives
|
||||
by their `priority`.
|
||||
|
||||
Each directive's `compile` functions are executed. Each `compile` function has a chance to
|
||||
modify the DOM. Each `compile` function returns a `link` function. These functions are composed into
|
||||
a "combined" link function, which invokes each directive's returned `link` function.
|
||||
|
||||
3. `$compile` links the template with the scope by calling the combined linking function from the previous step.
|
||||
This in turn will call the linking function of the individual directives, registering listeners on the elements
|
||||
and setting up {@link api/ng.$rootScope.Scope#methods_$watch `$watch`s} with the {@link api/ng.$rootScope.Scope `scope`}
|
||||
as each directive is configured to do.
|
||||
|
||||
The result of this is a live binding between the scope and the DOM. So at this point, a change in
|
||||
a model on the compiled scope will be reflected in the DOM.
|
||||
|
||||
Below is the corresponding code using the `$compile` service.
|
||||
This should help give you an idea of what Angular does internally.
|
||||
|
||||
<pre>
|
||||
var $compile = ...; // injected into your code
|
||||
var scope = ...;
|
||||
|
||||
var html = '<div ng-bind="exp"></div>';
|
||||
|
||||
// Step 1: parse HTML into DOM element
|
||||
var template = angular.element(html);
|
||||
|
||||
// Step 2: compile the template
|
||||
var linkFn = $compile(template);
|
||||
|
||||
// Step 3: link the compiled template with the scope.
|
||||
linkFn(scope);
|
||||
</pre>
|
||||
|
||||
### The difference between Compile and Link
|
||||
|
||||
At this point you may wonder why the compile process has separate compile and link phases. The
|
||||
short answer is that compile and link separation is needed any time a change in a model causes
|
||||
a change in the **structure** of the DOM.
|
||||
|
||||
It's rare for directives to have a **compile function**, since most directives are concerned with
|
||||
working with a specific DOM element instance rather than changing its overall structure.
|
||||
|
||||
Directives often have a **link function**. A link function allows the directive to register
|
||||
listeners to the specific cloned DOM element instance as well as to copy content into the DOM
|
||||
from the scope.
|
||||
|
||||
<div class="alert alert-success">
|
||||
**Best Practice:** Any operation which can be shared among the instance of directives should be
|
||||
moved to the compile function for performance reasons.
|
||||
</div>
|
||||
|
||||
#### An Example of "Compile" Versus "Link"
|
||||
|
||||
To understand, let's look at a real-world example with `ngRepeat`:
|
||||
|
||||
<pre>
|
||||
Hello {{user}}, you have these actions:
|
||||
<ul>
|
||||
<li ng-repeat="action in user.actions">
|
||||
{{action.description}}
|
||||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
|
||||
When the above example is compiled, the compiler visits every node and looks for directives.
|
||||
|
||||
`{{user}}` matches the {@link api/ng.$interpolate interpolation directive}
|
||||
and `ng-repeat` matches the {@link api/ng.directive:ngRepeat `ngRepeat` directive}.
|
||||
|
||||
But {@link api/ng.directive:ngRepeat ngRepeat} has a dilemma.
|
||||
|
||||
It needs to be able to clone new `<li>` elements for every `action` in `user.actions`.
|
||||
This initially seems trivial, but it becomes more complicated when you consider that `user.actions`
|
||||
might have items added to it later. This means that it needs to save a clean copy of the `<li>`
|
||||
element for cloning purposes.
|
||||
|
||||
As new `action`s are inserted, the template `<li>` element needs to be cloned and inserted into `ul`.
|
||||
But cloning the `<li>` element is not enough. It also needs to compile the `<li>` so that its
|
||||
directives, like `{{action.description}}`, evaluate against the right {@link api/ng.$rootScope.Scope scope}.
|
||||
|
||||
|
||||
A naive approach to solving this problem would be to simply insert a copy of the `<li>` element and
|
||||
then compile it.
|
||||
The problem with this approach is that compiling on every `<li>` element that we clone would duplicate
|
||||
a lot of the work. Specifically, we'd be traversing `<li>` each time before cloning it to find the
|
||||
directives. This would cause the compilation process to be slower, in turn making applications
|
||||
less responsive when inserting new nodes.
|
||||
|
||||
The solution is to break the compilation process into two phases:
|
||||
|
||||
the **compile phase** where all of the directives are identified and sorted by priority,
|
||||
and a **linking phase** where any work which "links" a specific instance of the
|
||||
{@link api/ng.$rootScope.Scope scope} and the specific instance of an `<li>` is performed.
|
||||
|
||||
<div class="alert alert-warning">
|
||||
**Note:** *Link* means setting up listeners on the DOM and setting up `$watch` on the Scope to
|
||||
keep the two in sync.
|
||||
</div>
|
||||
|
||||
{@link api/ng.directive:ngRepeat `ngRepeat`} works by preventing the compilation process from
|
||||
descending into the `<li>` element so it can make a clone of the original and handle inserting
|
||||
and removing DOM nodes itself.
|
||||
|
||||
Instead the {@link api/ng.directive:ngRepeat `ngRepeat`} directive compiles `<li>` separately.
|
||||
The result of the `<li>` element compilation is a linking function which contains all of the
|
||||
directives contained in the `<li>` element, ready to be attached to a specific clone of the `<li>`
|
||||
element.
|
||||
|
||||
At runtime the {@link api/ng.directive:ngRepeat `ngRepeat`} watches the expression and as items
|
||||
are added to the array it clones the `<li>` element, creates a new
|
||||
{@link api/ng.$rootScope.Scope scope} for the cloned `<li>` element and calls the link function
|
||||
on the cloned `<li>`.
|
||||
|
||||
|
||||
|
||||
### Understanding How Scopes Work with Transclused Directives
|
||||
|
||||
One of the most common use cases for directives is to create reusable components.
|
||||
|
||||
Below is a pseudo code showing how a simplified dialog component may work.
|
||||
|
||||
<pre>
|
||||
<div>
|
||||
<button ng-click="show=true">show</button>
|
||||
|
||||
<dialog title="Hello {{username}}."
|
||||
visible="show"
|
||||
on-cancel="show = false"
|
||||
on-ok="show = false; doSomething()">
|
||||
Body goes here: {{username}} is {{title}}.
|
||||
</dialog>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
Clicking on the "show" button will open the dialog. The dialog will have a title, which is
|
||||
data bound to `username`, and it will also have a body which we would like to transclude
|
||||
into the dialog.
|
||||
|
||||
Here is an example of what the template definition for the `dialog` widget may look like.
|
||||
|
||||
<pre>
|
||||
<div ng-show="visible">
|
||||
<h3>{{title}}</h3>
|
||||
<div class="body" ng-transclude></div>
|
||||
<div class="footer">
|
||||
<button ng-click="onOk()">Save changes</button>
|
||||
<button ng-click="onCancel()">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
This will not render properly, unless we do some scope magic.
|
||||
|
||||
The first issue we have to solve is that the dialog box template expects `title` to be defined, but
|
||||
the place of instantiation would like to bind to `username`. Furthermore the buttons expect the
|
||||
`onOk` and `onCancel` functions to be present in the scope. This limits the usefulness of the
|
||||
widget. To solve the mapping issue we use the `locals` to create local variables which the template
|
||||
expects as follows:
|
||||
|
||||
<pre>
|
||||
scope: {
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
}
|
||||
</pre>
|
||||
|
||||
Creating local properties on widget scope creates two problems:
|
||||
|
||||
1. isolation - if the user forgets to set `title` attribute of the dialog widget the dialog
|
||||
template will bind to parent scope property. This is unpredictable and undesirable.
|
||||
|
||||
2. transclusion - the transcluded DOM can see the widget locals, which may overwrite the
|
||||
properties which the transclusion needs for data-binding. In our example the `title`
|
||||
property of the widget clobbers the `title` property of the transclusion.
|
||||
|
||||
|
||||
To solve the issue of lack of isolation, the directive declares a new `isolated` scope. An
|
||||
isolated scope does not prototypically inherit from the child scope, and therefore we don't have
|
||||
to worry about accidentally clobbering any properties.
|
||||
|
||||
However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
|
||||
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
|
||||
is a child of the original scope, before the widget created an isolated scope for its local
|
||||
variables. This makes the transcluded and widget isolated scope siblings.
|
||||
|
||||
This may seem to be unexpected complexity, but it gives the widget user and developer the least
|
||||
surprise.
|
||||
|
||||
Therefore the final directive definition looks something like this:
|
||||
|
||||
<pre>
|
||||
transclude: true,
|
||||
scope: {
|
||||
title: '@', // the title uses the data-binding from the parent scope
|
||||
onOk: '&', // create a delegate onOk function
|
||||
onCancel: '&', // create a delegate onCancel function
|
||||
visible: '=' // set up visible to accept data-binding
|
||||
},
|
||||
restrict: 'E',
|
||||
replace: true
|
||||
</pre>
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,21 +25,355 @@
|
|||
*
|
||||
* @description
|
||||
* Compiles a piece of HTML string or DOM into a template and produces a template function, which
|
||||
* can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
|
||||
* can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
|
||||
*
|
||||
* The compilation is a process of walking the DOM tree and trying to match DOM elements to
|
||||
* {@link ng.$compileProvider#methods_directive directives}. For each match it
|
||||
* executes corresponding template function and collects the
|
||||
* instance functions into a single template function which is then returned.
|
||||
* The compilation is a process of walking the DOM tree and matching DOM elements to
|
||||
* {@link ng.$compileProvider#methods_directive directives}.
|
||||
*
|
||||
* The template function can then be used once to produce the view or as it is the case with
|
||||
* {@link ng.directive:ngRepeat repeater} many-times, in which
|
||||
* case each call results in a view that is a DOM clone of the original template.
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** 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 {@link guide/directive directive guide}.
|
||||
* </div>
|
||||
*
|
||||
* ## Comprehensive Directive API
|
||||
*
|
||||
* There are many different options for a directive.
|
||||
*
|
||||
* The difference resides in the return value of the factory function.
|
||||
* You can either return a "Directive Definition Object" (see below) that defines the directive properties,
|
||||
* or just the `postLink` function (all other properties will have the default values).
|
||||
*
|
||||
* <div class="alert alert-success">
|
||||
* **Best Practice:** It's recommended to use the "directive definition object" form.
|
||||
* </div>
|
||||
*
|
||||
* Here's an example directive declared with a Directive Definition Object:
|
||||
*
|
||||
* <pre>
|
||||
* var myModule = angular.module(...);
|
||||
*
|
||||
* myModule.directive('directiveName', function factory(injectables) {
|
||||
* var directiveDefinitionObject = {
|
||||
* priority: 0,
|
||||
* template: '<div></div>', // 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">
|
||||
* **Note:** Any unspecified options will use the default value. You can see the default values below.
|
||||
* </div>
|
||||
*
|
||||
* Therefore the above can be simplified as:
|
||||
*
|
||||
* <pre>
|
||||
* 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>
|
||||
*
|
||||
*
|
||||
*
|
||||
* ### Directive Definition Object
|
||||
*
|
||||
* The directive definition object provides instructions to the {@link api/ng.$compile
|
||||
* compiler}. The attributes are:
|
||||
*
|
||||
* #### `priority`
|
||||
* 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 `priority` is used
|
||||
* to sort the directives before their `compile` functions get called. Priority is defined as a
|
||||
* number. Directives with greater numerical `priority` are compiled first. The order of directives with
|
||||
* the same priority is undefined. The default priority is `0`.
|
||||
*
|
||||
* #### `terminal`
|
||||
* If set to true then the current `priority` 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 `priority` is undefined).
|
||||
*
|
||||
* #### `scope`
|
||||
* **If set to `true`,** 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.
|
||||
*
|
||||
* **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' 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.
|
||||
*
|
||||
* The 'isolate' 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:
|
||||
*
|
||||
* * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
|
||||
* always a string since DOM attributes are strings. If no `attr` name is specified then the
|
||||
* attribute name is assumed to be the same as the local name.
|
||||
* Given `<widget my-attr="hello {{name}}">` and widget definition
|
||||
* of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
|
||||
* the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
|
||||
* `localName` property on the widget scope. The `name` is read from the parent scope (not
|
||||
* component scope).
|
||||
*
|
||||
* * `=` or `=attr` - set up bi-directional binding between a local scope property and the
|
||||
* parent scope property of name defined via the value of the `attr` attribute. If no `attr`
|
||||
* name is specified then the attribute name is assumed to be the same as the local name.
|
||||
* Given `<widget my-attr="parentModel">` and widget definition of
|
||||
* `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
|
||||
* value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
|
||||
* in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
|
||||
* scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
|
||||
* can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
|
||||
*
|
||||
* * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
|
||||
* If no `attr` name is specified then the attribute name is assumed to be the same as the
|
||||
* local name. Given `<widget my-attr="count = count + value">` and widget definition of
|
||||
* `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
|
||||
* a function wrapper for the `count = count + value` expression. Often it'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 `increment(amount)` then we can specify the amount value
|
||||
* by calling the `localFn` as `localFn({amount: 22})`.
|
||||
*
|
||||
*
|
||||
*
|
||||
* #### `controller`
|
||||
* Controller constructor function. The controller is instantiated before the
|
||||
* pre-linking phase and it is shared with other directives (see
|
||||
* `require` attribute). This allows the directives to communicate with each other and augment
|
||||
* each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
|
||||
*
|
||||
* * `$scope` - Current scope associated with the element
|
||||
* * `$element` - Current element
|
||||
* * `$attrs` - Current attributes object for the element
|
||||
* * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
|
||||
* `function(cloneLinkingFn)`.
|
||||
*
|
||||
*
|
||||
* #### `require`
|
||||
* Require another directive and inject its controller as the fourth argument to the linking function. The
|
||||
* `require` 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:
|
||||
*
|
||||
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
|
||||
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
|
||||
* * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
|
||||
* * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the
|
||||
* `link` fn if not found.
|
||||
*
|
||||
*
|
||||
* #### `controllerAs`
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* #### `restrict`
|
||||
* String of subset of `EACM` which restricts the directive to a specific directive
|
||||
* declaration style. If omitted, the default (attributes only) is used.
|
||||
*
|
||||
* * `E` - Element name: `<my-directive></my-directive>`
|
||||
* * `A` - Attribute (default): `<div my-directive="exp"></div>`
|
||||
* * `C` - Class: `<div class="my-directive: exp;"></div>`
|
||||
* * `M` - Comment: `<!-- directive: my-directive exp -->`
|
||||
*
|
||||
*
|
||||
* #### `template`
|
||||
* 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
|
||||
* {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
|
||||
* Directives Guide} for an example.
|
||||
*
|
||||
* You can specify `template` as a string representing the template or as a function which takes
|
||||
* two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
|
||||
* returns a string value representing the template.
|
||||
*
|
||||
*
|
||||
* #### `templateUrl`
|
||||
* Same as `template` 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.
|
||||
*
|
||||
* You can specify `templateUrl` as a string representing the URL or as a function which takes two
|
||||
* arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
|
||||
* a string value representing the url. In either case, the template URL is passed through {@link
|
||||
* api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl}.
|
||||
*
|
||||
*
|
||||
* #### `replace`
|
||||
* specify where the template should be inserted. Defaults to `false`.
|
||||
*
|
||||
* * `true` - the template will replace the current element.
|
||||
* * `false` - the template will replace the contents of the current element.
|
||||
*
|
||||
*
|
||||
* #### `transclude`
|
||||
* compile the content of the element and make it available to the directive.
|
||||
* Typically used with {@link api/ng.directive:ngTransclude
|
||||
* ngTransclude}. 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 `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
|
||||
* scope. This makes it possible for the widget to have private state, and the transclusion to
|
||||
* be bound to the parent (pre-`isolate`) scope.
|
||||
*
|
||||
* * `true` - transclude the content of the directive.
|
||||
* * `'element'` - transclude the whole element including any directives defined at lower priority.
|
||||
*
|
||||
*
|
||||
* #### `compile`
|
||||
*
|
||||
* <pre>
|
||||
* function compile(tElement, tAttrs, transclude) { ... }
|
||||
* </pre>
|
||||
*
|
||||
* 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 {@link
|
||||
* api/ng.directive:ngRepeat ngRepeat}, or load the contents
|
||||
* asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The
|
||||
* compile function takes the following arguments.
|
||||
*
|
||||
* * `tElement` - template element - The element where the directive has been declared. It is
|
||||
* safe to do template transformation on the element and child elements only.
|
||||
*
|
||||
* * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
|
||||
* between all directive compile functions.
|
||||
*
|
||||
* * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note:** The template instance and the link instance may be different objects if the template has
|
||||
* been cloned. For this reason it is **not** 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>
|
||||
*
|
||||
* A compile function can have a return value which can be either a function or an object.
|
||||
*
|
||||
* * returning a (post-link) function - is equivalent to registering the linking function via the
|
||||
* `link` property of the config object when the compile function is empty.
|
||||
*
|
||||
* * returning an object with function(s) registered via `pre` and `post` 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.
|
||||
*
|
||||
*
|
||||
* #### `link`
|
||||
* This property is used only if the `compile` property is not defined.
|
||||
*
|
||||
* <pre>
|
||||
* function link(scope, iElement, iAttrs, controller) { ... }
|
||||
* </pre>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the
|
||||
* directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}.
|
||||
*
|
||||
* * `iElement` - instance element - The element where the directive is to be used. It is safe to
|
||||
* manipulate the children of the element only in `postLink` function since the children have
|
||||
* already been linked.
|
||||
*
|
||||
* * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
|
||||
* between all directive linking functions.
|
||||
*
|
||||
* * `controller` - 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.
|
||||
*
|
||||
*
|
||||
*
|
||||
* #### Pre-linking function
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* #### Post-linking function
|
||||
*
|
||||
* Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
|
||||
*
|
||||
* <a name="Attributes"></a>
|
||||
* ### Attributes
|
||||
*
|
||||
* The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
|
||||
* `link()` or `compile()` functions. It has a variety of uses.
|
||||
*
|
||||
* accessing *Normalized attribute names:*
|
||||
* Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
|
||||
* the attributes object allows for normalized access to
|
||||
* the attributes.
|
||||
*
|
||||
* * *Directive inter-communication:* All directives share the same instance of the attributes
|
||||
* object which allows the directives to use the attributes object as inter directive
|
||||
* communication.
|
||||
*
|
||||
* * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
|
||||
* allowing other directives to read the interpolated value.
|
||||
*
|
||||
* * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
|
||||
* that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
|
||||
* the only way to easily get the actual value because during the linking phase the interpolation
|
||||
* hasn't been evaluated yet and so the value is at this time set to `undefined`.
|
||||
*
|
||||
* <pre>
|
||||
* 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>
|
||||
*
|
||||
* Below is an example using `$compileProvider`.
|
||||
*
|
||||
* <div class="alert alert-warning">
|
||||
* **Note**: Typically directives are registered with `module.directive`. The example below is
|
||||
* to illustrate how `$compile` works.
|
||||
* </div>
|
||||
*
|
||||
<doc:example module="compile">
|
||||
<doc:source>
|
||||
<script>
|
||||
// declare a new module, and inject the $compileProvider
|
||||
angular.module('compile', [], function($compileProvider) {
|
||||
// configure new 'compile' directive by passing a directive
|
||||
// factory function. The factory function injects the '$compile'
|
||||
|
|
|
|||
Loading…
Reference in a new issue