mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
docs(compiler): update the compiler docs
This commit is contained in:
parent
e2b1d9e994
commit
4804c83b7d
50 changed files with 862 additions and 788 deletions
|
|
@ -0,0 +1,505 @@
|
|||
@ngdoc overview
|
||||
@name angular.module.ng.$compileProvider.directive
|
||||
@description
|
||||
|
||||
Directives are a way to teach HTML new tricks. During DOM compilation directives are matched
|
||||
against the HTML and executed. This allows directives to register behavior, or transform the DOM.
|
||||
|
||||
Angular comes with a built in set of directives which are useful for building web applications but
|
||||
can be extended such that HTML can be turned into a declarative domain specific language (DSL).
|
||||
|
||||
# Invoking directives from HTML
|
||||
|
||||
Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating
|
||||
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
|
||||
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
|
||||
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
|
||||
`data-ng-bind`.
|
||||
|
||||
The directives can be placed in element names, attributes, class names, as well as comments. Here
|
||||
are some equivalent examples of invoking `ngBind`.
|
||||
|
||||
<pre>
|
||||
<span ng-bind="exp"></span>
|
||||
<span class="ng-bind: exp;"></span>
|
||||
<ng-bind></ng-bind>
|
||||
<!-- directive: ng-bind exp --!>
|
||||
</pre>
|
||||
|
||||
Directives can be invoked in many different ways, but are equivalent in the end result as shown in
|
||||
the following example.
|
||||
|
||||
<doc:example>
|
||||
<doc:source >
|
||||
<script>
|
||||
function Ctrl1($scope) {
|
||||
$scope.name = 'angular';
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="Ctrl1">
|
||||
Hello <input ng-model='name'> <hr/>
|
||||
<span ng:bind="name"> <span ng:bind="name"></span> <br/>
|
||||
<span ng_bind="name"> <span ng_bind="name"></span> <br/>
|
||||
<span ng-bind="name"> <span ng-bind="name"></span> <br/>
|
||||
<span data-ng-bind="name"> <span data-ng-bind="name"></span> <br/>
|
||||
<span x-ng-bind="name"> <span x-ng-bind="name"></span> <br/>
|
||||
<span class="ng-bind: name;"> <span class="ng-bind: name;"></span> <br/>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should load template1.html', function() {
|
||||
expect(element('div[ng-controller="Ctrl1"] span[ng-bind]').text()).toBe('angular');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
# String interpolation
|
||||
|
||||
During the compilation process the {@link angular.module.ng.$compile compiler} matches text and
|
||||
attributes using the {@link angular.module.ng.$interpolate $interpolate} service to see if they
|
||||
contain embedded expressions. These expressions are registered as {@link
|
||||
angular.module.ng.$rootScope.Scope#.watch watches} and will update as part of normal {@link
|
||||
angular.module.ng.$rootScope.Scope#.digest digest} cycle. An example of interpolation is shown
|
||||
here:
|
||||
|
||||
<pre>
|
||||
<img src="img/{{username}}.jpg">Hello {{username}}!</img>
|
||||
</pre>
|
||||
|
||||
# Compilation process, and directive matching
|
||||
|
||||
Compilation of HTML happens in three phases:
|
||||
|
||||
1. First the HTML is parsed into DOM using the standard browser API. This is important to
|
||||
realize because the templates must be parsable HTML. This is in contrast to most templating
|
||||
systems that operate on strings, rather then on DOM elements.
|
||||
|
||||
2. The compilation of the DOM is performed by the call to {@link angular.module.ng.$compile
|
||||
$compile()} method. The method traverses the DOM and matches the directives. If a match is found
|
||||
it is added to the list of directives associated with the given DOM element. Once all directives
|
||||
for a given DOM element have been identified they are sorted by priority and their `compile()`
|
||||
functions are executed. The directive compile function has a chance to modify the DOM structure
|
||||
and is responsible for producing a `link()` function explained next. The {@link
|
||||
angular.module.ng.$compile $compile()} method returns a combined linking function, which is a
|
||||
collection of all of the linking functions returned from the individual directive compile
|
||||
functions.
|
||||
|
||||
3. Link the template with scope by calling the liking function returned from the previous step.
|
||||
This in turn will call the linking function of the individual directives allowing them to
|
||||
register any listeners on the elements and set up any {@link
|
||||
angular.module.ng.$rootScope.Scope#.watch watches} with the {@link
|
||||
angular.module.ng.$rootScope.Scope scope}. The result of this is a live binding between the
|
||||
scope and the DOM. A change in the scope is reflected in the DOM.
|
||||
|
||||
<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>
|
||||
|
||||
## Reasons behind the compile/link separation
|
||||
|
||||
At this point you may wonder why is the compile process broken down to a compile and link phase.
|
||||
To understand this, lets look at a real world example with repeater:
|
||||
|
||||
<pre>
|
||||
Hello {{user}}, you have these actions:
|
||||
<ul>
|
||||
<li ng:repeat="action in user.actions">
|
||||
{{action.description}}
|
||||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
|
||||
The short answer is that compile and link separation is needed any time a change in model causes
|
||||
a change in DOM structure such as in repeaters.
|
||||
|
||||
When the above example is compiled, the compiler visits every node and looks for directives. The
|
||||
`{{user}}` is an example of {@link angular.module.ng.$interpolate interpolation} directive. {@link
|
||||
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} is another directive. But {@link
|
||||
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} has a dilemma. It needs to be
|
||||
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
|
||||
to save a clean copy of the `li` element for cloning purposes and 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 such as
|
||||
`{{action.descriptions}}` evaluate against the right {@link angular.module.ng.$rootScope.Scope
|
||||
scope}. A naive method would be to simply insert a copy of the `li` elemnt and then compile it.
|
||||
But compiling on every `li` element clone would be slow, since the compilation requires that we
|
||||
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
|
||||
repeater which needs to unroll 100 items we would quickly run into performance problem.
|
||||
|
||||
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 angular.module.ng.$rootScope.Scope scope} and the specific
|
||||
instance of an `li` is performed.
|
||||
|
||||
{@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} works by preventing the
|
||||
compilation process form descending into `li` element. Instead the {@link
|
||||
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} directive compiles `li`
|
||||
seperatly. The result of 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 `li`
|
||||
element. At runtime the {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat}
|
||||
watches the expression and as items are added to the array it clones the `li` element, creates a
|
||||
new {@link angular.module.ng.$rootScope.Scope scope} for the cloned `li` element and calls the
|
||||
link function on the cloned `li`.
|
||||
|
||||
Summary:
|
||||
|
||||
* *compile function* - The compile function is relatively rare in directives, since most
|
||||
directives are concerned with working with a specific DOM element instance rather then
|
||||
transforming the template DOM element. Any operation which can be shared among the instance of
|
||||
directives should be moved to the compile function for performance reasons.
|
||||
|
||||
* *link function* - It is rare for the directive not to have a link function. 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.
|
||||
|
||||
|
||||
# Writing directives (short version)
|
||||
|
||||
In this example we will build a directive which displays the current time.
|
||||
|
||||
<doc:example module="time">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl2($scope) {
|
||||
$scope.format = 'M/d/yy h:mm:ss a';
|
||||
}
|
||||
|
||||
angular.module('time', [], function($compileProvider) {
|
||||
// Register the 'myCurrentTime' directive factory method.
|
||||
// We inject $defer and dateFilter service since the factory method is DI.
|
||||
$compileProvider.directive('myCurrentTime', function($defer, dateFilter) {
|
||||
// return the directive link function. (compile function not needed)
|
||||
return function(scope, element, attrs) {
|
||||
var format, // date format
|
||||
deferId; // deferId, so that we can cancel the time updates
|
||||
|
||||
// used to update the UI
|
||||
function updateTime() {
|
||||
element.text(dateFilter(new Date(), format));
|
||||
}
|
||||
|
||||
// watch the expression, and update the UI on change.
|
||||
scope.$watch(attrs.myCurrentTime, function(value) {
|
||||
format = value;
|
||||
updateTime();
|
||||
});
|
||||
|
||||
// schedule update in one second
|
||||
function updateLater() {
|
||||
// save the deferId for canceling
|
||||
deferId = $defer(function() {
|
||||
updateTime(); // update DOM
|
||||
updateLater(); // schedule another update
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// listen on DOM destroy (removal) event, and cancel the next UI update
|
||||
// to prevent updating time ofter the DOM element was removed.
|
||||
element.bind('$destroy', function() {
|
||||
$defer.cancel(deferId);
|
||||
});
|
||||
|
||||
updateLater(); // kick of the UI update process.
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<div ng-controller="Ctrl2">
|
||||
Date format: <input ng-model='format'> <hr/>
|
||||
Current time is: <span my-current-time="format"></span
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
|
||||
# Writing directives (long version)
|
||||
|
||||
The full skeleton of the directive is shown here:
|
||||
|
||||
<pre>
|
||||
var $compileProvider = ...;
|
||||
|
||||
$compileProvider.directive('directiveName', function factory(injectables) {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
template: '<div></div>',
|
||||
templateUrl: 'directive.html',
|
||||
restrict: 'EACM',
|
||||
scope: false,
|
||||
compile: function compile(tElement, tAttrs) {
|
||||
return {
|
||||
pre: function preLink(scope, iElement, iAttrs) { ... },
|
||||
post: function postLink(scope, iElement, iAttrs) { ... }
|
||||
}
|
||||
},
|
||||
link: function postLink(scope, iElement, iAttrs) { ... }
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
</pre>
|
||||
|
||||
In most cases you will not need such fine control and so the above can be simplified. All of the
|
||||
different parts of this skeleton are explained in following sections. In this section we are
|
||||
interested only isomers of this skeleton.
|
||||
|
||||
It is rare that you need `preLink` method since most directives use the `postLink` method.
|
||||
Therefore the above can be simplified as:
|
||||
|
||||
<pre>
|
||||
var $compileProvider = ...;
|
||||
|
||||
$compileProvider.directive('directiveName', function factory(injectables) {
|
||||
var directiveDefinitionObject = {
|
||||
compile: function compile(tElement, tAttrs) {
|
||||
return function postLink(scope, iElement, iAttrs) { ... }
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
</pre>
|
||||
|
||||
Most directives concern themselves only with instances not with template transformations allowing
|
||||
further simplification:
|
||||
|
||||
<pre>
|
||||
var $compileProvider = ...;
|
||||
|
||||
$compileProvider.directive('directiveName', function factory(injectables) {
|
||||
return function postLink(scope, iElement, iAttrs) { ... }
|
||||
});
|
||||
</pre>
|
||||
|
||||
|
||||
## Factory method
|
||||
|
||||
The factory method is responsible for creating the directive. It is invoked only once, when the
|
||||
{@link angular.module.ng.$compile compiler} matches the directive for the first time. You can
|
||||
perform any initialization work here. The method is invoked using the {@link
|
||||
http://localhost:8000/build/docs/api/angular.module.AUTO.$injector#invoke $injector.invoke} which
|
||||
makes it injectable following all of the rules of injection annotation.
|
||||
|
||||
## Directive Definition Object
|
||||
|
||||
The directive definition object provides instructions to the {@link angular.module.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. Higher `priority` goes
|
||||
first. The order of directives within the same priority is undefined.
|
||||
|
||||
* `terminal` - If set to true then the current `priority` will be the last set of directives
|
||||
which will execute (this means that 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. It is an error
|
||||
to have two directives on the same element both requesting new scope. The new scope rule does
|
||||
not apply for the root of the template since the root of the template always gets a new scope.
|
||||
|
||||
* `restrict` - String of subset of `EACM` which restricts the directive to a specific directive
|
||||
declaration style.
|
||||
|
||||
* `E` - Element name: `<my-directive></my-directive>`
|
||||
* `A` - Attribute: `<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 HTML may have
|
||||
`<<content>>` string embedded in itself, in which case the current element content
|
||||
will be transferred there. The replacement process migrates all of the attributes / classes
|
||||
from the old element to the new one. See Creating Widgets section below for more information.
|
||||
|
||||
* `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.
|
||||
|
||||
* `compile`: This is the compile function described in the section below.
|
||||
|
||||
* `link`: This is the link function described in the section below. This property is used only
|
||||
if the `compile` property is not defined.
|
||||
|
||||
## Compile function
|
||||
|
||||
<pre>
|
||||
function compile(tElement, tAttrs) { ... }
|
||||
</pre>
|
||||
|
||||
Compile function deals with transforming the template DOM. Since most directives do not do
|
||||
template transformation, it is not used often. Examples which require compile functions are
|
||||
directives which transform template DOM such as {@link
|
||||
angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} or load the contents
|
||||
asynchronously such as {@link angular.module.ng.$compileProvider.directive.ng:view ng:view}. The
|
||||
compile functions 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. See {@link
|
||||
angular.module.ng.$compileProvider.directive.Attributes Attributes}
|
||||
|
||||
NOTE: The template instance and the link instance may not be the same objects if the template has
|
||||
been cloned. For this reason it is not safe to do anything other the DOM transformation.
|
||||
Specifically listener registration as not allowed inside the compile function.
|
||||
|
||||
## Link function
|
||||
|
||||
<pre>
|
||||
function link(scope, iElement, iAttrs) { ... }
|
||||
</pre>
|
||||
|
||||
Compile 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 angular.module.ng.$rootScope.Scope Scope} - The scope to be used be the
|
||||
directive for registering {@link angular.module.ng.$rootScope.Scope#.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. See {@link
|
||||
angular.module.ng.$compileProvider.directive.Attributes Attributes}
|
||||
|
||||
|
||||
### Pre link 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 link function
|
||||
|
||||
Executed after the child elements are linked. Safe to do DOM transformation in here.
|
||||
|
||||
## Attributes
|
||||
|
||||
Attributes object is a way of accessing element attributes which:
|
||||
|
||||
* *normalize attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
|
||||
sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed 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.
|
||||
|
||||
|
||||
# Creating Widgets
|
||||
|
||||
It is often desirable to replace a single directive with a more complex DOM structure. This
|
||||
allows the directives to become a short hand for reusable components from which applications
|
||||
can be built.
|
||||
|
||||
Following is an example of building a reusable widget.
|
||||
|
||||
|
||||
<doc:example module="zippyModule">
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl3($scope) {
|
||||
$scope.title = 'Lorem Ipsum';
|
||||
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
|
||||
}
|
||||
|
||||
angular.module('zippyModule', [], function($compileProvider) {
|
||||
$compileProvider.directive('zippy', function(){
|
||||
return {
|
||||
// This HTML will replace the zippy directive.
|
||||
replace: true,
|
||||
template: '<div>' +
|
||||
'<div class="title"></div>' +
|
||||
'<div class="body"><<content>></div>' +
|
||||
'</div>',
|
||||
// The linking function will add behavior to the template
|
||||
link: function(scope, element, attrs) {
|
||||
// Title element
|
||||
var title = angular.element(element.children()[0]),
|
||||
// Opened / closed state
|
||||
opened = true;
|
||||
|
||||
// Watch the zippy-title attribute, copy changes to title element
|
||||
scope.$watch(
|
||||
function(){ return attrs.zippyTitle; },
|
||||
function(value) { return title.text(value); }
|
||||
);
|
||||
|
||||
// Clicking on title should open/close the zippy
|
||||
title.bind('click', toggle);
|
||||
|
||||
// Toggle the closed/opened state
|
||||
function toggle() {
|
||||
opened = !opened;
|
||||
element.removeClass(opened ? 'closed' : 'opened');
|
||||
element.addClass(opened ? 'opened' : 'closed');
|
||||
}
|
||||
|
||||
// initialize the zippy
|
||||
toggle();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.zippy {
|
||||
border: 1px solid black;
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
}
|
||||
.zippy.opened > .title:before { content: '▼ '; }
|
||||
.zippy.opened > .body { display: block; }
|
||||
.zippy.closed > .title:before { content: '► '; }
|
||||
.zippy.closed > .body { display: none; }
|
||||
.zippy > .title {
|
||||
background-color: black;
|
||||
color: white;
|
||||
padding: .1em .3em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.zippy > .body {
|
||||
padding: .1em .3em;
|
||||
}
|
||||
</style>
|
||||
<div ng-controller="Ctrl3">
|
||||
Title: <input ng-model="title"> <br>
|
||||
Text: <textarea ng-model="text"></textarea>
|
||||
<hr>
|
||||
<div class="zippy" zippy-title="Details: {{title}}...">{{text}}</div>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should bind and open / close', function() {
|
||||
input('title').enter('TITLE');
|
||||
input('text').enter('TEXT');
|
||||
expect(element('.title').text()).toEqual('Details: TITLE...');
|
||||
expect(binding('text')).toEqual('TEXT');
|
||||
|
||||
expect(element('.zippy').prop('className')).toMatch(/closed/);
|
||||
element('.zippy > .title').click();
|
||||
expect(element('.zippy').prop('className')).toMatch(/opened/);
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
|
||||
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
## Angular Compiler API
|
||||
|
||||
* {@link angular.widget Widgets} - Angular custom DOM element
|
||||
* {@link angular.directive Directives} - Angular DOM element attributes
|
||||
* {@link angular.markup Markup} and {@link angular.attrMarkup Attribute Markup}
|
||||
* {@link angular.module.ng.$compileProvider.directive Directives} - Angular DOM element attributes
|
||||
* {@link angular.module.ng.$filter Filters} - Angular output filters
|
||||
* {@link angular.module.ng.$compile $compile} - Template compiler
|
||||
|
||||
|
|
|
|||
|
|
@ -102,11 +102,10 @@ The two partials are defined in the following URLs:
|
|||
|
||||
* Routes are defined in the `AppCntl` class. The initialization of the controller causes the
|
||||
initialization of the {@link api/angular.module.ng.$route $route} service with the proper URL
|
||||
routes.
|
||||
routes.
|
||||
* The {@link api/angular.module.ng.$route $route} service then watches the URL and instantiates the
|
||||
appropriate controller when the URL changes.
|
||||
* The {@link api/angular.widget.ng:view ng:view} widget loads the view when the URL changes. It
|
||||
also
|
||||
sets the view scope to the newly instantiated controller.
|
||||
* The {@link api/angular.module.ng.$compileProvider.directive.ng:view ng:view} widget loads the
|
||||
view when the URL changes. It also sets the view scope to the newly instantiated controller.
|
||||
* Changing the URL is sufficient to change the controller and view. It makes no difference whether
|
||||
the URL is changed programatically or by the user.
|
||||
|
|
|
|||
|
|
@ -102,12 +102,12 @@ allow a user to enter data.
|
|||
|
||||
# Things to notice
|
||||
|
||||
* The user data model is initialized {@link api/angular.directive.ng:controller controller} and is
|
||||
available in
|
||||
the {@link api/angular.module.ng.$rootScope.Scope scope} with the initial data.
|
||||
* The user data model is initialized {@link api/angular.module.ng.$compileProvider.directive.ng:controller controller} and is
|
||||
available in the {@link api/angular.module.ng.$rootScope.Scope scope} with the initial data.
|
||||
* For debugging purposes we have included a debug view of the model to better understand what
|
||||
is going on.
|
||||
* The {@link api/angular.widget.input input widgets} simply refer to the model and are data-bound.
|
||||
* The {@link api/angular.module.ng.$compileProvider.directive.input input directives} simply refer
|
||||
to the model and are data-bound.
|
||||
* The inputs {@link guide/dev_guide.forms validate}. (Try leaving them blank or entering non digits
|
||||
in the zip field)
|
||||
* In your application you can simply read from or write to the model and the form will be updated.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@
|
|||
Take a look through the source and note:
|
||||
|
||||
* The script tag that {@link guide/dev_guide.bootstrap bootstraps} the angular environment.
|
||||
* The text {@link api/angular.widget.input input widget} which is bound to the greeting name text.
|
||||
* The text {@link api/angular.module.ng.$compileProvider.directive.input input widget} which is
|
||||
bound to the greeting name text.
|
||||
* No need for listener registration and event firing on change events.
|
||||
* The implicit presence of the `name` variable which is in the root {@link api/angular.module.ng.$rootScope.Scope scope}.
|
||||
* The double curly brace `{{markup}}`, which binds the name variable to the greeting text.
|
||||
|
|
|
|||
|
|
@ -31,18 +31,19 @@ and manage the whole page. You do this as follows:
|
|||
|
||||
You need to declare the angular namespace declaration in the following cases:
|
||||
|
||||
* For all browsers if you are using XHTML.
|
||||
* For Internet Explorer older than version 9 (because older versions of IE do not render widgets
|
||||
* For all types of browser if you are using XHTML.
|
||||
* For Internet Explorer older than version 9 (because older versions of IE do not render namespace
|
||||
properly for either HTML or XHTML).
|
||||
|
||||
|
||||
## Creating Your Own Namespaces
|
||||
|
||||
When you are ready to define your own {@link dev_guide.compiler.widgets widgets}, you must create
|
||||
your own namespace in addition to specifying the angular namespace. You use your own namespace to
|
||||
form the fully qualified name for widgets that you create.
|
||||
When you are ready to define your own {@link api/angular.module.ng.$compileProvider.directive
|
||||
directive}, you may chose to create your own namespace in addition to specifying the angular
|
||||
namespace. You use your own namespace to form the fully qualified name for directives that you
|
||||
create.
|
||||
|
||||
For example, you could map the alias `my` to your domain, and create a widget called `my:widget`.
|
||||
For example, you could map the alias `my` to your domain, and create a directive called `my:directive`.
|
||||
To create your own namespace, simply add another `xmlns` tag to your page, create an alias, and set
|
||||
it to your unique domain:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Directives: Creating Custom Angular Directives
|
||||
@description
|
||||
|
||||
The following code snippet shows how to define a custom directive. You define a new directive by
|
||||
extending the {@link dev_guide.compiler Angular HTML compiler}. The code snippet below is a
|
||||
simplified definition of the built-in {@link api/angular.directive.ng:bind ng:bind} directive:
|
||||
|
||||
<pre>
|
||||
angular.directive('ng:bind', function(expression, compiledElement) {
|
||||
var compiler = this;
|
||||
return function(linkElement) {
|
||||
var currentScope = this;
|
||||
currentScope.$watch(expression, function(value) {
|
||||
linkElement.text(value);
|
||||
});
|
||||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
# Additional Compiler Methods for Custom Directives
|
||||
|
||||
The angular compiler exposes methods that you may need to use when writing your own widgets and
|
||||
directives. For example, the `descend()` method lets you control whether the compiler ignores or
|
||||
processes child elements of the element it is compiling. For information on this and other
|
||||
compiler methods, see the {@link api/angular.module.ng.$compile Compiler API doc}.
|
||||
|
||||
|
||||
## Related Docs
|
||||
|
||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link api/angular.directive Angular Directive API}.
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Understanding Angular Directives
|
||||
@description
|
||||
|
||||
An angular directive is a custom HTML attribute that angular knows how to process. You add them to
|
||||
a template element like any other attribute. Angular directives all have a `ng:` prefix. In the
|
||||
following example, the angular directive (`ng:controller`) is a div tag:
|
||||
|
||||
<div ng:controller>
|
||||
|
||||
You use angular directives to modify DOM element properties. The element you modify can be an
|
||||
existing HTML element type or a custom DOM element type that you created. You can use any number of
|
||||
directives per element.
|
||||
|
||||
You add angular directives to a standard HTML tag as in the following example, in which we have
|
||||
added the {@link api/angular.directive.ng:click ng:click} directive to a button tag:
|
||||
|
||||
<button ng:click="foo()">Click This</button>
|
||||
|
||||
The `ng:click` directive lets you specify click event handlers directly in the template. Unlike the
|
||||
evil `onclick` attribute, the expression associated with the `ng:click` directive is always executed
|
||||
in the context of the current angular scope.
|
||||
|
||||
In the next example, we add the {@link api/angular.directive.ng:bind ng:bind} directive to a
|
||||
`<span>` tag:
|
||||
|
||||
<span ng:bind="1+2"></span>
|
||||
|
||||
The `ng:bind` directive tells angular to set up {@link dev_guide.templates.databinding data
|
||||
binding} between the data model and the view for the specified expression. When the angular {@link
|
||||
dev_guide.compiler compiler} encounters an `ng:bind` directive in a template, it passes the
|
||||
attribute value to the `ng:bind` function, which in turn sets up the data binding. On any change to
|
||||
the model that would change the result of the expression, the view is updated and the text of the
|
||||
span element will reflect the new value. In the example above, the model is represented by two
|
||||
constants, so nothing will ever change - Sorry!
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
* {@link dev_guide.compiler.directives.creating_directives Creating Angular Directives}
|
||||
* {@link dev_guide.compiler.directives_widgets Comparing Directives and Widgets}
|
||||
|
||||
## Related API:
|
||||
|
||||
* {@link api/angular.directive Directive API}
|
||||
* {@link api/angular.widget Widget API}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Comparing Directives and Attribute Widgets
|
||||
@description
|
||||
|
||||
Although directives and {@link dev_guide.compiler.widgets attribute widgets} appear the same in a
|
||||
template (`ng:init` is a directive, `ng:repeat` is an attribute widget), there is a difference in
|
||||
the order in which they are evaluated. The user of existing directives or widgets cannot determine
|
||||
the order of evaluation. The evaluation order is the responsibility of the developer creating
|
||||
custom directives and widgets.
|
||||
|
||||
For example, consider this piece of HTML, which uses the `ng:repeat`, `ng:init`, and `ng:bind`
|
||||
widget and directives:
|
||||
|
||||
<pre>
|
||||
<ul ng:init="people=['mike', 'mary']">
|
||||
<li ng:repeat="person in people"
|
||||
ng:init="a=a+1"
|
||||
ng:bind="person">
|
||||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
|
||||
Notice that the order of execution matters here. Because we want to run the `ng:init="a=a+1` and
|
||||
`ng:bind="person"` once for each `person in people`, we need to execute {@link
|
||||
api/angular.widget.@ng:repeat ng:repeat} to make copies of the `<li>` element before we run the
|
||||
{@link api/angular.directive.ng:init ng:init}, and {@link api/angular.directive.ng:bind ng:bind}
|
||||
for each of the `<li>`copies.
|
||||
|
||||
If you implemented `ng:repeat` as a directive, there would be no guarantee that the attributes
|
||||
`ng:repeat`, `ng:init`, and `ng:bind` would be evaluated in the order they are declared, because
|
||||
the order of element attributes in HTML is not significant to the browser.
|
||||
|
||||
So, when creating a custom HTML attribute, you will have to consider whether a directive or a
|
||||
widget is more appropriate. When the order of execution doesn't matter, directives are the right
|
||||
choice. In a situation where the order matters and one attribute should be processed with a higher
|
||||
priority than others, use a widget for the attribute that must be processed first.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
||||
|
||||
## Related API:
|
||||
|
||||
* {@link api/angular.directive Directive API}
|
||||
* {@link api/angular.widget Widget API}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Extending the Angular Compiler
|
||||
@description
|
||||
|
||||
Let's say that we want to create a new DOM element called `<my:greeter/>` that displays a greeting.
|
||||
We want this HTML source:
|
||||
|
||||
<pre>
|
||||
<div ng:init="s='Hello'; n='World'">
|
||||
<my:greeter salutation="s" name="n"></my:greeter>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
to produce this DOM:
|
||||
|
||||
<pre>
|
||||
<div ng:init="s='Hello'; n='World'">
|
||||
<my:greeter salutation="s" name="n"/>
|
||||
<span class="salutation">Hello</span>
|
||||
<span class="name">World</span>!
|
||||
</my:greeter>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
That is, the new `<my:greeter></my:greeter>` tag's `salutation` and `name` attributes should be
|
||||
transformed by the compiler such that two `<span>` tags display the values of the attributes, with
|
||||
CSS classes applied to the output.
|
||||
|
||||
The following code snippet shows how to write a following widget definition that will be processed
|
||||
by the compiler. Note that you have to declare the {@link dev_guide.bootstrap namespace} `my` 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(' ');
|
||||
linkElement.append(nameSpan);
|
||||
linkElement.append('!');
|
||||
this.$watch(salutationExp, function(value){
|
||||
salutationSpan.text(value);
|
||||
});
|
||||
this.$watch(nameExp, function(value){
|
||||
nameSpan.text(value);
|
||||
});
|
||||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
|
||||
Note: For more about widgets, see {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
||||
and the {@link api/angular.widget widget API reference page}.
|
||||
|
||||
# Compilation process for `<my:greeter>`
|
||||
|
||||
Here are the steps that the compiler takes in processing the page that contains the widget
|
||||
definition above:
|
||||
|
||||
## Compile Phase
|
||||
|
||||
1. Recursively traverse the DOM depth-first.
|
||||
2. Find the angular.widget definition.
|
||||
3. Find and execute the widget's compileElement function, which includes the following steps:
|
||||
1. 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)).
|
||||
2. Extract the salutation and name HTML attributes as angular expressions.
|
||||
4. Return the aggregate link function, which includes just one link function in this example.
|
||||
|
||||
## Link Phase
|
||||
|
||||
1. Execute the aggregate link function, which includes the following steps:
|
||||
1. Create a <span> element set to the salutation class
|
||||
2. Create a <span> element set to the name class.
|
||||
2. Add the span elements to the linkElement. (Note: be careful not to add them to the
|
||||
compileElement, because that's the template.)
|
||||
3. Set up watches on the expressions. When an expression changes, copy the data to the
|
||||
corresponding spans.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
||||
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link api/angular.module.ng.$compile $compile()}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Understanding Angular Markup
|
||||
@description
|
||||
|
||||
Markup in angular is a feature that you can use in templates to transform the content of DOM
|
||||
elements prior to the compile phase (in which elements are compiled and link functions are
|
||||
returned. See the {@link dev_guide.compiler compiler docs} for details on how the compiler
|
||||
works.) The ability to make pre-compile changes to DOM elements lets you create shorthand for
|
||||
{@link api/angular.widget widget} and {@link api/angular.directive directive} declarations.
|
||||
|
||||
Angular provides one built-in markup feature: the double curly-braces used to declare binding
|
||||
points (between the model and view) for angular expressions. You can also create your own custom
|
||||
markup.
|
||||
|
||||
# Using Double Curly-brace Markup (`{{ }}`)
|
||||
|
||||
The double curly-brace (`{{ }}`) markup translates an enclosed expression into an {@link
|
||||
api/angular.directive.ng:bind ng:bind} directive:
|
||||
|
||||
<pre>
|
||||
{{expression}}
|
||||
</pre>
|
||||
|
||||
is transformed to:
|
||||
|
||||
<pre>
|
||||
<span ng:bind="expression"></span>
|
||||
</pre>
|
||||
|
||||
Markup is useful for the simple reason that `{{1+2}}` is easier to write and understand than `<span
|
||||
ng:bind="1+2"></span>`. After markup shorthand is expanded into the DOM elements it represents, the
|
||||
expanded elements are then {@link dev_guide.compiler compiled} normally.
|
||||
|
||||
|
||||
# Creating Custom Markup
|
||||
|
||||
Let's say you want to define markup that transforms `---` into a horizontal rule (`<hr/>`):
|
||||
|
||||
<pre>
|
||||
header
|
||||
---
|
||||
footer
|
||||
</pre>
|
||||
|
||||
should translate to:
|
||||
<pre>
|
||||
header
|
||||
<hr/>
|
||||
footer
|
||||
</pre>
|
||||
|
||||
Here is how you could extend the angular compiler to create the "---" markup:
|
||||
|
||||
<pre>
|
||||
angular.markup('---', function(text, textNode, parentElement) {
|
||||
var compiler = this;
|
||||
var index = text.indexOf('---');
|
||||
if (index > -1) {
|
||||
textNode.after(text.substring(index + 3));
|
||||
textNode.after(angular.element('<hr>'));
|
||||
textNode.after(text.substring(0, index));
|
||||
textNode.remove();
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
Unlike the way the compiler processes {@link api/angular.widget widgets} and {@link
|
||||
api/angular.directive directives} (matching the name of the handler function to a DOM element or
|
||||
attribute name), the compiler calls every markup handler for every text node, giving the handler a
|
||||
chance to transform the text. The markup handler needs to find all the matches in the text.
|
||||
|
||||
## Attribute Markup
|
||||
|
||||
Attribute markup extends the angular compiler in a very similar way to markup, except that it
|
||||
allows you to modify the state of attribute text rather then the content of a node.
|
||||
|
||||
<pre>
|
||||
angular.attrMarkup('extraClass', function(attrValue, attrName, element){
|
||||
if (attrName == 'additional-class') {
|
||||
element.addClass(attrValue);
|
||||
}
|
||||
});
|
||||
</pre>
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link api/angular.module.ng.$compile Compiler API Reference}
|
||||
|
|
@ -2,8 +2,8 @@
|
|||
@name Developer Guide: Angular HTML Compiler
|
||||
@description
|
||||
|
||||
The core of angular is its HTML compiler. The compiler processes angular directives, widgets, and
|
||||
markup to transform a static HTML page into a dynamic web application.
|
||||
The core of angular is its HTML compiler. The compiler processes angular directives allowing them
|
||||
to transform a static HTML page into a dynamic web application.
|
||||
|
||||
The default HTML transformations that the angular compiler provides are useful for building generic
|
||||
apps, but you can also extend the compiler to create a domain-specific language for building
|
||||
|
|
@ -15,12 +15,9 @@ All compilation takes place in the web browser; no server is involved.
|
|||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
||||
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
||||
* {@link dev_guide.compiler.testing_dom_element Testing a New DOM Element}
|
||||
* {@link dev_guide.compiler.widgets Understanding Angular Widgets}
|
||||
* {@link dev_guide.compiler.directives Understanding Angular Directives}
|
||||
* {@link dev_guide.compiler.markup Understanding Angular Markup}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link api/angular.module.ng.$compile Angular Compiler API}
|
||||
* {@link api/angular.module.ng.$compileProvider.directive Directives API}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
* {@link dev_guide.compiler.understanding_compiler Understanding How the Compiler Works}
|
||||
* {@link dev_guide.compiler.extending_compiler Extending the Angular Compiler}
|
||||
|
||||
## Related API
|
||||
|
||||
|
|
|
|||
|
|
@ -2,59 +2,27 @@
|
|||
@name Developer Guide: Angular HTML Compiler: Understanding How the Compiler Works
|
||||
@description
|
||||
|
||||
Every {@link api/angular.widget widget}, {@link api/angular.directive directive} and {@link
|
||||
dev_guide.compiler.markup markup} is defined with a compile function, which the angular compiler
|
||||
executes on each widget or directive it encounters. The compile function optionally returns a link
|
||||
function. This compilation process happens automatically when the page is loaded when you specify
|
||||
`ng:app` on the root element of the application. (See {@link dev_guide.bootstrap Initializing Angular}.)
|
||||
The {@link angular.module.ng.$compile compiler} is responsible for applying
|
||||
{@link angular.module.ng.$compileProvider.directive directives} to the HTML. The directives
|
||||
extend the behavior of HTML elements and can effect the DOM structure, presentation, and behavior.
|
||||
This allows Angular to teach the browser new tricks.
|
||||
|
||||
The compile and link functions are related as follows:
|
||||
The compilation starts at the root element and proceeds in a depth-first order. As the compiler
|
||||
visits each node it collects the directives, orders them by priority and executes their compile
|
||||
function. The result of the compilation process is a linking function. The linking function
|
||||
can be used on the template clones to quickly bind the directives with the scope.
|
||||
|
||||
* **compile function** — Registers a listener for the widget, directive, or markup expression. The
|
||||
compiler calls this function exactly once.
|
||||
* **link function** — Sets up the listener registered by the compile function. This function can be
|
||||
called multiple times, once per cloned DOM element. For example, in the case of the {@link
|
||||
api/angular.widget.@ng:repeat repeater widget} used in a list element (`<li ng:repeat="[item in
|
||||
dataset]"`), the link function gets called to set up a listener on each element in the list.
|
||||
The result of the compilation process is a live view. We say 'live' since any changes to the
|
||||
model attached to the {@link angular.module.ng.$rootScope.Scope scope} are reflected in the view,
|
||||
and any changes in the view are reflected in the scope. This makes the scope the 'single source of
|
||||
truth'.
|
||||
|
||||
Note that angular's built-in widgets, directives, and markup have predefined compile and link
|
||||
functions that you don't need to modify. When you create your own widgets, directives, or markup,
|
||||
you must write compile and link functions for them. Refer to the {@link api/angular.module.ng.$compile
|
||||
Compiler API} for details.
|
||||
|
||||
When the angular compiler compiles a page, it proceeds through 3 phases: Compile, Create Root
|
||||
Scope, and Link:
|
||||
|
||||
1. Compile Phase
|
||||
|
||||
1. Recursively traverse the DOM, depth-first.
|
||||
2. Look for a matching compile function of type widget, then markup, then directive.
|
||||
3. If a compile function is found then execute it.
|
||||
4. When the compile function completes, it should return a link function. Aggregate this link
|
||||
function with all link functions returned previously by step 3.
|
||||
5. Repeat steps 3 and 4 for all compile functions found.
|
||||
|
||||
The result of the compilation phase is an aggregate link function, which comprises all of the
|
||||
individual link functions.
|
||||
|
||||
2. Create Root Scope Phase
|
||||
|
||||
* Inject all services into the root scope.
|
||||
|
||||
3. Link Phase
|
||||
|
||||
1. Execute the aggregate link function with the root scope. The aggregate link function calls
|
||||
all of the individual link functions that were generated in the compile phase.
|
||||
2. 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, for example, once for each iteration in a repeater.
|
||||
|
||||
The angular compiler exposes methods that you will need to make use of when writing your own
|
||||
widgets and directives. For information on these methods, see the {@link api/angular.module.ng.$compile
|
||||
Compiler API doc}.
|
||||
Since directives allow attachment of behavior to the HTML, the angular philosophy is to use the
|
||||
HTML as Domain Specific Language (DSL) when building an application. For example it may be useful
|
||||
to declare `TabPanel` directive, or `KeyboardShortcut` directive when for an application.
|
||||
|
||||
For details on how directives are created see {@link angular.module.ng.$compileProvider.directive
|
||||
directives}
|
||||
|
||||
## Related Topics
|
||||
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Widgets: Creating Custom Widgets
|
||||
@description
|
||||
|
||||
When you create your own widgets, you must set up your own namespace for them. (See
|
||||
dev_guide.bootstrap Initializing Angular} for information about namespaces in angular.)
|
||||
|
||||
Let's say we would like to create a new element type in the namespace `my` that can watch an
|
||||
expression and `alert()` the user with each new value:
|
||||
|
||||
<pre>
|
||||
// An element widget
|
||||
<my:watch exp="name"></my:watch>
|
||||
</pre>
|
||||
|
||||
You can implement `my:watch` like this:
|
||||
|
||||
<pre>
|
||||
angular.widget('my:watch', function(compileElement) {
|
||||
var compiler = this;
|
||||
var exp = compileElement.attr('exp');
|
||||
return function(linkElement) {
|
||||
var currentScope = this;
|
||||
currentScope.$watch(exp, function(value){
|
||||
alert(value);
|
||||
});
|
||||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
|
||||
# Creating a Custom Attribute Widget
|
||||
|
||||
Let's implement the same widget as in the example in Defining an Element Widget, but this time as
|
||||
an attribute that can be added to any existing DOM element:
|
||||
|
||||
<pre>
|
||||
// An attribute widget (my:watch) in a div tag
|
||||
<div my:watch="name">text</div>
|
||||
</pre>
|
||||
You can implement `my:watch` attribute like this:
|
||||
<pre>
|
||||
angular.widget('@my:watch', function(expression, compileElement) {
|
||||
var compiler = this;
|
||||
return function(linkElement) {
|
||||
var currentScope = this;
|
||||
currentScope.$watch(expression, function(value) {
|
||||
alert(value);
|
||||
});
|
||||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
|
||||
# Live Example of a Custom Element Widget
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<script>
|
||||
angular.widget('my:time', function(compileElement){
|
||||
compileElement.css('display', 'block');
|
||||
return function(linkElement){
|
||||
function update() {
|
||||
linkElement.text('Current time is: ' + new Date());
|
||||
setTimeout(update, 1000);
|
||||
}
|
||||
update();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<my:time></my:time>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
|
||||
# Additional Compiler Methods for Custom Widgets
|
||||
|
||||
The angular compiler exposes methods that you may need to use of when writing your own widgets and
|
||||
directives. For example, the `descend()` method lets you control whether the compiler ignores or
|
||||
processes child elements of the element it is compiling. For information on this and other
|
||||
compiler methods, see the {@link api/angular.module.ng.$compile Compiler API doc}.
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
* {@link dev_guide.compiler.directives Angular Directives}
|
||||
* {@link dev_guide.compiler.widgets Angular Widgets}
|
||||
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link api/angular.module.ng.$compile Compiler API}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
@ngdoc overview
|
||||
@name Developer Guide: Angular HTML Compiler: Understanding Angular Widgets
|
||||
@description
|
||||
|
||||
Widgets are DOM elements that the browser doesn't already understand. Angular provides some
|
||||
built-in widgets (such as {@link api/angular.widget.@ng:repeat ng:repeat}), and you can create your
|
||||
own custom widgets.
|
||||
|
||||
Widgets are intended to manipulate the DOM tree by adding new elements (unlike {@link
|
||||
dev_guide.compiler.directives angular directives}, which are intended to modify only element
|
||||
properties).
|
||||
|
||||
Widgets come in two types:
|
||||
|
||||
* Element Widget — A custom DOM element. An example of a custom element is shown in {@link
|
||||
dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
|
||||
|
||||
* Attribute Widget — A custom attribute on an existing DOM element. An attribute widget is similar
|
||||
to an angular directive, with the main difference being that an attribute widget will always be
|
||||
processed before any directives that are specified on the same element. Only one attribute widget
|
||||
is allowed per element. An example of an attribute widget is shown in {@link
|
||||
dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}.
|
||||
|
||||
|
||||
|
||||
## Related Topics
|
||||
|
||||
* {@link dev_guide.compiler Angular HTML Compiler}
|
||||
* {@link dev_guide.compiler.directives Angular Directives}
|
||||
* {@link dev_guide.compiler.widgets.creating_widgets Creating Custom Widgets}
|
||||
* {@link dev_guide.compiler.directives.creating_directives Creating Custom Directives}
|
||||
|
||||
## Related API
|
||||
|
||||
* {@link api/angular.module.ng.$compile Compiler API}
|
||||
|
|
@ -58,12 +58,8 @@ You can try evaluating different expressions here:
|
|||
this.exprs.push(expr);
|
||||
};
|
||||
|
||||
$scope.removeExp = function(contact) {
|
||||
for ( var i = 0, ii = this.exprs.length; i < ii; i++) {
|
||||
if (contact === this.exprs[i]) {
|
||||
this.exprs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
$scope.removeExp = function(index) {
|
||||
this.exprs.splice(index, 1);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
|
@ -73,7 +69,7 @@ You can try evaluating different expressions here:
|
|||
<button ng:click="addExp(expr)">Evaluate</button>
|
||||
<ul>
|
||||
<li ng:repeat="expr in exprs">
|
||||
[ <a href="" ng:click="removeExp(expr)">X</a> ]
|
||||
[ <a href="" ng:click="removeExp($index)">X</a> ]
|
||||
<tt>{{expr}}</tt> => <span ng:bind="$parent.$eval(expr)"></span>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ Forms consist of all of the following:
|
|||
# Form
|
||||
|
||||
A form groups a set of widgets together into a single logical data-set. A form is created using
|
||||
the {@link api/angular.widget.form <form>} element that calls the
|
||||
the {@link api/angular.module.ng.$compileProvider.directive.form <form>} element that calls the
|
||||
{@link api/angular.module.ng.$formFactory $formFactory} service. The form is responsible for managing
|
||||
the widgets and for tracking validation information.
|
||||
|
||||
|
|
@ -54,8 +54,8 @@ A form is:
|
|||
# Widgets
|
||||
|
||||
In Angular, a widget is the term used for the UI with which the user input. Examples of
|
||||
bult-in Angular widgets are {@link api/angular.widget.input input} and
|
||||
{@link api/angular.widget.select select}. Widgets provide the rendering and the user
|
||||
bult-in Angular widgets are {@link api/angular.module.ng.$compileProvider.directive.input input} and
|
||||
{@link api/angular.module.ng.$compileProvider.directive.select select}. Widgets provide the rendering and the user
|
||||
interaction logic. Widgets should be declared inside a form, if no form is provided an implicit
|
||||
form {@link api/angular.module.ng.$formFactory $formFactory.rootForm} form is used.
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ The following example demonstrates:
|
|||
<hr/>
|
||||
Debug View:
|
||||
<pre>form={{form|json}}</pre>
|
||||
<pre>master={{master}|json}</pre>
|
||||
<pre>master={{master|json}}</pre>
|
||||
<pre>userForm={{userForm|json}}</pre>
|
||||
<pre>addressForm={{addressForm|json}}</pre>
|
||||
</div>
|
||||
|
|
@ -289,15 +289,15 @@ This example shows how to implement a custom HTML editor widget in Angular.
|
|||
scope.$parseModel = function() {
|
||||
// need to protect for script injection
|
||||
try {
|
||||
this.$viewValue = $sanitize(
|
||||
this.$modelValue || '');
|
||||
scope.$viewValue = $sanitize(
|
||||
scope.$modelValue || '');
|
||||
if (this.$error.HTML) {
|
||||
// we were invalid, but now we are OK.
|
||||
this.$emit('$valid', 'HTML');
|
||||
scope.$emit('$valid', 'HTML');
|
||||
}
|
||||
} catch (e) {
|
||||
// if HTML not parsable invalidate form.
|
||||
this.$emit('$invalid', 'HTML');
|
||||
scope.$emit('$invalid', 'HTML');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +312,7 @@ This example shows how to implement a custom HTML editor widget in Angular.
|
|||
});
|
||||
}
|
||||
|
||||
angular.module.formModule = function($compileProvider){
|
||||
angular.module('formModule', [], function($compileProvider){
|
||||
$compileProvider.directive('ngHtmlEditorModel', function ($formFactory) {
|
||||
return function(scope, element, attr) {
|
||||
var form = $formFactory.forElement(element),
|
||||
|
|
@ -330,7 +330,7 @@ This example shows how to implement a custom HTML editor widget in Angular.
|
|||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<form name='editorForm' ng:controller="EditorCntl">
|
||||
<div ng:html-editor-model="htmlContent"></div>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ http://docs.angularjs.org/#!/api/angular.module.ng.$filter.number number} and {@
|
|||
http://docs.angularjs.org/#!/api/angular.module.ng.$filter.currency currency} filters.
|
||||
|
||||
Additionally, Angular supports localizable pluralization support provided by the {@link
|
||||
api/angular.widget.ng:pluralize ng:pluralize widget}.
|
||||
api/angular.module.ng.$compileProvider.directive.ng:pluralize ng:pluralize widget}.
|
||||
|
||||
All localizable Angular components depend on locale-specific rule sets managed by the {@link
|
||||
api/angular.module.ng.$locale $locale service}.
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ constructor). Constructors are always applied to an existing scope object.
|
|||
|
||||
You set up the initial state of a scope by creating model properties. For example:
|
||||
|
||||
function GreetingCtrl() {
|
||||
this.greeting = 'Hola!';
|
||||
function GreetingCtrl($scope) {
|
||||
$scope.greeting = 'Hola!';
|
||||
}
|
||||
|
||||
The `GreetingCtrl` controller creates a `greeting` model which can be referred to in a template.
|
||||
|
|
@ -43,7 +43,7 @@ As discussed in the {@link dev_guide.mvc.understanding_model Model} section of t
|
|||
objects (or primitives) assigned to the scope become model properties. Any functions assigned to
|
||||
the scope, along with any prototype methods of the controller type, become functions available in
|
||||
the template/view, and can be invoked via angular expressions and `ng:` event handlers (e.g. {@link
|
||||
api/angular.directive.ng:click ng:click}). These controller methods are always evaluated within the
|
||||
api/angular.module.ng.$compileProvider.directive.ng:click ng:click}). These controller methods are always evaluated within the
|
||||
context of the angular scope object that the controller function was applied to (which means that
|
||||
the `this` keyword of any controller method is always bound to the scope that the controller
|
||||
augments). This is how the second task of adding behavior to the scope is accomplished.
|
||||
|
|
@ -78,7 +78,7 @@ instances).
|
|||
# Associating Controllers with Angular Scope Objects
|
||||
|
||||
You can associate controllers with scope objects explicitly via the {@link api/angular.module.ng.$rootScope.Scope#$new
|
||||
scope.$new} api or implicitly via the {@link api/angular.directive.ng:controller ng:controller
|
||||
scope.$new} api or implicitly via the {@link api/angular.module.ng.$compileProvider.directive.ng:controller ng:controller
|
||||
directive} or {@link api/angular.module.ng.$route $route service}.
|
||||
|
||||
|
||||
|
|
@ -105,9 +105,9 @@ string "very". Depending on which button is clicked, the `spice` model is set to
|
|||
<p>The food is {{spice}} spicy!</p>
|
||||
</body>
|
||||
|
||||
function SpicyCtrl() {
|
||||
this.spice = 'very';
|
||||
this.chiliSpicy = function() {
|
||||
function SpicyCtrl($scope) {
|
||||
$scope.spice = 'very';
|
||||
$scope.chiliSpicy = function() {
|
||||
this.spice = 'chili';
|
||||
}
|
||||
}
|
||||
|
|
@ -144,9 +144,9 @@ previous example.
|
|||
<p>The food is {{spice}} spicy!</p>
|
||||
</body>
|
||||
|
||||
function SpicyCtrl() {
|
||||
this.spice = 'very';
|
||||
this.spicy = function(spice) {
|
||||
function SpicyCtrl($scope) {
|
||||
$scope.spice = 'very';
|
||||
$scope.spicy = function(spice) {
|
||||
this.spice = spice;
|
||||
}
|
||||
}
|
||||
|
|
@ -171,18 +171,18 @@ have a look at an example:
|
|||
<p ng:controller="BabyCtrl">Good {{timeOfDay}}, {{name}}!</p>
|
||||
</body>
|
||||
|
||||
function MainCtrl() {
|
||||
this.timeOfDay = 'morning';
|
||||
this.name = 'Nikki';
|
||||
function MainCtrl($scope) {
|
||||
$scope.timeOfDay = 'morning';
|
||||
$scope.name = 'Nikki';
|
||||
}
|
||||
|
||||
function ChildCtrl() {
|
||||
this.name = 'Mattie';
|
||||
function ChildCtrl($scope) {
|
||||
$scope.name = 'Mattie';
|
||||
}
|
||||
|
||||
function BabyCtrl() {
|
||||
this.timeOfDay = 'evening';
|
||||
this.name = 'Gingerbreak Baby';
|
||||
function BabyCtrl($scope) {
|
||||
$scope.timeOfDay = 'evening';
|
||||
$scope.name = 'Gingerbreak Baby';
|
||||
}
|
||||
</pre>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,17 +20,17 @@ following ways:
|
|||
* Make a direct property assignment to the scope object in JavaScript code; this most commonly
|
||||
occurs in controllers:
|
||||
|
||||
function MyCtrl() {
|
||||
function MyCtrl($scope) {
|
||||
// create property 'foo' on the MyCtrl's scope
|
||||
// and assign it an initial value 'bar'
|
||||
this.foo = 'bar';
|
||||
$scope.foo = 'bar';
|
||||
}
|
||||
|
||||
* Use an {@link dev_guide.expressions angular expression} with an assignment operator in templates:
|
||||
|
||||
<button ng:click="{{foos='ball'}}">Click me</button>
|
||||
|
||||
* Use {@link api/angular.directive.ng:init ng:init directive} in templates (for toy/example apps
|
||||
* Use {@link api/angular.module.ng.$compileProvider.directive.ng:init ng:init directive} in templates (for toy/example apps
|
||||
only, not recommended for real applications):
|
||||
|
||||
<body ng:init=" foo = 'bar' ">
|
||||
|
|
@ -45,7 +45,7 @@ when processing the following template constructs:
|
|||
The code above creates a model called "query" on the current scope with the value set to "fluffy
|
||||
cloud".
|
||||
|
||||
* An iterator declaration in {@link api/angular.widget.@ng:repeat ng:repeater}:
|
||||
* An iterator declaration in {@link api/angular.module.ng.$compileProvider.directive.@ng:repeat ng:repeater}:
|
||||
|
||||
<p ng:repeat="phone in phones"></p>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ the DOM based on information in the template, controller and model.
|
|||
|
||||
In the angular implementation of MVC, the view has knowledge of both the model and the controller.
|
||||
The view knows about the model where two-way data-binding occurs. The view has knowledge of the
|
||||
controller through angular directives, such as {@link api/angular.directive.ng:controller
|
||||
ng:controller} and {@link api/angular.widget.ng:view ng:view}, and through bindings of this form:
|
||||
controller through angular directives, such as {@link api/angular.module.ng.$compileProvider.directive.ng:controller
|
||||
ng:controller} and {@link api/angular.module.ng.$compileProvider.directive.ng:view ng:view}, and through bindings of this form:
|
||||
`{{someControllerFunction()}}`. In these ways, the view can call functions in an associated
|
||||
controller function.
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ These input widgets look normal enough, but consider these points:
|
|||
* When this page loaded, angular bound the names of the input widgets (`qty` and `cost`) to
|
||||
variables of the same name. Think of those variables as the "Model" component of the
|
||||
Model-View-Controller design pattern.
|
||||
* Note the angular/HTML widget, {@link api/angular.widget.input input}.
|
||||
* Note the angular/HTML widget, {@link api/angular.module.ng.$compileProvider.directive.input input}.
|
||||
You may have noticed that when you enter invalid data
|
||||
or leave the the input fields blank, the borders turn red color, and the display value disappears.
|
||||
These widgets make it easier to implement field validation than coding them in JavaScript,
|
||||
|
|
@ -113,7 +113,7 @@ And finally, the mysterious `{{ double curly braces }}`:
|
|||
|
||||
This notation, `{{ _expression_ }}`, is a bit of built-in angular {@link dev_guide.compiler.markup
|
||||
markup}, a shortcut for displaying data to the user. The expression within curly braces gets
|
||||
transformed by the angular compiler into an angular directive ({@link api/angular.directive.ng:bind
|
||||
transformed by the angular compiler into an angular directive ({@link api/angular.module.ng.$compileProvider.directive.ng:bind
|
||||
ng:bind}). The expression itself can be a combination of both an expression and a {@link
|
||||
dev_guide.templates.filters filter}: `{{ expression | filter }}`. Angular provides filters for
|
||||
formatting display data.
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@ reside on a child scope, if a property read does not find the property on a scop
|
|||
recursively check the parent scope, grandparent scope, etc. all the way to the root scope before
|
||||
defaulting to undefined.
|
||||
|
||||
{@link api/angular.directive Directives} associated with elements (ng:controller, ng:repeat,
|
||||
ng:include, etc.) create new child scopes that inherit properties from the current parent scope.
|
||||
Any code in Angular is free to create a new scope. Whether or not your code does so is an
|
||||
implementation detail of the directive, that is, you can decide when or if this happens.
|
||||
Inheritance typically mimics HTML DOM element nesting, but does not do so with the same
|
||||
{@link angular.module.ng.$compileProvider.directive directives} associated with elements
|
||||
(ng:controller, ng:repeat, ng:include, etc.) create new child scopes that inherit properties from
|
||||
the current parent scope. Any code in Angular is free to create a new scope. Whether or not your
|
||||
code does so is an implementation detail of the directive, that is, you can decide when or if this
|
||||
happens. Inheritance typically mimics HTML DOM element nesting, but does not do so with the same
|
||||
granularity.
|
||||
|
||||
A property write will always write to the current scope. This means that a write can hide a parent
|
||||
|
|
@ -117,24 +117,25 @@ scopes come into play throughout and get a sense of their interactions.
|
|||
1. At application compile time, a root scope is created and is attached to the root `<HTML>` DOM
|
||||
element.
|
||||
2. During the compilation phase, the {@link dev_guide.compiler compiler} matches {@link
|
||||
api/angular.directive directives} against the DOM template. The directives usually fall into one of
|
||||
two categories:
|
||||
- Observing {@link api/angular.directive directives}, such as double-curly expressions
|
||||
`{{expression}}`, register listeners using the {@link api/angular.module.ng.$rootScope.Scope#$watch $watch()} method.
|
||||
This type of directive needs to be notified whenever the expression changes so that it can update
|
||||
the view.
|
||||
- Listener directives, such as {@link api/angular.directive.ng:click ng:click}, register a
|
||||
listener with the DOM. When the DOM listener fires, the directive executes the associated
|
||||
expression and updates the view using the {@link api/angular.module.ng.$rootScope.Scope#$apply $apply()} method.
|
||||
angular.module.ng.$compileProvider.directive directives} against the DOM template. The directives
|
||||
usually fall into one of two categories:
|
||||
- Observing {@link angular.module.ng.$compileProvider.directive directives}, such as double-curly
|
||||
expressions `{{expression}}`, register listeners using the {@link
|
||||
api/angular.module.ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs to
|
||||
be notified whenever the expression changes so that it can update the view.
|
||||
- Listener directives, such as {@link api/angular.module.ng.$compileProvider.directive.ng:click
|
||||
ng:click}, register a listener with the DOM. When the DOM listener fires, the directive executes
|
||||
the associated expression and updates the view using the {@link
|
||||
api/angular.module.ng.$rootScope.Scope#$apply $apply()} method.
|
||||
3. When an external event (such as a user action, timer or XHR) is received, the associated {@link
|
||||
dev_guide.expressions expression} must be applied to the scope through the {@link
|
||||
api/angular.module.ng.$rootScope.Scope#$apply $apply()} method so that all listeners are updated correctly.
|
||||
|
||||
|
||||
### Directives that create scopes
|
||||
In most cases, {@link api/angular.directive directives} and scopes interact but do not create new
|
||||
instances of scope. However, some directives, such as {@link api/angular.directive.ng:controller
|
||||
ng:controller} and {@link api/angular.widget.@ng:repeat ng:repeat}, create new child scopes using
|
||||
In most cases, {@link angular.module.ng.$compileProvider.directive directives} and scopes interact but do not create new
|
||||
instances of scope. However, some directives, such as {@link api/angular.module.ng.$compileProvider.directive.ng:controller
|
||||
ng:controller} and {@link api/angular.module.ng.$compileProvider.directive.@ng:repeat ng:repeat}, create new child scopes using
|
||||
the {@link api/angular.module.ng.$rootScope.Scope#$new $new()} method and then attach the child scope to the
|
||||
corresponding DOM element. You can retrieve a scope for any DOM element by using an
|
||||
`angular.element(aDomElement).scope()` method call.)
|
||||
|
|
@ -143,7 +144,7 @@ corresponding DOM element. You can retrieve a scope for any DOM element by using
|
|||
### Controllers and scopes
|
||||
Scopes and controllers interact with each other in the following situations:
|
||||
- Controllers use scopes to expose controller methods to templates (see {@link
|
||||
api/angular.directive.ng:controller ng:controller}).
|
||||
api/angular.module.ng.$compileProvider.directive.ng:controller ng:controller}).
|
||||
- Controllers define methods (behavior) that can mutate the model (properties on the scope).
|
||||
- Controllers may register {@link api/angular.module.ng.$rootScope.Scope#$watch watches} on the model. These watches
|
||||
execute immediately after the controller behavior executes, but before the DOM gets updated.
|
||||
|
|
@ -169,7 +170,7 @@ $watch-ers firing and view getting updated. Similarly, when a request to fetch d
|
|||
is made and the response comes back, the data is written into the model (scope) within an $apply,
|
||||
which then pushes updates through to the view and any other dependents.
|
||||
|
||||
A widget that creates scopes (such as {@link api/angular.widget.@ng:repeat ng:repeat}) via `$new`,
|
||||
A widget that creates scopes (such as {@link api/angular.module.ng.$compileProvider.directive.@ng:repeat ng:repeat}) via `$new`,
|
||||
doesn't need to worry about propagating the `$digest` call from the parent scope to child scopes.
|
||||
This happens automatically.
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ the contexts in which Angular creates data-bindings between the model and the vi
|
|||
In addition to providing the context in which data is evaluated, Angular scope objects watch for
|
||||
model changes. The scope objects also notify all components interested in any model changes (for
|
||||
example, functions registered through {@link api/angular.module.ng.$rootScope.Scope#$watch $watch}, bindings created by
|
||||
{@link api/angular.directive.ng:bind ng:bind}, or HTML input elements).
|
||||
{@link api/angular.module.ng.$compileProvider.directive.ng:bind ng:bind}, or HTML input elements).
|
||||
|
||||
Angular scope objects:
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ code, observe how the value of `name` changes, based on the HTML element it is d
|
|||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
The angular {@link api/angular.widget.@ng:repeat ng:repeat} directive creates a new scope for each
|
||||
The angular {@link api/angular.module.ng.$compileProvider.directive.@ng:repeat ng:repeat} directive creates a new scope for each
|
||||
element that it repeats (in this example the elements are list items). In the `<ul>` element, we
|
||||
initialized `name` to "Hank", and we created an array called `names` to use as the data source for
|
||||
the list items. In each `<li>` element, `name` is overridden. Outside of the `<li>` repeater, the
|
||||
|
|
|
|||
|
|
@ -434,40 +434,40 @@ In this examples we use `<base href="/base/index.html" />`
|
|||
this.$location = $location;
|
||||
}
|
||||
|
||||
angular.widget('ng:address-bar', function(tpl) {
|
||||
return function(elm) {
|
||||
var browser = browsers[elm.attr('browser')],
|
||||
input = angular.element('<input type="text" />').val(browser.url()),
|
||||
delay;
|
||||
|
||||
input.bind('keypress keyup keydown', function() {
|
||||
if (!delay) {
|
||||
delay = setTimeout(fireUrlChange, 250);
|
||||
}
|
||||
});
|
||||
|
||||
browser.url = function(url) {
|
||||
return input.val(url);
|
||||
};
|
||||
|
||||
elm.append('Address: ').append(input);
|
||||
|
||||
function fireUrlChange() {
|
||||
delay = null;
|
||||
browser.urlChange(input.val());
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function initEnv(name) {
|
||||
var root = angular.element(document.getElementById(name + '-mode'));
|
||||
angular.bootstrap(root, [function($locationProvider, $provide){
|
||||
angular.bootstrap(root, [function($compileProvider, $locationProvider, $provide){
|
||||
$locationProvider.html5Mode = true;
|
||||
$locationProvider.hashPrefix = '!';
|
||||
|
||||
$provide.value('$browser', browsers[name]);
|
||||
$provide.value('$document', root);
|
||||
$provide.value('$sniffer', {history: name == 'html5'});
|
||||
|
||||
$compileProvider.directive('ngAddressBar', function() {
|
||||
return function(scope, elm, attrs) {
|
||||
var browser = browsers[attrs.browser],
|
||||
input = angular.element('<input type="text" />').val(browser.url()),
|
||||
delay;
|
||||
|
||||
input.bind('keypress keyup keydown', function() {
|
||||
if (!delay) {
|
||||
delay = setTimeout(fireUrlChange, 250);
|
||||
}
|
||||
});
|
||||
|
||||
browser.url = function(url) {
|
||||
return input.val(url);
|
||||
};
|
||||
|
||||
elm.append('Address: ').append(input);
|
||||
|
||||
function fireUrlChange() {
|
||||
delay = null;
|
||||
browser.urlChange(input.val());
|
||||
}
|
||||
};
|
||||
});
|
||||
}]);
|
||||
root.bind('click', function(e) {
|
||||
e.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -9,24 +9,13 @@ Angular sets these CSS classes. It is up to your application to provide useful s
|
|||
|
||||
* `ng-invalid`, `ng-valid`
|
||||
- **Usage:** angular applies this class to an input widget element if that element's input does
|
||||
notpass validation. (see {@link api/angular.widget.input input} widget).
|
||||
notpass validation. (see {@link api/angular.module.ng.$compileProvider.directive.input input} widget).
|
||||
|
||||
* `ng-pristine`, `ng-dirty`
|
||||
- **Usage:** angular {@link api/angular.widget.input input} widget applies `ng-pristine` class
|
||||
- **Usage:** angular {@link api/angular.module.ng.$compileProvider.directive.input input} widget applies `ng-pristine` class
|
||||
to a new input widget element which did not have user interaction. Once the user interacts with
|
||||
the input widget the class is changed to `ng-dirty`.
|
||||
|
||||
# Marking CSS classes
|
||||
|
||||
* `ng-widget`, `ng-directive`
|
||||
- **Usage:** angular sets these class on elements where {@link api/angular.widget widget} or
|
||||
{@link api/angular.directive directive} has bound to.
|
||||
|
||||
|
||||
* Old browser support
|
||||
- Pre v9, IE browsers could not select `ng:include` elements in CSS, because of the `:`
|
||||
character. For this reason angular also sets `ng-include` class on any element which has `:`
|
||||
character in the name by replacing `:` with `-`.
|
||||
|
||||
## Related Topics
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ These are the types of angular elements and element attributes you can use in a
|
|||
* {@link dev_guide.compiler.directives Directive} — An attribute that augments an existing DOM
|
||||
element.
|
||||
* {@link dev_guide.compiler.widgets Widget} — A custom DOM element. An example of a built-in widget
|
||||
is {@link api/angular.widget.@ng:repeat ng:repeat}.
|
||||
is {@link api/angular.module.ng.$compileProvider.directive.@ng:repeat ng:repeat}.
|
||||
* {@link dev_guide.compiler.markup Markup} — Shorthand for a widget or a directive. The double
|
||||
curly brace notation `{{ }}` to bind expressions to elements is built-in angular markup.
|
||||
* {@link dev_guide.templates.filters Filter} — Formats your data for display to the user.
|
||||
|
|
@ -44,7 +44,7 @@ In a simple single-page app, the template consists of HTML, CSS, and angular dir
|
|||
in just one HTML file (usually `index.html`). In a more complex app, you can display multiple views
|
||||
within one main page using "partials", which are segments of template located in separate HTML
|
||||
files. You "include" the partials in the main page using the {@link api/angular.module.ng.$route
|
||||
$route} service in conjunction with the {@link api/angular.widget.ng:view ng:view} directive. An
|
||||
$route} service in conjunction with the {@link api/angular.module.ng.$compileProvider.directive.ng:view ng:view} directive. An
|
||||
example of this technique is shown in the {@link tutorial/ angular tutorial}, in steps seven and
|
||||
eight.
|
||||
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ After the refresh, the page should look something like this:
|
|||
|
||||
These are some of the important points to note from this example:
|
||||
|
||||
* The text input {@link api/angular.widget widget} called `yourname` is bound to a model variable
|
||||
called `yourname`.
|
||||
* The text input {@link api/angular.module.ng.$compileProvider.directive directive}
|
||||
is bound to a model variable called `yourname`.
|
||||
* The double curly braces notation binds the `yourname` model to the greeting text.
|
||||
|
||||
* You did not need to explicitly register an event listener or define an event handler for events!
|
||||
|
|
|
|||
|
|
@ -154,13 +154,12 @@ describe('ngdoc', function() {
|
|||
};
|
||||
}
|
||||
|
||||
var angular_widget = doc('overview', 'angular.widget');
|
||||
var angular_x = doc('function', 'angular.x');
|
||||
var angular_y = doc('property', 'angular.y');
|
||||
var dev_guide_overview = doc('overview', 'dev_guide.overview');
|
||||
var dev_guide_bootstrap = doc('function', 'dev_guide.bootstrap');
|
||||
|
||||
it('should put angular.fn() in front of angular.widget, etc', function() {
|
||||
expect(ngdoc.metadata([angular_widget, angular_y, angular_x]).map(property('id')))
|
||||
.toEqual(['angular.x', 'angular.y', 'angular.widget' ]);
|
||||
it('should put angular.fn() in front of dev_guide.overview, etc', function() {
|
||||
expect(ngdoc.metadata([dev_guide_overview, dev_guide_bootstrap]).map(property('id')))
|
||||
.toEqual(['dev_guide.overview', 'dev_guide.bootstrap']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -630,7 +630,6 @@ var KEYWORD_PRIORITY = {
|
|||
'.angular.module': 8,
|
||||
'.angular.mock': 9,
|
||||
'.angular.module.ng.$filter': 7,
|
||||
'.angular.module.ng.$filter': 7,
|
||||
'.angular.module.ng.$rootScope.Scope': 7,
|
||||
'.angular.module.ng': 7,
|
||||
'.angular.mock': 8,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ angular.module('ngdocs.directives', [], function($compileProvider) {
|
|||
return {
|
||||
terminal: true,
|
||||
compile: function(element, attrs) {
|
||||
var module = element.attr('module') || '';
|
||||
var module = attrs.module;
|
||||
|
||||
//jQuery find() methods in this widget contain primitive selectors on purpose so that we can use
|
||||
//jqlite instead. jqlite's find() method currently supports onlt getElementsByTagName!
|
||||
|
|
@ -86,6 +86,17 @@ angular.module('ngdocs.directives', [], function($compileProvider) {
|
|||
function($provide) {
|
||||
$provide.value('$browser', $browser);
|
||||
$provide.value('$location', $location);
|
||||
$provide.decorator('$defer', function($rootScope, $delegate) {
|
||||
return angular.extend(function(fn, delay) {
|
||||
if (delay && delay > 500) {
|
||||
return setTimeout(function() {
|
||||
$rootScope.$apply(fn);
|
||||
}, delay);
|
||||
} else {
|
||||
return $delegate.apply(this, arguments);
|
||||
}
|
||||
}, $delegate);
|
||||
});
|
||||
}
|
||||
];
|
||||
module && modules.push(module);
|
||||
|
|
|
|||
|
|
@ -1,40 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name angular.directive
|
||||
* @description
|
||||
*
|
||||
* Angular directives create custom attributes for DOM elements. A directive can modify the
|
||||
* behavior of the element in which it is specified. Do not use directives to add elements to the
|
||||
* DOM; instead, use {@link angular.widget widgets} to add DOM elements.
|
||||
*
|
||||
* For more information about how Angular directives work, and to learn how to create your own
|
||||
* directives, see {@link guide/dev_guide.compiler.directives Understanding Angular Directives} in
|
||||
* the Angular Developer Guide.
|
||||
*
|
||||
* @param {string} name Directive identifier (case insensitive).
|
||||
* @param {function(string, Element)} compileFn Also called "template function" is a function called
|
||||
* during compilation of the template when the compiler comes across the directive being
|
||||
* registered. The string value of the element attribute representing the directive and
|
||||
* jQuery/jqLite wrapped DOM element are passed as arguments to this function.
|
||||
*
|
||||
* The `compileFn` function may return a linking function also called an instance function.
|
||||
* This function is called during the linking phase when a Scope is being associated with the
|
||||
* template or template clone (see repeater notes below). The signature of the linking function
|
||||
* is: `function(Element)` where Element is jQuery/jqLite wrapped DOM Element that is being
|
||||
* linked.
|
||||
*
|
||||
* The biggest differenciator between the compile and linking functions is how they are being called
|
||||
* when a directive is present within an {@link angular.widget.@ng:repeat ng:repeat}. In this case,
|
||||
* the compile function gets called once per occurence of the directive in the template. On the
|
||||
* other hand the linking function gets called once for each repeated clone of the template (times
|
||||
* number of occurences of the directive in the repeated template).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:init
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:init
|
||||
*
|
||||
* @description
|
||||
* The `ng:init` attribute specifies initialization tasks to be executed
|
||||
|
|
@ -70,7 +38,7 @@ var ngInitDirective = valueFn({
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:controller
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:controller
|
||||
*
|
||||
* @description
|
||||
* The `ng:controller` directive assigns behavior to a scope. This is a key aspect of how angular
|
||||
|
|
@ -183,7 +151,7 @@ var ngControllerDirective = ['$controller', '$window', function($controller, $wi
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:bind
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:bind
|
||||
*
|
||||
* @description
|
||||
* The `ng:bind` attribute tells Angular to replace the text content of the specified HTML element
|
||||
|
|
@ -248,7 +216,7 @@ var ngBindHtmlDirective = ['$sanitize', function($sanitize) {
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:bind-template
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:bind-template
|
||||
*
|
||||
* @description
|
||||
* The `ng:bind-template` attribute specifies that the element
|
||||
|
|
@ -305,7 +273,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:bind-attr
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:bind-attr
|
||||
*
|
||||
* @description
|
||||
* The `ng:bind-attr` attribute specifies that a
|
||||
|
|
@ -333,7 +301,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
|
|||
* During compilation, the template with attribute markup gets translated to the ng:bind-attr form
|
||||
* mentioned above.
|
||||
*
|
||||
* _Note_: You might want to consider using {@link angular.directive.ng:href ng:href} instead of
|
||||
* _Note_: You might want to consider using {@link angular.module.ng.$compileProvider.directive.ng:href ng:href} instead of
|
||||
* `href` if the binding is present in the main application template (`index.html`) and you want to
|
||||
* make sure that a user is not capable of clicking on raw/uncompiled link.
|
||||
*
|
||||
|
|
@ -399,7 +367,7 @@ var ngBindAttrDirective = ['$interpolate', function($interpolate) {
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:click
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:click
|
||||
*
|
||||
* @description
|
||||
* The ng:click allows you to specify custom behavior when
|
||||
|
|
@ -435,33 +403,133 @@ var ngBindAttrDirective = ['$interpolate', function($interpolate) {
|
|||
* TODO: maybe we should consider allowing users to control event propagation in the future.
|
||||
*/
|
||||
var ngEventDirectives = {};
|
||||
forEach('click dblclick mousedown mouseup mouseover mousemove'.split(' '), function(name) {
|
||||
var directiveName = camelCase('ng-' + name);
|
||||
ngEventDirectives[directiveName] = valueFn(function(scope, element, attr) {
|
||||
element.bind(lowercase(name), function(event) {
|
||||
scope.$apply(attr[directiveName]);
|
||||
event.stopPropagation();
|
||||
forEach(
|
||||
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave'.split(' '),
|
||||
function(name) {
|
||||
var directiveName = directiveNormalize('ng-' + name);
|
||||
ngEventDirectives[directiveName] = valueFn(function(scope, element, attr) {
|
||||
element.bind(lowercase(name), function(event) {
|
||||
scope.$apply(attr[directiveName]);
|
||||
event.stopPropagation();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:dblclick
|
||||
*
|
||||
* @description
|
||||
* The ng:dblclick allows you to specify custom behavior on dblclick event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* dblclick.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:dblclick
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:mousedown
|
||||
*
|
||||
* @description
|
||||
* The ng:dblclick allows you to specify custom behavior when
|
||||
* element is double-clicked.
|
||||
* The ng:mousedown allows you to specify custom behavior on mousedown event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* double-click.
|
||||
* mousedown.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:mouseup
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior on mouseup event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* mouseup.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:submit
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:mouseover
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior on mouseover event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* mouseover.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:mouseenter
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior on mouseenter event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* mouseenter.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:mouseleave
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior on mouseleave event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* mouseleave.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:mousemove
|
||||
*
|
||||
* @description
|
||||
* Specify custom behavior on mousemove event.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
|
||||
* mousemove.
|
||||
*
|
||||
* @example
|
||||
* See {@link angular.module.ng.$compileProvider.directive.ng:click ng:click}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:submit
|
||||
*
|
||||
* @description
|
||||
* Enables binding angular expressions to onsubmit events.
|
||||
|
|
@ -536,7 +604,7 @@ function classDirective(name, selector) {
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:class
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:class
|
||||
*
|
||||
* @description
|
||||
* The `ng:class` allows you to set CSS class on HTML element dynamically by databinding an
|
||||
|
|
@ -582,15 +650,15 @@ var ngClassDirective = classDirective('', true);
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:class-odd
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:class-odd
|
||||
*
|
||||
* @description
|
||||
* The `ng:class-odd` and `ng:class-even` works exactly as
|
||||
* {@link angular.directive.ng:class ng:class}, except it works in conjunction with `ng:repeat` and
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:class ng:class}, except it works in conjunction with `ng:repeat` and
|
||||
* takes affect only on odd (even) rows.
|
||||
*
|
||||
* This directive can be applied only within a scope of an
|
||||
* {@link angular.widget.@ng:repeat ng:repeat}.
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat}.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. The result
|
||||
|
|
@ -622,15 +690,15 @@ var ngClassOddDirective = classDirective('Odd', 0);
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:class-even
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:class-even
|
||||
*
|
||||
* @description
|
||||
* The `ng:class-odd` and `ng:class-even` works exactly as
|
||||
* {@link angular.directive.ng:class ng:class}, except it works in conjunction with `ng:repeat` and
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:class ng:class}, except it works in conjunction with `ng:repeat` and
|
||||
* takes affect only on odd (even) rows.
|
||||
*
|
||||
* This directive can be applied only within a scope of an
|
||||
* {@link angular.widget.@ng:repeat ng:repeat}.
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat}.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. The result
|
||||
|
|
@ -661,7 +729,7 @@ var ngClassEvenDirective = classDirective('Even', 1);
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:show
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:show
|
||||
*
|
||||
* @description
|
||||
* The `ng:show` and `ng:hide` directives show or hide a portion of the DOM tree (HTML)
|
||||
|
|
@ -700,7 +768,7 @@ var ngShowDirective = valueFn(function(scope, element, attr){
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:hide
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:hide
|
||||
*
|
||||
* @description
|
||||
* The `ng:hide` and `ng:show` directives hide or show a portion
|
||||
|
|
@ -739,7 +807,7 @@ var ngHideDirective = valueFn(function(scope, element, attr){
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:style
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:style
|
||||
*
|
||||
* @description
|
||||
* The ng:style allows you to set CSS style on an HTML element conditionally.
|
||||
|
|
@ -781,7 +849,7 @@ var ngStyleDirective = valueFn(function(scope, element, attr) {
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:cloak
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:cloak
|
||||
*
|
||||
* @description
|
||||
* The `ng:cloak` directive is used to prevent the Angular html template from being briefly
|
||||
|
|
@ -840,9 +908,9 @@ var ngCloakDirective = valueFn({
|
|||
});
|
||||
|
||||
function ngAttributeAliasDirective(propName, attrName) {
|
||||
ngAttributeAliasDirectives[camelCase('ng-' + attrName)] = ['$interpolate', function($interpolate) {
|
||||
ngAttributeAliasDirectives[directiveNormalize('ng-' + attrName)] = ['$interpolate', function($interpolate) {
|
||||
return function(scope, element, attr) {
|
||||
scope.$watch($interpolate(attr[camelCase('ng-' + attrName)]), function(value) {
|
||||
scope.$watch($interpolate(attr[directiveNormalize('ng-' + attrName)]), function(value) {
|
||||
attr.$set(attrName, value);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,22 +101,15 @@ function getStyle(element) {
|
|||
|
||||
|
||||
var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
|
||||
var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
|
||||
var MOZ_HACK_REGEXP = /^moz([A-Z])/;
|
||||
|
||||
/**
|
||||
* Converts all accepted directives format into proper directive name.
|
||||
* All of these will become 'myDirective':
|
||||
* my:DiRective
|
||||
* my-directive
|
||||
* x-my-directive
|
||||
* data-my:directive
|
||||
*
|
||||
* Converts snake_case to camelCase.
|
||||
* Also there is special case for Moz prefix starting with upper case letter.
|
||||
* @param name Name to normalize
|
||||
*/
|
||||
function camelCase(name) {
|
||||
return name.
|
||||
replace(PREFIX_REGEXP, '').
|
||||
replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
|
||||
return offset ? letter.toUpperCase() : letter;
|
||||
}).
|
||||
|
|
|
|||
|
|
@ -143,13 +143,25 @@ function setupModuleLoader(window) {
|
|||
* @ngdoc method
|
||||
* @name angular.Module#filter
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name filterr name
|
||||
* @param {string} name filter name
|
||||
* @param {Function} filterFactory Factory function for creating new instance of filter.
|
||||
* @description
|
||||
* See {@link angular.module.ng.$filterProvider#register $filterProvider.register()}.
|
||||
*/
|
||||
filter: invokeLater('$filterProvider', 'register'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#directive
|
||||
* @methodOf angular.Module
|
||||
* @param {string} name directive name
|
||||
* @param {Function} directiveFactory Factory function for creating new instance of
|
||||
* directives.
|
||||
* @description
|
||||
* See {@link angular.module.ng.$compileProvider#directive $compileProvider.directive()}.
|
||||
*/
|
||||
directive: invokeLater('$compileProvider', 'directive'),
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name angular.Module#config
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:href
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:href
|
||||
*
|
||||
* @description
|
||||
* Using <angular/> markup like {{hash}} in an href attribute makes
|
||||
|
|
@ -83,7 +83,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:src
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:src
|
||||
*
|
||||
* @description
|
||||
* Using <angular/> markup like `{{hash}}` in a `src` attribute doesn't
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:disabled
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:disabled
|
||||
*
|
||||
* @description
|
||||
*
|
||||
|
|
@ -146,7 +146,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:checked
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:checked
|
||||
*
|
||||
* @description
|
||||
* The HTML specs do not require browsers to preserve the special attributes such as checked.
|
||||
|
|
@ -175,7 +175,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:multiple
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:multiple
|
||||
*
|
||||
* @description
|
||||
* The HTML specs do not require browsers to preserve the special attributes such as multiple.
|
||||
|
|
@ -210,7 +210,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:readonly
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:readonly
|
||||
*
|
||||
* @description
|
||||
* The HTML specs do not require browsers to preserve the special attributes such as readonly.
|
||||
|
|
@ -239,7 +239,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:selected
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:selected
|
||||
*
|
||||
* @description
|
||||
* The HTML specs do not require browsers to preserve the special attributes such as selected.
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ angular.scenario.SpecRunner.prototype.addFuture = function(name, behavior, line)
|
|||
*/
|
||||
angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior, line) {
|
||||
var self = this;
|
||||
var NG = /\[ng\\\:/;
|
||||
return this.addFuture(name, function(done) {
|
||||
this.application.executeAction(function($window, $document) {
|
||||
|
||||
|
|
@ -117,6 +118,9 @@ angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior,
|
|||
selector = selector.replace('$' + (index + 1), value);
|
||||
});
|
||||
var result = $document.find(selector);
|
||||
if (selector.match(NG)) {
|
||||
result = result.add(selector.replace(NG, '[ng-'), $document);
|
||||
}
|
||||
if (!result.length) {
|
||||
throw {
|
||||
type: 'selector',
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@
|
|||
})
|
||||
});
|
||||
|
||||
function Ctrl() {
|
||||
this.name = 'Angular';
|
||||
this.html = 'Hello {{name}}';
|
||||
function Ctrl($scope) {
|
||||
$scope.name = 'Angular';
|
||||
$scope.html = 'Hello {{name}}';
|
||||
}
|
||||
</script>
|
||||
<div ng-controller="Ctrl">
|
||||
|
|
|
|||
|
|
@ -22,26 +22,27 @@
|
|||
* This example shows how one could write a widget which would enable data-binding on
|
||||
* `contenteditable` feature of HTML.
|
||||
*
|
||||
<doc:example>
|
||||
<doc:example module="formModule">
|
||||
<doc:source>
|
||||
<script>
|
||||
function EditorCntl($scope) {
|
||||
$scope.html = '<b>Hello</b> <i>World</i>!';
|
||||
$scope.htmlContent = '<b>Hello</b> <i>World</i>!';
|
||||
}
|
||||
|
||||
HTMLEditorWidget.$inject = ['$element', '$scope', 'htmlFilter'];
|
||||
function HTMLEditorWidget(element, scope, htmlFilter) {
|
||||
HTMLEditorWidget.$inject = ['$scope', '$element', '$sanitize'];
|
||||
function HTMLEditorWidget(scope, element, $sanitize) {
|
||||
scope.$parseModel = function() {
|
||||
// need to protect for script injection
|
||||
try {
|
||||
this.$viewValue = htmlFilter(this.$modelValue || '').get();
|
||||
scope.$viewValue = $sanitize(
|
||||
scope.$modelValue || '');
|
||||
if (this.$error.HTML) {
|
||||
// we were invalid, but now we are OK.
|
||||
this.$emit('$valid', 'HTML');
|
||||
scope.$emit('$valid', 'HTML');
|
||||
}
|
||||
} catch (e) {
|
||||
// if HTML not parsable invalidate form.
|
||||
this.$emit('$invalid', 'HTML');
|
||||
scope.$emit('$invalid', 'HTML');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +129,7 @@ function $FormFactoryProvider() {
|
|||
* Static method on `$formFactory` service.
|
||||
*
|
||||
* Retrieve the closest form for a given element or defaults to the `root` form. Used by the
|
||||
* {@link angular.widget.form form} element.
|
||||
* {@link angular.module.ng.$compileProvider.directive.form form} element.
|
||||
* @param {Element} element The element where the search for form should initiate.
|
||||
*/
|
||||
formFactory.forElement = function(element) {
|
||||
|
|
|
|||
|
|
@ -438,14 +438,14 @@ function $HttpProvider() {
|
|||
it('should make an xhr GET request', function() {
|
||||
element(':button:contains("Sample GET")').click();
|
||||
element(':button:contains("fetch")').click();
|
||||
expect(binding('status')).toBe('http status code: 200');
|
||||
expect(binding('data')).toBe('http response data: Hello, $http!\n');
|
||||
expect(binding('status')).toBe('200');
|
||||
expect(binding('data')).toBe('Hello, $http!\n');
|
||||
});
|
||||
|
||||
it('should make a JSONP request to angularjs.org', function() {
|
||||
element(':button:contains("Sample JSONP")').click();
|
||||
element(':button:contains("fetch")').click();
|
||||
expect(binding('status')).toBe('http status code: 200');
|
||||
expect(binding('status')).toBe('200');
|
||||
expect(binding('data')).toMatch(/Super Hero!/);
|
||||
});
|
||||
|
||||
|
|
@ -453,8 +453,8 @@ function $HttpProvider() {
|
|||
function() {
|
||||
element(':button:contains("Invalid JSONP")').click();
|
||||
element(':button:contains("fetch")').click();
|
||||
expect(binding('status')).toBe('http status code: 0');
|
||||
expect(binding('data')).toBe('http response data: Request failed');
|
||||
expect(binding('status')).toBe('0');
|
||||
expect(binding('data')).toBe('Request failed');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* Watches `$location.url()` and tries to map the path to an existing route
|
||||
* definition. It is used for deep-linking URLs to controllers and views (HTML partials).
|
||||
*
|
||||
* The `$route` service is typically used in conjunction with {@link angular.widget.ng:view ng:view}
|
||||
* The `$route` service is typically used in conjunction with {@link angular.module.ng.$compileProvider.directive.ng:view ng:view}
|
||||
* widget and the {@link angular.module.ng.$routeParams $routeParams} service.
|
||||
*
|
||||
* @example
|
||||
|
|
@ -150,8 +150,8 @@ function $RouteProvider(){
|
|||
* - `controller` – `{function()=}` – Controller fn that should be associated with newly
|
||||
* created scope.
|
||||
* - `template` – `{string=}` – path to an html template that should be used by
|
||||
* {@link angular.widget.ng:view ng:view} or
|
||||
* {@link angular.widget.ng:include ng:include} widgets.
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:view ng:view} or
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:include ng:include} widgets.
|
||||
* - `redirectTo` – {(string|function())=} – value to update
|
||||
* {@link angular.module.ng.$location $location} path with and trigger route redirection.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@
|
|||
<doc:example>
|
||||
<doc:source>
|
||||
<script>
|
||||
function Ctrl() {
|
||||
this.snippet =
|
||||
function Ctrl($scope) {
|
||||
$scope.snippet =
|
||||
'<p style="color:blue">an html\n' +
|
||||
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
||||
'snippet</p>';
|
||||
|
|
|
|||
|
|
@ -277,9 +277,10 @@ function $RootScopeProvider(){
|
|||
* `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 100.
|
||||
*
|
||||
* Usually you don't call `$digest()` directly in
|
||||
* {@link angular.directive.ng:controller controllers} or in {@link angular.directive directives}.
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:controller controllers} or in
|
||||
* {@link angular.module.ng.$compileProvider.directive directives}.
|
||||
* Instead a call to {@link angular.module.ng.$rootScope.Scope#$apply $apply()} (typically from within a
|
||||
* {@link angular.directive directive}) will force a `$digest()`.
|
||||
* {@link angular.module.ng.$compileProvider.directive directives}) will force a `$digest()`.
|
||||
*
|
||||
* If you want to be notified whenever `$digest()` is called,
|
||||
* you can register a `watchExpression` function with {@link angular.module.ng.$rootScope.Scope#$watch $watch()}
|
||||
|
|
@ -396,7 +397,7 @@ function $RootScopeProvider(){
|
|||
* The destructing scope emits an `$destroy` {@link angular.module.ng.$rootScope.Scope#$emit event}.
|
||||
*
|
||||
* The `$destroy()` is usually used by directives such as
|
||||
* {@link angular.widget.@ng:repeat ng:repeat} for managing the unrolling of the loop.
|
||||
* {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} for managing the unrolling of the loop.
|
||||
*
|
||||
*/
|
||||
$destroy: function() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.form
|
||||
* @name angular.module.ng.$compileProvider.directive.form
|
||||
*
|
||||
* @description
|
||||
* Angular widget that creates a form scope using the
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@ var HTML5_INPUTS_TYPES = makeMap(
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.input
|
||||
* @name angular.module.ng.$compileProvider.directive.input
|
||||
*
|
||||
* @description
|
||||
* HTML input element widget with angular data-binding. Input widget follows HTML5 input types
|
||||
|
|
@ -827,12 +827,12 @@ var inputDirective = ['$defer', '$formFactory', function($defer, $formFactory) {
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.textarea
|
||||
* @name angular.module.ng.$compileProvider.directive.textarea
|
||||
*
|
||||
* @description
|
||||
* HTML textarea element widget with angular data-binding. The data-binding and validation
|
||||
* properties of this element are exactly the same as those of the
|
||||
* {@link angular.widget.input input element}.
|
||||
* {@link angular.module.ng.$compileProvider.directive.input input element}.
|
||||
*
|
||||
* @param {string} type Widget types as defined by {@link angular.inputType}. If the
|
||||
* type is in the format of `@ScopeType` then `ScopeType` is loaded from the
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.select
|
||||
* @name angular.module.ng.$compileProvider.directive.select
|
||||
*
|
||||
* @description
|
||||
* HTML `SELECT` element with angular data-binding.
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
* Optionally `ng:options` attribute can be used to dynamically generate a list of `<option>`
|
||||
* elements for a `<select>` element using an array or an object obtained by evaluating the
|
||||
* `ng:options` expression.
|
||||
*
|
||||
*˝˝
|
||||
* When an item in the select menu is select, the value of array element or object property
|
||||
* represented by the selected option will be bound to the model identified by the `ng:model` attribute
|
||||
* of the parent select element.
|
||||
|
|
@ -22,13 +22,13 @@
|
|||
* option. See example below for demonstration.
|
||||
*
|
||||
* Note: `ng:options` provides iterator facility for `<option>` element which must be used instead
|
||||
* of {@link angular.widget.@ng:repeat ng:repeat}. `ng:repeat` is not suitable for use with
|
||||
* of {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat}. `ng:repeat` is not suitable for use with
|
||||
* `<option>` element because of the following reasons:
|
||||
*
|
||||
* * value attribute of the option element that we need to bind to requires a string, but the
|
||||
* source of data for the iteration might be in a form of array containing objects instead of
|
||||
* strings
|
||||
* * {@link angular.widget.@ng:repeat ng:repeat} unrolls after the select binds causing
|
||||
* * {@link angular.module.ng.$compileProvider.directive.ng:repeat ng:repeat} unrolls after the select binds causing
|
||||
* incorect rendering on most browsers.
|
||||
* * binding to a value not in list confuses most browsers.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,35 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name angular.widget
|
||||
* @description
|
||||
*
|
||||
* An angular widget can be either a custom attribute that modifies an existing DOM element or an
|
||||
* entirely new DOM element.
|
||||
*
|
||||
* During html compilation, widgets are processed after {@link angular.markup markup}, but before
|
||||
* {@link angular.directive directives}.
|
||||
*
|
||||
* Following is the list of built-in angular widgets:
|
||||
*
|
||||
* * {@link angular.widget.@ng:non-bindable ng:non-bindable} - Blocks angular from processing an
|
||||
* HTML element.
|
||||
* * {@link angular.widget.@ng:repeat ng:repeat} - Creates and manages a collection of cloned HTML
|
||||
* elements.
|
||||
* * {@link angular.inputType HTML input elements} - Standard HTML input elements data-bound by
|
||||
* angular.
|
||||
* * {@link angular.widget.ng:view ng:view} - Works with $route to "include" partial templates
|
||||
* * {@link angular.widget.ng:switch ng:switch} - Conditionally changes DOM structure
|
||||
* * {@link angular.widget.ng:include ng:include} - Includes an external HTML fragment
|
||||
*
|
||||
* For more information about angular widgets, see {@link guide/dev_guide.compiler.widgets
|
||||
* Understanding Angular Widgets} in the angular Developer Guide.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.ng:include
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:include
|
||||
*
|
||||
* @description
|
||||
* Fetches, compiles and includes an external HTML fragment.
|
||||
|
|
@ -146,7 +119,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.ng:switch
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:switch
|
||||
*
|
||||
* @description
|
||||
* Conditionally change the DOM structure.
|
||||
|
|
@ -290,7 +263,7 @@ var htmlAnchorDirective = valueFn({
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.@ng:repeat
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:repeat
|
||||
*
|
||||
* @description
|
||||
* The `ng:repeat` widget instantiates a template once per item from a collection. Each template
|
||||
|
|
@ -474,7 +447,7 @@ var ngRepeatDirective = ['$compile', function($compile) {
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.@ng:non-bindable
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:non-bindable
|
||||
*
|
||||
* @description
|
||||
* Sometimes it is necessary to write code which looks like bindings but which should be left alone
|
||||
|
|
@ -508,7 +481,7 @@ var ngNonBindableDirective = valueFn({ terminal: true });
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.ng:view
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:view
|
||||
*
|
||||
* @description
|
||||
* # Overview
|
||||
|
|
@ -517,7 +490,7 @@ var ngNonBindableDirective = valueFn({ terminal: true });
|
|||
* Every time the current route changes, the included view changes with it according to the
|
||||
* configuration of the `$route` service.
|
||||
*
|
||||
* This widget provides functionality similar to {@link angular.widget.ng:include ng:include} when
|
||||
* This widget provides functionality similar to {@link angular.module.ng.$compileProvider.directive.ng:include ng:include} when
|
||||
* used like this:
|
||||
*
|
||||
* <ng:include src="$route.current.template" scope="$route.current.scope"></ng:include>
|
||||
|
|
@ -617,7 +590,7 @@ var ngViewDirective = ['$http', '$templateCache', '$route', '$anchorScroll', '$c
|
|||
|
||||
/**
|
||||
* @ngdoc widget
|
||||
* @name angular.widget.ng:pluralize
|
||||
* @name angular.module.ng.$compileProvider.directive.ng:pluralize
|
||||
*
|
||||
* @description
|
||||
* # Overview
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ describe('module loader', function() {
|
|||
factory('fk', 'fv').
|
||||
value('k', 'v').
|
||||
filter('f', 'ff').
|
||||
directive('d', 'dd').
|
||||
config('init2').
|
||||
run('runBlock')).toBe(myModule);
|
||||
|
||||
|
|
@ -46,6 +47,7 @@ describe('module loader', function() {
|
|||
['$provide', 'factory', ['fk', 'fv'] ],
|
||||
['$provide', 'value', ['k', 'v'] ],
|
||||
['$filterProvider', 'register', ['f', 'ff'] ],
|
||||
['$compileProvider', 'directive', ['d', 'dd'] ],
|
||||
['$injector', 'invoke', ['init2'] ]
|
||||
]);
|
||||
expect(myModule._runBlocks).toEqual(['runBlock']);
|
||||
|
|
|
|||
|
|
@ -543,6 +543,13 @@ describe("angular.scenario.dsl", function() {
|
|||
expect(_jQuery('input[ng\\:model="test.input"]').val()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should change value in text input in dash form', function() {
|
||||
doc.append('<input ng-model="test.input" value="something">');
|
||||
var chain = $root.dsl.input('test.input');
|
||||
chain.enter('foo');
|
||||
expect(_jQuery('input[ng-model="test.input"]').val()).toEqual('foo');
|
||||
});
|
||||
|
||||
it('should return error if no input exists', function() {
|
||||
var chain = $root.dsl.input('test.input');
|
||||
chain.enter('foo');
|
||||
|
|
|
|||
Loading…
Reference in a new issue