mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
f2beef5 squash: run on build_only
This commit is contained in:
+47
@@ -0,0 +1,47 @@
|
||||
.DS_STORE
|
||||
|
||||
# Don’t commit the following directories created by pub.
|
||||
packages
|
||||
pubspec.lock
|
||||
.pub
|
||||
.packages
|
||||
|
||||
/dist/
|
||||
.buildlog
|
||||
node_modules
|
||||
bower_components
|
||||
|
||||
# Or broccoli working directory
|
||||
tmp
|
||||
|
||||
# Or the files created by dart2js.
|
||||
*.dart.js
|
||||
*.dart.precompiled.js
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
|
||||
# Or type definitions we mirror from github
|
||||
**/typings/**/*.d.ts
|
||||
**/typings/tsd.cached.json
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
.c9
|
||||
.idea/
|
||||
.settings/
|
||||
*.swo
|
||||
modules/.settings
|
||||
.vscode
|
||||
modules/.vscode
|
||||
|
||||
# Don't check in secret files
|
||||
*secret.js
|
||||
|
||||
# Ignore npm debug log
|
||||
npm-debug.log
|
||||
|
||||
/docs/bower_components/
|
||||
|
||||
# build-analytics
|
||||
.build-analytics
|
||||
@@ -0,0 +1,6 @@
|
||||
Angular2
|
||||
=========
|
||||
|
||||
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. This is the repository for the upcoming 2.0 version. If you're looking for the current official version of Angular you should go to [angular/angular.js](https://github.com/angular/angular.js)
|
||||
|
||||
License: Apache MIT 2.0
|
||||
@@ -0,0 +1,15 @@
|
||||
Angular2
|
||||
=========
|
||||
|
||||
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. This is the repository for the upcoming 2.0 version. If you're looking for the current official version of Angular you should go to [angular/angular.js](https://github.com/angular/angular.js)
|
||||
|
||||
This package contains different sources for different users:
|
||||
|
||||
1. The files located in the root folder can be consumed using CommonJS.
|
||||
2. The files under `/es6` are es6 compatible files that can be transpiled to
|
||||
es5 using any transpiler. This contains:
|
||||
* `dev/`: a development version that includes runtime type assertions
|
||||
* `prod/`: a production version that does not include runtime type assertions
|
||||
3. The files under `/ts` are the TypeScript source files.
|
||||
|
||||
License: Apache MIT 2.0
|
||||
@@ -0,0 +1 @@
|
||||
f2beef551567fd5d25d634c572938cbfd9207bcb
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
__export(require('./common'));
|
||||
__export(require('./core'));
|
||||
__export(require('./profile'));
|
||||
__export(require('./lifecycle_hooks'));
|
||||
__export(require('./bootstrap'));
|
||||
__export(require('./upgrade'));
|
||||
//# sourceMappingURL=angular2.js.map
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
var ng = require('./angular2');
|
||||
// the router and http should have their own SFX bundle
|
||||
// But currently the module arithmetic 'angular2/router_sfx - angular2/angular2',
|
||||
// is not support by system builder.
|
||||
var router = require('./router');
|
||||
var http = require('./http');
|
||||
var _prevNg = window.ng;
|
||||
window.ng = ng;
|
||||
window.ngRouter = router;
|
||||
window.ngHttp = http;
|
||||
/**
|
||||
* Calling noConflict will restore window.angular to its pre-angular loading state
|
||||
* and return the angular module object.
|
||||
*/
|
||||
ng.noConflict = function () {
|
||||
window.ng = _prevNg;
|
||||
return ng;
|
||||
};
|
||||
//# sourceMappingURL=angular2_sfx.js.map
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
var animation_1 = require('./src/animate/animation');
|
||||
exports.Animation = animation_1.Animation;
|
||||
var animation_builder_1 = require('./src/animate/animation_builder');
|
||||
exports.AnimationBuilder = animation_builder_1.AnimationBuilder;
|
||||
var browser_details_1 = require('./src/animate/browser_details');
|
||||
exports.BrowserDetails = browser_details_1.BrowserDetails;
|
||||
var css_animation_builder_1 = require('./src/animate/css_animation_builder');
|
||||
exports.CssAnimationBuilder = css_animation_builder_1.CssAnimationBuilder;
|
||||
var css_animation_options_1 = require('./src/animate/css_animation_options');
|
||||
exports.CssAnimationOptions = css_animation_options_1.CssAnimationOptions;
|
||||
//# sourceMappingURL=animate.js.map
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This file is only used for dart applications and for internal examples
|
||||
* that compile with both JavaScript and Dart.
|
||||
*/
|
||||
var bootstrap_1 = require('angular2/src/core/bootstrap');
|
||||
exports.bootstrap = bootstrap_1.bootstrap;
|
||||
//# sourceMappingURL=bootstrap.js.map
|
||||
@@ -0,0 +1,8 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
__export(require('./src/common/pipes'));
|
||||
__export(require('./src/common/directives'));
|
||||
__export(require('./src/common/forms'));
|
||||
__export(require('./src/common/common_directives'));
|
||||
//# sourceMappingURL=common.js.map
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Starting point to import all compiler APIs.
|
||||
*/
|
||||
__export(require('./src/compiler/url_resolver'));
|
||||
__export(require('./src/compiler/xhr'));
|
||||
//# sourceMappingURL=compiler.js.map
|
||||
@@ -0,0 +1,28 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Starting point to import all public core APIs.
|
||||
*/
|
||||
__export(require('./src/core/metadata'));
|
||||
__export(require('./src/core/util'));
|
||||
__export(require('./src/core/di'));
|
||||
__export(require('./src/common/pipes'));
|
||||
__export(require('./src/facade/facade'));
|
||||
__export(require('./src/core/application'));
|
||||
__export(require('./src/core/bootstrap'));
|
||||
__export(require('./src/core/services'));
|
||||
__export(require('./src/core/linker'));
|
||||
var application_ref_1 = require('./src/core/application_ref');
|
||||
exports.ApplicationRef = application_ref_1.ApplicationRef;
|
||||
__export(require('./src/core/zone'));
|
||||
__export(require('./src/core/render'));
|
||||
__export(require('./src/common/directives'));
|
||||
__export(require('./src/common/forms'));
|
||||
__export(require('./src/core/debug'));
|
||||
__export(require('./src/core/change_detection'));
|
||||
__export(require('./src/core/ambient'));
|
||||
__export(require('./src/core/dev_mode'));
|
||||
//# sourceMappingURL=core.js.map
|
||||
@@ -0,0 +1,10 @@
|
||||
@name Change Detection
|
||||
@description
|
||||
# Change Detection
|
||||
|
||||
* Mechanisms by which changes are detected in the model
|
||||
* DAG
|
||||
* Order of evaluation
|
||||
* Pure Functions
|
||||
* `onChange` method
|
||||
* Parser
|
||||
@@ -0,0 +1,7 @@
|
||||
# Expressions
|
||||
|
||||
## Binding Semantics
|
||||
|
||||
### Formatters
|
||||
|
||||
## Statement Semantics
|
||||
@@ -0,0 +1,3 @@
|
||||
# Record
|
||||
|
||||
## RecordRange
|
||||
@@ -0,0 +1,3 @@
|
||||
# Overview
|
||||
|
||||
* High level description of all of the components.
|
||||
@@ -0,0 +1,610 @@
|
||||
# Templates
|
||||
|
||||
Templates are markup which is added to HTML to declaratively describe how the application model should be
|
||||
projected to DOM as well as which DOM events should invoke which methods on the controller. Templates contain
|
||||
syntaxes which are core to Angular and allows for data-binding, event-binding, template-instantiation.
|
||||
|
||||
The design of the template syntax has these properties:
|
||||
|
||||
|
||||
* All data-binding expressions are easily identifiable. (i.e. there is never an ambiguity whether the value should be
|
||||
interpreted as string literal or as an expression.)
|
||||
* All events and their statements are easily identifiable.
|
||||
* All places of DOM instantiation are easily identifiable.
|
||||
* All places of variable declaration are easily identifiable.
|
||||
|
||||
The above properties guarantee that the templates are easy to parse by tools (such as IDEs) and reason about by people.
|
||||
At no point is it necessary to understand which directives are active or what their semantics are in order to reason
|
||||
about the template runtime characteristics.
|
||||
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
Below is a summary of the kinds of syntaxes which Angular templating supports. The syntaxes are explained in more
|
||||
detail in the following sections.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th><th>Short</th><th>Canonical</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Text Interpolation</th>
|
||||
<td>
|
||||
<pre>
|
||||
<div>{{exp}}</div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
<div>
|
||||
Hello {{name}}!
|
||||
<br>
|
||||
Goodbye {{name}}!
|
||||
</div>
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
<div [text|index]="exp"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
<div
|
||||
[text|0]=" 'Hello' + stringify(name) + '!' "
|
||||
[text|2]=" 'Goodbye' + stringify(name) + '!' ">
|
||||
<b>x</b>
|
||||
</div>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Property Interpolation</th>
|
||||
<td>
|
||||
<pre>
|
||||
<div name="{{exp}}"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<div class="{{selected}}"></div>
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
<div [name]="stringify(exp)"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<div [title]="stringify(selected)"></div>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Property binding</th>
|
||||
<td>
|
||||
<pre>
|
||||
<div [prop]="exp"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<div [hidden]="true"></div>
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
<div bind-prop="exp"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<div bind-hidden="true"></div>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Event binding (non-bubbling)</th>
|
||||
<td>
|
||||
<pre>
|
||||
<div (event)="statement"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<div (click)="doX()"></div>
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
<div on-event="statement"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<video #player>
|
||||
<button (click)="player.play()">play</button>
|
||||
</video>
|
||||
</pre>
|
||||
|
||||
Or:
|
||||
|
||||
<pre>
|
||||
<div def="symbol"></div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<video def="player">
|
||||
<button on-click="player.play()">play</button>
|
||||
</video>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Inline Template</th>
|
||||
<td>
|
||||
<pre>
|
||||
<div template="...">...</div>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<ul>
|
||||
<li template="for: #item of items">
|
||||
{{item}}
|
||||
</li>
|
||||
</ul>
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
<template>...</template>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
<pre>
|
||||
<ul>
|
||||
<template def-for:"item"
|
||||
bind-for-in="items">
|
||||
<li>
|
||||
{{item}}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Explicit Template</th>
|
||||
<td>
|
||||
<pre>
|
||||
<template>...</template>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<template #for="item"
|
||||
[for-in]="items">
|
||||
_some_content_to_repeat_
|
||||
</template>
|
||||
</pre>
|
||||
</td>
|
||||
<td>
|
||||
<pre>
|
||||
<template>...</template>
|
||||
</pre>
|
||||
|
||||
Example:
|
||||
|
||||
<pre>
|
||||
<template def-for="item"
|
||||
bind-for-in="items">
|
||||
_some_content_to_repeat_
|
||||
</template>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
## Property Binding
|
||||
|
||||
Binding application model data to the UI is the most common kind of bindings in an Angular application. The bindings
|
||||
are always in the form of `property-name` which is assigned an `expression`. The generic form is:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Short form</th>
|
||||
<td><pre><some-element [some-property]="expression"></pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Canonical form</th>
|
||||
<td><pre><some-element bind-some-property="expression"></pre></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
Where:
|
||||
* `some-element` can be any existing DOM element.
|
||||
* `some-property` (escaped with `[]` or `bind-`) is the name of the property on `some-element`. In this case the
|
||||
dash-case is converted into camel-case `someProperty`.
|
||||
* `expression` is a valid expression (as defined in section below).
|
||||
|
||||
Example:
|
||||
```
|
||||
<div [title]="user.firstName">
|
||||
```
|
||||
|
||||
In the above example the `title` property of the `div` element will be updated whenever the `user.firstName` changes
|
||||
its value.
|
||||
|
||||
Key points:
|
||||
* The binding is to the element property not the element attribute.
|
||||
* To prevent custom element from accidentally reading the literal `expression` on the title element, the attribute name
|
||||
is escaped. In our case the `title` is escaped to `[title]` through the addition of square brackets `[]`.
|
||||
* A binding value (in this case `user.firstName`) will always be an expression, never a string literal.
|
||||
|
||||
NOTE: Unlike Angular v1, Angular v2 binds to properties of elements rather than attributes of elements. This is
|
||||
done to better support custom elements, and to allow binding for values other than strings.
|
||||
|
||||
NOTE: Some editors/server side pre-processors may have trouble generating `[]` around the attribute name. For this
|
||||
reason Angular also supports a canonical version which is prefixed using `bind-`.
|
||||
|
||||
|
||||
|
||||
### String Interpolation
|
||||
|
||||
Property bindings are the only data bindings which Angular supports, but for convenience Angular supports an interpolation
|
||||
syntax which is just a short hand for the data binding syntax.
|
||||
|
||||
```
|
||||
<span>Hello {{name}}!</span>
|
||||
```
|
||||
|
||||
is a short hand for:
|
||||
|
||||
```
|
||||
<span [text|0]=" 'Hello ' + stringify(name) + '!' "></span>
|
||||
```
|
||||
|
||||
The above says to bind the `'Hello ' + stringify(name) + '!'` expression to the zero-th child of the `span`'s `text`
|
||||
property. The index is necessary in case there are more than one text nodes, or if the text node we wish to bind to
|
||||
is not the first one.
|
||||
|
||||
Similarly the same rules apply to interpolation inside attributes.
|
||||
|
||||
```
|
||||
<span title="Hello {{name}}!"></span>
|
||||
```
|
||||
|
||||
is a short hand for:
|
||||
|
||||
```
|
||||
<span [title]=" 'Hello ' + stringify(name) + '!' "></span>
|
||||
```
|
||||
|
||||
NOTE: `stringify()` is a built in implicit function which converts its argument to a string representation, while
|
||||
keeping `null` and `undefined` as empty strings.
|
||||
|
||||
|
||||
|
||||
|
||||
## Local Variables
|
||||
|
||||
|
||||
|
||||
|
||||
## Inline Templates
|
||||
|
||||
Data binding allows updating the DOM's properties, but it does not allow for changing of the DOM structure. To change
|
||||
DOM structure we need the ability to define child templates, and then instantiate these templates into Views. The
|
||||
Views than can be inserted and removed as needed to change the DOM structure.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Short form</th>
|
||||
<td>
|
||||
<pre>
|
||||
parent template
|
||||
<element>
|
||||
<some-element template="instantiating-directive-microsyntax">child template</some-element>
|
||||
</element>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Canonical form</th>
|
||||
<td>
|
||||
<pre>
|
||||
parent template
|
||||
<element>
|
||||
<template instantiating-directive-bindings>
|
||||
<some-element>child template</some-element>
|
||||
</template>
|
||||
</element>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Where:
|
||||
* `template` defines a child template and designates the anchor where Views (instances of the template) will be
|
||||
inserted. The template can be defined implicitly with `template` attribute, which turns the current element into
|
||||
a template, or explicitly with `<template>` element. Explicit declaration is longer, but it allows for having
|
||||
templates which have more than one root DOM node.
|
||||
* `viewport` is required for templates. The directive is responsible for deciding when
|
||||
and in which order should child views be inserted into this location. Such a directive usually has one or
|
||||
more bindings and can be represented as either `viewport-directive-bindings` or
|
||||
`viewport-directive-microsyntax` on `template` element or attribute. See template microsyntax for more details.
|
||||
|
||||
|
||||
Example of conditionally included template:
|
||||
|
||||
```
|
||||
Hello {{user}}!
|
||||
<div template="ng-if: isAdministrator">
|
||||
...administrator menu here...
|
||||
</div>
|
||||
```
|
||||
|
||||
In the above example the `ng-if` directive determines whether the child view (an instance of the child template) should be
|
||||
inserted into the root view. The `ng-if` makes this decision based on if the `isAdministrator` binding is true.
|
||||
|
||||
The above example is in the short form, for better clarity let's rewrite it in the canonical form, which is functionally
|
||||
identical.
|
||||
|
||||
```
|
||||
Hello {{user}}!
|
||||
<template [ng-if]="isAdministrator">
|
||||
<div>
|
||||
...administrator menu here...
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
||||
### Template Microsyntax
|
||||
|
||||
Often times it is necessary to encode a lot of different bindings into a template to control how the instantiation
|
||||
of the templates occurs. One such example is `ng-for`.
|
||||
|
||||
```
|
||||
<form #foo=form>
|
||||
</form>
|
||||
<ul>
|
||||
<template [ng-for] #person [ng-for-of]="people" #i="index">
|
||||
<li>{{i}}. {{person}}<li>
|
||||
</template>
|
||||
</ul>
|
||||
```
|
||||
|
||||
Where:
|
||||
* `[ng-for]` triggers the for directive.
|
||||
* `#person` exports the implicit `ng-for` item.
|
||||
* `[ng-for-of]="people"` binds an iterable object to the `ng-for` controller.
|
||||
* `#i=index` exports item index as `i`.
|
||||
|
||||
The above example is explicit but quite wordy. For this reason in most situations a short hand version of the
|
||||
syntax is preferable.
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li template="ng-for; #person; of=people; #i=index;">{{i}}. {{person}}<li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
Notice how each key value pair is translated to a `key=value;` statement in the `template` attribute. This makes the
|
||||
repeat syntax a much shorter, but we can do better. Turns out that most punctuation is optional in the short version
|
||||
which allows us to further shorten the text.
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li template="ng-for #person of people #i=index">{{i}}. {{person}}<li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
We can also optionally use `var` instead of `#` and add `:` to `for` which creates the following recommended
|
||||
microsyntax for `ng-for`.
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li template="ng-for: var person of people; var i=index">{{i}}. {{person}}<li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
Finally, we can move the `ng-for` keyword to the left hand side and prefix it with `*` as so:
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li *ng-for="var person of people; var i=index">{{i}}. {{person}}<li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
The format is intentionally defined freely, so that developers of directives can build an expressive microsyntax for
|
||||
their directives. The following code describes a more formal definition.
|
||||
|
||||
```
|
||||
expression: ... // as defined in Expressions section
|
||||
local: [a-zA-Z][a-zA-Z0-9]* // exported variable name available for binding
|
||||
internal: [a-zA-Z][a-zA-Z0-9]* // internal variable name which the directive exports.
|
||||
key: [a-z][-|_|a-z0-9]]* // key which maps to attribute name
|
||||
keyExpression: key[:|=]?expression // binding which maps an expression to a property
|
||||
varExport: [#|var]local(=internal)? // binding which exports a local variable from a directive
|
||||
microsyntax: ([[key|keyExpression|varExport][;|,]?)*
|
||||
```
|
||||
|
||||
Where
|
||||
* `expression` is an Angular expression as defined in section: Expressions.
|
||||
* `local` is a local identifier for local variables.
|
||||
* `internal` is an internal variable which the directive exports for binding.
|
||||
* `key` is an attribute name usually only used to trigger a specific directive.
|
||||
* `keyExpression` is an property name to which the expression will be bound to.
|
||||
* `varExport` allows exporting of directive internal state as variables for further binding. If no `internal` name
|
||||
is specified, the exporting is to an implicit variable.
|
||||
* `microsyntax` allows you to build a simple microsyntax which can still clearly identify which expressions bind to
|
||||
which properties as well as which variables are exported for binding.
|
||||
|
||||
|
||||
NOTE: the `template` attribute must be present to make it clear to the user that a sub-template is being created. This
|
||||
goes along with the philosophy that the developer should be able to reason about the template without understanding the
|
||||
semantics of the instantiator directive.
|
||||
|
||||
|
||||
|
||||
|
||||
## Binding Events
|
||||
|
||||
Binding events allows wiring events from DOM (or other components) to the Angular controller.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Short form</th>
|
||||
<td><pre><some-element (some-event)="statement"></pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Canonical form</th>
|
||||
<td><pre><some-element on-some-event="statement"></pre></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Where:
|
||||
* `some-element` Any element which can generate DOM events (or has an angular directive which generates the event).
|
||||
* `some-event` (escaped with `()` or `on-`) is the name of the event `some-event`. In this case the
|
||||
dash-case is converted into camel-case `someEvent`.
|
||||
* `statement` is a valid statement (as defined in section below).
|
||||
If the execution of the statement returns `false`, then `preventDefault`is applied on the DOM event.
|
||||
|
||||
Angular listens to bubbled DOM events (as in the case of clicking on any child), as shown below:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Short form</th>
|
||||
<td><pre><some-element (some-event)="statement"></pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Canonical form</th>
|
||||
<td><pre><some-element on-some-event="statement"></pre></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
Example:
|
||||
```
|
||||
@Component(...)
|
||||
class Example {
|
||||
submit() {
|
||||
// do something when button is clicked
|
||||
}
|
||||
}
|
||||
|
||||
<button (click)="submit()">Submit</button>
|
||||
```
|
||||
|
||||
In the above example, when clicking on the submit button angular will invoke the `submit` method on the surrounding
|
||||
component's controller.
|
||||
|
||||
|
||||
NOTE: Unlike Angular v1, Angular v2 treats event bindings as core constructs not as directives. This means that there
|
||||
is no need to create an event directive for each kind of event. This makes it possible for Angular v2 to easily
|
||||
bind to custom events of Custom Elements, whose event names are not known ahead of time.
|
||||
|
||||
|
||||
|
||||
|
||||
## Expressions, Statements and Formatters
|
||||
|
||||
Angular templates contain expressions for binding to data and statements for binding to events. Expressions and statements
|
||||
have different semantics.
|
||||
|
||||
|
||||
### Expressions
|
||||
|
||||
Expressions can be used to bind to properties only. Expressions represent how data should be projected to the View.
|
||||
Expressions should not have any side effect and should be idempotent. Examples of where expressions can be used in
|
||||
Angular are:
|
||||
```
|
||||
<div title="{{expression}}">{{expression}}</div>
|
||||
<div [title]="expression">...</div>
|
||||
<div bind-title="expression">...</div>
|
||||
<div template="ng-if: expression">...</div>
|
||||
```
|
||||
|
||||
Expressions are simplified version of expression in the language in which you are writing your application. (i.e.
|
||||
expressions follow JS syntax and semantics in JS and Dart syntax and semantics in Dart). Unlike expressions in the
|
||||
language, binding expressions behave differently in following ways:
|
||||
|
||||
* *Must be defined*: Unlike Angular v1, Angular v2 will throw an error on dereferencing fields which are not defined.
|
||||
For example: `user.name` will throw an error if `user` is defined but it does not have `name` property. If the `name`
|
||||
property is not known, it must be declared and set to some value such as empty string, `null` (or `undefined` in JS).
|
||||
This is done to allow early detection of errors in the templates.
|
||||
* *Safe dereference*: Expressions `user.name` where `user` is null will throw `NullPointerException` in the language.
|
||||
In contrast Angular will silently ignore `null` on `user`. This is done because Views often have to wait for the data
|
||||
to arrive from the backend and many fields will be `null` until the data arrives. Safe dereference is so common in the
|
||||
Views that we have made it the default.
|
||||
* *Single expression*: An expression must be a single statement. (i.e. no `;`)
|
||||
* *No assignments*: Binding expressions can not contain assignments.
|
||||
* *No keywords*: Binding expressions can not contain keywords such as: `var`, `if`, and so on.
|
||||
* *Formatters*: Angular expressions can be piped through formatters to further transform the binding value.
|
||||
(See: Formatters)
|
||||
|
||||
Examples of some expressions and their behavior:
|
||||
|
||||
Given:
|
||||
```
|
||||
class Greeter {
|
||||
name:string;
|
||||
}
|
||||
```
|
||||
|
||||
* `name` : Will result in the value of the `name` property on the `Greeter` class.
|
||||
* `name.length`: Will result in either the length of the `name` string or `undefined` (`null` in Dart) if `name`
|
||||
property is `null` or `undefined`. Example of: safe dereference.
|
||||
* `foo`: Will throw an error because `foo` is not declared on the `Greeter` class. Example of: Must be defined
|
||||
* `name=1`: Not allowed because of assignment.
|
||||
* `name; name.length`: Not allowed because of multiple statements.
|
||||
|
||||
|
||||
|
||||
### Statements
|
||||
|
||||
Statements can be used to bind to events only. Statements represent actions to trigger as a response to an event.
|
||||
Examples of where statements can be used in Angular are:
|
||||
```
|
||||
<div (click)="statements">...</div>
|
||||
<div on-click="statements">...</div>
|
||||
```
|
||||
|
||||
Statements are similar to statements in the language in which you are writing your application. (i.e.
|
||||
statements follow JS syntax and semantics in JS and Dart syntax and semantics in Dart). Unlike statements in the
|
||||
language, binding expressions behave differently in the following ways:
|
||||
|
||||
* *Unsafe dereference*: Expressions `user.verify()` where `user` is `null` will throw `NullPointerException` in the
|
||||
language as well as in statements. (In contrast to Safe dereference in Angular expressions.) While Angular protects
|
||||
you from null dereferencing in expressions due to lazy loading of data, no such protection is required for statements,
|
||||
and doing so would make it harder to detect typos in statements.
|
||||
* *Multiple statements OK*: Statements can be composed from more than one statement. (i.e. no `doA(); doB()`)
|
||||
* *Assignments OK*: Event bindings can have side effects and hence assignments are allowed.
|
||||
* *No keywords*: Statements can not contain keywords such as: `var`, `if`, and so on.
|
||||
* *No Formatters*: Angular statements can not contain formatters. (Formatters are only useful for data binding)
|
||||
|
||||
## Further Reading
|
||||
|
||||
* [Template Syntax Constraints and Reasoning](https://docs.google.com/document/d/1HHy_zPLGqJj0bHMiWPzPCxn1pO5GlOYwmv-qGgl4f_s)
|
||||
@@ -0,0 +1,390 @@
|
||||
# Directives
|
||||
|
||||
Directives are classes which get instantiated as a response to a particular DOM structure. By controlling the DOM structure, what directives are imported, and their selectors, the developer can use the [composition pattern](http://en.wikipedia.org/wiki/Object_composition) to get a desirable application behavior.
|
||||
|
||||
Directives are the cornerstone of an Angular application. We use Directives to break complex problems into smaller more reusable components. Directives allow the developer to turn HTML into a DSL and then control the application assembly process.
|
||||
|
||||
Angular applications do not have a main method. Instead they have a root Component. Dependency Injection then assembles the directives into a working Angular application.
|
||||
|
||||
Directives with an encapsulated view and an optional injector are called *Components*.
|
||||
|
||||
|
||||
## CSS Selectors
|
||||
|
||||
Directives are instantiated whenever the CSS selector matches the DOM structure.
|
||||
|
||||
Angular supports these CSS selector constructs:
|
||||
* Element name: `name`
|
||||
* Attribute: `[attribute]`
|
||||
* Attribute has value: `[attribute=value]`
|
||||
* Attribute contains value: `[attribute*=value]`
|
||||
* Class: `.class`
|
||||
* AND operation: `name[attribute]`
|
||||
* OR operation: `name,.class`
|
||||
* NOT operation: `:not(.class)`
|
||||
|
||||
Angular does not support these (and any CSS selector which crosses element boundaries):
|
||||
* Descendant: `body div`
|
||||
* Direct descendant: `body > div`
|
||||
* Adjacent: `div + table`
|
||||
* Sibling: `div ~ table`
|
||||
* Wildcard: `*`
|
||||
* ID: `#id`
|
||||
* Pseudo selectors: `:pseudo` other than `:not`
|
||||
|
||||
|
||||
|
||||
Given this DOM:
|
||||
|
||||
```<input type="text" required class="primary">```
|
||||
|
||||
These CSS selectors will match:
|
||||
* `input`: Triggers whenever element name is `input`.
|
||||
* `[required]`: Triggers whenever element contains a required attribute.
|
||||
* `[type=text]`: Triggers whenever element contains attribute `type` whose value is `text`.
|
||||
* `.primary`: Triggers whenever element class contains `primary`.
|
||||
|
||||
CSS Selectors can be combined:
|
||||
* `input[type=text]`: Triggers on element name `input` which is of `type` `text`.
|
||||
* `input[type=text], textarea`: triggers on element name `input` which is of `type` `text` or element name `textarea`.
|
||||
|
||||
|
||||
|
||||
## Directives
|
||||
|
||||
The simplest kind of directive is a decorator. Directives are useful for encapsulating behavior.
|
||||
|
||||
* Multiple decorators can be placed on a single element.
|
||||
* Directives do not introduce new evaluation context.
|
||||
* Directives are registered through the `@Directive` meta-data annotation.
|
||||
|
||||
Here is a trivial example of a tooltip decorator. The directive will log a tooltip into the console on every time mouse enters a region:
|
||||
|
||||
```
|
||||
@Directive({
|
||||
selector: '[tooltip]', | CSS Selector which triggers the decorator
|
||||
properties: [ | List which properties need to be bound
|
||||
'text: tooltip' | - DOM element tooltip property should be
|
||||
], | mapped to the directive text property.
|
||||
host: { | List which events need to be mapped.
|
||||
'(mouseover)': 'show()' | - Invoke the show() method every time
|
||||
} | the mouseover event is fired.
|
||||
}) |
|
||||
class Form { | Directive controller class, instantiated
|
||||
| when CSS matches.
|
||||
text:string; | text property on the Directive Controller.
|
||||
|
|
||||
show() { | Show method which implements the show action.
|
||||
console.log(this.text); |
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Example of usage:
|
||||
|
||||
```<span tooltip="Tooltip text goes here.">Some text here.</span>```
|
||||
|
||||
The developer of an application can now freely use the `tooltip` attribute wherever the behavior is needed. The code above has taught the browser a new reusable and declarative behavior.
|
||||
|
||||
Notice that data binding will work with this decorator with no further effort as shown below.
|
||||
|
||||
```<span tooltip="Greetings {{user}}!">Some text here.</span>```
|
||||
|
||||
|
||||
|
||||
## Components
|
||||
|
||||
Component is a directive which uses shadow DOM to create encapsulate visual behavior. Components are typically used to create UI widgets or to break up the application into smaller components.
|
||||
|
||||
* Only one component can be present per DOM element.
|
||||
* Component's CSS selectors usually trigger on element names. (Best practice)
|
||||
* Component has its own shadow view which is attached to the element as a Shadow DOM.
|
||||
* Shadow view context is the component instance. (i.e. template expressions are evaluated against the component instance.)
|
||||
|
||||
>> TODO(misko): Configuring the injector
|
||||
|
||||
Example of a component:
|
||||
|
||||
```
|
||||
@Component({ | Component annotation
|
||||
selector: 'pane', | CSS selector on <pane> element
|
||||
properties: [ | List which property need to be bound
|
||||
'title', | - title mapped to component title
|
||||
'open' | - open attribute mapped to component's open property
|
||||
], |
|
||||
}) |
|
||||
@View({ | View annotation
|
||||
templateUrl: 'pane.html' | - URL of template HTML
|
||||
}) |
|
||||
class Pane { | Component controller class
|
||||
title:string; | - title property
|
||||
open:boolean;
|
||||
|
||||
constructor() {
|
||||
this.title = '';
|
||||
this.open = true;
|
||||
}
|
||||
|
||||
// Public API
|
||||
toggle() => this.open = !this.open;
|
||||
open() => this.open = true;
|
||||
close() => this.open = false;
|
||||
}
|
||||
```
|
||||
|
||||
`pane.html`:
|
||||
```
|
||||
<div class="outer">
|
||||
<h1>{{title}}</h1>
|
||||
<div class="inner" [hidden]="!open">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
`pane.css`:
|
||||
```
|
||||
.outer, .inner { border: 1px solid blue;}
|
||||
.h1 {background-color: blue;}
|
||||
```
|
||||
|
||||
Example of usage:
|
||||
```
|
||||
<pane #pane title="Example Title" open="true">
|
||||
Some text to wrap.
|
||||
</pane>
|
||||
<button (click)="pane.toggle()">toggle</button>
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Directives that use a ViewContainer
|
||||
|
||||
Directives that use a ViewContainer can control instantiation of child views which are then inserted into the DOM. (Examples are `ng-if` and `ng-for`.)
|
||||
|
||||
* Every `template` element creates a `ProtoView` which can be used to create Views via the ViewContainer.
|
||||
* The child views show up as siblings of the directive in the DOM.
|
||||
|
||||
>> TODO(misko): Relationship with Injection
|
||||
>> TODO(misko): Instantiator can not be injected into child Views
|
||||
|
||||
|
||||
```
|
||||
@Directive({
|
||||
selector: '[if]',
|
||||
properties: [
|
||||
'condition: if'
|
||||
]
|
||||
})
|
||||
export class If {
|
||||
viewContainer: ViewContainerRef;
|
||||
protoViewRef: ProtoViewRef;
|
||||
view: View;
|
||||
|
||||
constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) {
|
||||
this.viewContainer = viewContainer;
|
||||
this.protoViewRef = protoViewRef;
|
||||
this.view = null;
|
||||
}
|
||||
|
||||
set condition(value) {
|
||||
if (value) {
|
||||
if (this.view === null) {
|
||||
this.view = this.viewContainer.create(protoViewRef);
|
||||
}
|
||||
} else {
|
||||
if (this.view !== null) {
|
||||
this.viewContainer.remove(this.view);
|
||||
this.view = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Dependency Injection
|
||||
|
||||
Dependency Injection (DI) is a key aspect of directives. DI allows directives to be assembled into different [compositional](http://en.wikipedia.org/wiki/Object_composition) hierarchies. Angular encourages [composition over inheritance](http://en.wikipedia.org/wiki/Composition_over_inheritance) in the application design (but inheritance based approaches are still supported).
|
||||
|
||||
When Angular directives are instantiated, the directive can ask for other related directives to be injected into it. By assembling the directives in different order and subtypes the application behavior can be controlled. A good mental model is that the DOM structure controls the directive instantiation graph.
|
||||
|
||||
Directive instantiation is triggered by the directive CSS selector matching the DOM structure. In a directive's constructor, it can ask for other directives or application services. When asking for directives, the dependency is attempted to be located by its DOM hierarchy first, then if not found, by using the application level injector.
|
||||
|
||||
To better understand the kinds of injections which are supported in Angular we have broken them down into use case examples.
|
||||
|
||||
|
||||
### Injecting Services
|
||||
|
||||
Service injection is the most straight forward kind of injection which Angular supports. It involves a component configuring the `bindings` or `viewBindings` and then letting the directive ask for the configured service.
|
||||
|
||||
This example illustrates how to inject `MyService` into `House` directive.
|
||||
|
||||
|
||||
```
|
||||
class MyService {} | Assume a service which needs to be injected
|
||||
| into a directive.
|
||||
|
|
||||
@Component({ | Assume a top level application component which
|
||||
selector: 'my-app', | configures the services to be injected.
|
||||
viewBindings: [MyService] |
|
||||
}) |
|
||||
@View({ | Assume we have a template that needs to be
|
||||
templateUrl: 'my_app.html', | configured with directives to be injected.
|
||||
directives: [House] |
|
||||
}) |
|
||||
class MyApp {} |
|
||||
|
|
||||
@Directive({ | This is the directive into which we would like
|
||||
selector: '[house]' | to inject the MyService.
|
||||
}) |
|
||||
class House { |
|
||||
constructor(myService:MyService) { | Notice that in the constructor we can simply
|
||||
} | ask for MyService.
|
||||
} |
|
||||
|
||||
|
||||
```
|
||||
|
||||
Assume the following DOM structure for `my_app.html`:
|
||||
```
|
||||
<div house> | The house attribute triggers the creation of the House directive.
|
||||
</div> | This is equivalent to:
|
||||
| new House(injector.get(MyService));
|
||||
```
|
||||
|
||||
|
||||
### Injecting other Directives
|
||||
|
||||
Injecting other directives into directives follows a similar mechanism as injecting services into directives, but with added constraint of visibility governed by DOM structure.
|
||||
|
||||
There are five kinds of visibilities:
|
||||
|
||||
* (no annotation): Inject dependent directives only if they are on the current element.
|
||||
* `@SkipSelf()`: Inject a directive if it is at any element above the current element.
|
||||
* `@child`: Inject a list of direct children which match a given type. (Used with `Query`)
|
||||
* `@descendant`: Inject a list of any children which match a given type. (Used with `Query`)
|
||||
|
||||
NOTE: if the injection constraint can not be satisfied by the current visibility constraint, then it is forwarded to the normal injector which either provides a default value for the directive or throws an error.
|
||||
|
||||
Here is an example of the kinds of injections which can be achieved:
|
||||
|
||||
|
||||
```
|
||||
@Component({ |
|
||||
selector: 'my-app' |
|
||||
}) |
|
||||
@View({ |
|
||||
templateUrl: 'my_app.html', |
|
||||
directives: [Form, FieldSet, |
|
||||
Field, Primary] |
|
||||
}) |
|
||||
class MyApp {} |
|
||||
|
|
||||
@Directive({ selector: 'form' }) |
|
||||
class Form { |
|
||||
constructor( |
|
||||
@descendant sets:Query<FieldSet> |
|
||||
) { |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Directive({ selector: 'fieldset' }) |
|
||||
class FieldSet { |
|
||||
constructor( |
|
||||
@child sets:Query<Field> |
|
||||
) { ... } |
|
||||
} |
|
||||
|
|
||||
@Directive({ selector: 'field' }) |
|
||||
class Field { |
|
||||
constructor( |
|
||||
@SkipSelf() field:Form, |
|
||||
@SkipSelf() field:FieldSet, |
|
||||
) { ... } |
|
||||
} |
|
||||
|
|
||||
@Directive({ selector: '[primary]'}) |
|
||||
class Primary { |
|
||||
constructor(field:Field ) { ... } |
|
||||
} |
|
||||
```
|
||||
|
||||
Assume the following DOM structure for `my_app.html`:
|
||||
```
|
||||
<form> |
|
||||
<div> |
|
||||
<fieldset> |
|
||||
<field primary></field> |
|
||||
<field></field> |
|
||||
</fieldset> |
|
||||
</div> |
|
||||
</form> |
|
||||
```
|
||||
|
||||
#### Shadow DOM effects on Directive DI
|
||||
|
||||
Shadow DOM provides an encapsulation for components, so as a general rule it does not allow directive injections to cross the shadow DOM boundaries. To remedy this, declaratively specify the required component as an injectable.
|
||||
|
||||
```
|
||||
@Component({
|
||||
selector: '[kid]'
|
||||
})
|
||||
@View({
|
||||
templateUrl: 'kid.html',
|
||||
directives: []
|
||||
})
|
||||
class Kid {
|
||||
constructor(
|
||||
@SkipSelf() dad:Dad,
|
||||
@Optional() grandpa:Grandpa
|
||||
) {
|
||||
this.name = 'Billy';
|
||||
this.dad = dad.name;
|
||||
this.grandpa = grandpa.name;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: '[dad]'
|
||||
})
|
||||
@View({
|
||||
templateUrl: 'dad.html',
|
||||
directives: [Kid]
|
||||
})
|
||||
class Dad {
|
||||
constructor(@SkipSelf() dad:Grandpa) {
|
||||
this.name = 'Joe Jr';
|
||||
this.dad = dad.name;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: '[grandpa]',
|
||||
viewBindings: []
|
||||
})
|
||||
@View({
|
||||
templateUrl: 'grandpa.html',
|
||||
directives: [Dad]
|
||||
})
|
||||
class Grandpa {
|
||||
constructor() {
|
||||
this.name = 'Joe';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Assume the following DOM structure for `grandpa.html`: The Dad has access to the Grandpa.
|
||||
```
|
||||
Name: {{name}}: <br> Children: <div dad></div>
|
||||
```
|
||||
|
||||
Assume the following DOM structure for `dad.html`: Here the rendered Kid will also have access to Grandpa.
|
||||
```
|
||||
Name: {{name}}: <br> Dad: {{dad}} <br> Children: <div kid></div>
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
|
||||
* [Composition](http://en.wikipedia.org/wiki/Object_composition)
|
||||
* [Composition over Inheritance](http://en.wikipedia.org/wiki/Composition_over_inheritance)
|
||||
@@ -0,0 +1,27 @@
|
||||
# Pipes
|
||||
|
||||
Pipes can be appended on the end of the expressions to translate the value to a different format. Typically used
|
||||
to control the stringification of numbers, dates, and other data, but can also be used for ordering, mapping, and
|
||||
reducing arrays. Pipes can be chained.
|
||||
|
||||
NOTE: Pipes are known as filters in Angular v1.
|
||||
|
||||
Pipes syntax is:
|
||||
|
||||
```
|
||||
<div class="movie-copy">
|
||||
<p>
|
||||
{{ model.getValue('copy') | async | uppercase }}
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Starring</b>: {{ model.getValue('starring') | async }}
|
||||
</li>
|
||||
<li>
|
||||
<b>Genres</b>: {{ model.getValue('genres') | async }}
|
||||
</li>
|
||||
<ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Components
|
||||
|
||||
* Different kinds of injections and visibility
|
||||
* Shadow DOM usage
|
||||
*
|
||||
@@ -0,0 +1,21 @@
|
||||
# HTML Template Compilation
|
||||
|
||||
* Process by which a HTML template is converted to a ProtoView
|
||||
|
||||
1. DOM parse()
|
||||
2. Macro
|
||||
3.
|
||||
|
||||
# HTML Template
|
||||
|
||||
* https://docs.google.com/document/d/1HHy_zPLGqJj0bHMiWPzPCxn1pO5GlOYwmv-qGgl4f_s
|
||||
* https://docs.google.com/document/d/1kpuR512G1b0D8egl9245OHaG0cFh0ST0ekhD_g8sxtI
|
||||
* https://docs.google.com/document/d/1DuFQKElIq293FlhQHvAp__NfP1XV9r8femZFMigm4-k
|
||||
* Must understand without understanding directives
|
||||
* IDE support
|
||||
* local variables
|
||||
|
||||
|
||||
# Binding Philosophy
|
||||
|
||||
# Binding to Shadow DOM
|
||||
@@ -0,0 +1,246 @@
|
||||
# View
|
||||
|
||||
## Overview
|
||||
|
||||
This document explains the concept of a View.
|
||||
A View is a core primitive used by angular to render the DOM tree.
|
||||
A ViewContainer is location in a View which can accept child Views.
|
||||
Every ViewContainer has an associated ViewContainerRef than can contain any number of child Views.
|
||||
Views form a tree structure which mimics the DOM tree.
|
||||
|
||||
* View is a core rendering construct. A running application is just a collection of Views which are
|
||||
nested in a tree like structure. The View tree is a simplified version of the DOM tree. A View can
|
||||
have a single DOM Element or large DOM structures. The key is that the DOM tree in the View can
|
||||
not undergo structural changes (only property changes).
|
||||
* Views represent a running instance of a DOM View. This implies that while elements in a View
|
||||
can change properties, they can not change structurally. (Structural changes such as, adding or
|
||||
removing elements requires adding or removing child Views into ViewContainers).
|
||||
* View can have zero or more ViewContainers. A ViewContainer is a marker in the DOM which allows
|
||||
the insertion of child Views.
|
||||
* Views are created from a ProtoView. A ProtoView is a compiled DOM View which is efficient at
|
||||
creating Views.
|
||||
* View contains a context object. The context represents the object instance against which all
|
||||
expressions are evaluated.
|
||||
* View contains a ChangeDetector for looking for detecting changes to the model.
|
||||
* View contains ElementInjector for creating Directives.
|
||||
|
||||
## Simple View
|
||||
|
||||
Let's examine a simple View and all of its parts in detail.
|
||||
|
||||
Assume the following Component:
|
||||
|
||||
```
|
||||
class Greeter {
|
||||
greeting:string;
|
||||
|
||||
constructor() {
|
||||
this.greeting = 'Hello';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And assume following HTML View:
|
||||
|
||||
```
|
||||
<div>
|
||||
Your name:
|
||||
<input var="name" type="Text">
|
||||
<br>
|
||||
{{greeting}} {{name.value}}!
|
||||
</div>
|
||||
```
|
||||
|
||||
The above template is compiled by the Compiler to create a ProtoView. The ProtoView is then used to
|
||||
create an instance of the View. The instantiation process involves cloning the above template and
|
||||
locating all of the elements which contain bindings and finally instantiating the Directives
|
||||
associated with the template. (See compilation for more details.)
|
||||
|
||||
```
|
||||
<div> | viewA(greeter)
|
||||
Your name: | viewA(greeter)
|
||||
<input var="name" type="Text"> | viewA(greeter): local variable 'name'
|
||||
<br> | viewA(greeter)
|
||||
{{greeting}} {{name.value}}! | viewA(greeter): binding expression 'greeting' & 'name.value'
|
||||
</div> | viewA(greeter)
|
||||
```
|
||||
|
||||
The resulting View instance looks something like this (simplified pseudo code):
|
||||
```
|
||||
viewA = new View({
|
||||
template: ...,
|
||||
context: new Greeter(),
|
||||
localVars: ['name'],
|
||||
watchExp: ['greeting', 'name.value']
|
||||
});
|
||||
```
|
||||
|
||||
Note:
|
||||
* View uses instance of `Greeter` as the evaluation context.
|
||||
* View knows of local variables `name`.
|
||||
* View knows which expressions need to be watched.
|
||||
* View knows what needs to be updated if the watched expression changes.
|
||||
* All DOM elements are owned by single instance of the view.
|
||||
* The structure of the DOM can not change during runtime. To allow structural changes to the DOM we need
|
||||
to understand Composed View.
|
||||
|
||||
|
||||
## Composed View
|
||||
|
||||
An important part of an application is to be able to change the DOM structure to render data for the
|
||||
user. In Angular this is done by inserting child views into the ViewContainer.
|
||||
|
||||
Let's start with a View such as:
|
||||
|
||||
```
|
||||
<ul>
|
||||
<li template="ng-for: #person of people">{{person}}</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
During the compilation process the Compiler breaks the HTML template into these two ProtoViews:
|
||||
|
||||
```
|
||||
<li>{{person}}</li> | protoViewB(Locals)
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
<ul> | protoViewA(someContext)
|
||||
<template></template> | protoViewA(someContext): protoViewB
|
||||
</ul> | protoViewA(someContext)
|
||||
```
|
||||
|
||||
|
||||
The next step is to compose these two ProtoViews into an actual view which is rendered to the user.
|
||||
|
||||
*Step 1:* Instantiate `viewA`
|
||||
|
||||
```
|
||||
<ul> | viewA(someContext)
|
||||
<template></template> | viewA(someContext): new NgFor(new ViewContainer(protoViewB))
|
||||
</ul> | viewA(someContext)
|
||||
```
|
||||
|
||||
*Step2:* Instantiate `NgFor` directive which will receive the `ViewContainerRef`. (The ViewContainerRef
|
||||
has a reference to `protoViewA`).
|
||||
|
||||
|
||||
*Step3:* As the `NgFor` directive unrolls it asks the `ViewContainerRef` to instantiate `protoViewB` and insert
|
||||
it after the `ViewContainer` anchor. This is repeated for each `person` in `people`. Notice that
|
||||
|
||||
```
|
||||
<ul> | viewA(someContext)
|
||||
<template></template> | viewA(someContext): new NgFor(new ViewContainer(protoViewB))
|
||||
<li>{{person}}</li> | viewB0(locals0(someContext))
|
||||
<li>{{person}}</li> | viewB1(locals0(someContext))
|
||||
</ul> | viewA(someContext)
|
||||
```
|
||||
|
||||
*Step4:* All of the bindings in the child Views are updated. Notice that in the case of `NgFor`
|
||||
the evaluation context for the `viewB0` and `viewB1` are `locals0` and `locals1` respectively.
|
||||
Locals allow the introduction of new local variables visible only within the scope of the View, and
|
||||
delegate any unknown references to the parent context.
|
||||
|
||||
```
|
||||
<ul> | viewA
|
||||
<template></template> | viewA: new NgFor(new ViewContainer(protoViewB))
|
||||
<li>Alice</li> | viewB0
|
||||
<li>Bob</li> | viewB1
|
||||
</ul> | viewA
|
||||
```
|
||||
|
||||
Each View can have zero or more ViewContainers. By inserting and removing child Views to and from the
|
||||
ViewContainers, the application can mutate the DOM structure to any desirable state. A View may contain
|
||||
individual nodes or a complex DOM structure. The insertion points for the child Views, known as
|
||||
ViewContainers, contain a DOM element which acts as an anchor. The anchor is either a `template` or
|
||||
a `script` element depending on your browser. It is used to identify where the child Views will be
|
||||
inserted.
|
||||
|
||||
## Component Views
|
||||
|
||||
A View can also contain Components. Components contain Shadow DOM for encapsulating their internal
|
||||
rendering state. Unlike ViewContainers which can contain zero or more Views, the Component always contains
|
||||
exactly one Shadow View.
|
||||
|
||||
```
|
||||
<div> | viewA
|
||||
<my-component> | viewA
|
||||
#SHADOW_ROOT | (encapsulation boundary)
|
||||
<div> | viewB
|
||||
encapsulated rendering | viewB
|
||||
</div> | viewB
|
||||
</my-component> | viewA
|
||||
</div> | viewA
|
||||
```
|
||||
|
||||
## Evaluation Context
|
||||
|
||||
Each View acts as a context for evaluating its expressions. There are two kinds of contexts:
|
||||
|
||||
1. A component controller instance and
|
||||
2. a `Locals` context for introducing local variables into the View.
|
||||
|
||||
Let's assume following component:
|
||||
|
||||
```
|
||||
class Greeter {
|
||||
greeting:string;
|
||||
|
||||
constructor() {
|
||||
this.greeting = 'Hello';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And assume the following HTML View:
|
||||
|
||||
```
|
||||
<div> | viewA(greeter)
|
||||
Your name: | viewA(greeter)
|
||||
<input var="name" type="Text"> | viewA(greeter)
|
||||
<br> | viewA(greeter)
|
||||
{{greeting}} {{name.value}}! | viewA(greeter)
|
||||
</div> | viewA(greeter)
|
||||
```
|
||||
|
||||
The above UI is built using a single View, and hence a single context `greeter`. It can be expressed
|
||||
in this pseudo-code.
|
||||
|
||||
```
|
||||
var greeter = new Greeter();
|
||||
```
|
||||
|
||||
The View contains two bindings:
|
||||
|
||||
1. `greeting`: This is bound to the `greeting` property on the `Greeter` instance.
|
||||
2. `name.value`: This poses a problem. There is no `name` property on the `Greeter` instance. To solve
|
||||
this we wrap the `Greeter` instance in the `Local` instance like so:
|
||||
```
|
||||
var greeter = new Locals(new Greeter(), {name: ref_to_input_element })
|
||||
```
|
||||
|
||||
|
||||
By wrapping the `Greeter` instance into the `Locals` we allow the view to introduce variables which
|
||||
are in addition to the `Greeter` instance. During the resolution of the expressions we first check
|
||||
the locals, and then the `Greeter` instance.
|
||||
|
||||
|
||||
|
||||
## View LifeCycle (Hydration and Dehydration)
|
||||
|
||||
Views transition through a particular set of states:
|
||||
|
||||
1. View is created from the ProtoView.
|
||||
2. View can be attached to an existing ViewContainerRef.
|
||||
3. Upon attaching View to the ViewContainerRef the View needs to be hydrated. The hydration process
|
||||
involves instantiating all of the Directives associated with the current View.
|
||||
4. At this point the view is ready and renderable. Multiple changes can be delivered to the
|
||||
Directives from the ChangeDetection.
|
||||
5. At some point the View can be removed. At this point all of the directives are destroyed during
|
||||
the dehydration process and the view becomes inactive.
|
||||
6. The View has to wait until it is detached from the DOM. The delay in detaching could be caused
|
||||
because an animation is animating the view away.
|
||||
7. After the View is detached from the DOM it is ready to be reused. The view reuse allows the
|
||||
application to be faster in subsequent renderings.
|
||||
@@ -0,0 +1,108 @@
|
||||
# Zones
|
||||
|
||||
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for
|
||||
JavaScript. Zones are used to intercept all async operation callbacks in the browser. By intercepting async
|
||||
callbacks Angular can automatically execute the change detection at the end of the VM turn to update the application
|
||||
UI bindings. Zones means that in Angular v2 you don't have to remember to call `rootScope.$apply()` in your async call.
|
||||
|
||||
## Execution Context
|
||||
|
||||
```
|
||||
zone.inTheZone = false;
|
||||
|
||||
zone.fork().run(function () {
|
||||
zone.inTheZone = true;
|
||||
|
||||
setTimeout(function () {
|
||||
console.log('async in the zone: ' + zone.inTheZone);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
console.log('sync in the zone: ' + zone.inTheZone);
|
||||
```
|
||||
|
||||
The above will log:
|
||||
|
||||
```
|
||||
sync in the zone: false
|
||||
async in the zone: true
|
||||
```
|
||||
|
||||
In the above example the `zone` is a global-callback-local variable. To the `zone` we can attach arbitrary properties
|
||||
such as `inTheZone`. When we enter the zone, we get a new `zone` context (which inherits all properties from the
|
||||
parent zone), once we leave the zone, the previous `zone` variable is restored. The key part is that when a async
|
||||
callback is scheduled in the zone, as is the case with `setTimeout`, the current `zone` variable is captured and
|
||||
restored on the callback. This is why the output of the `inTheZone` property inside the callback of the `setTimeout`
|
||||
prints `true`.
|
||||
|
||||
|
||||
## Callback Interception
|
||||
|
||||
In addition to storing properties on the current `zone`, zones can also allow us to intercept all async callbacks
|
||||
and notify us before and after the callback executes.
|
||||
|
||||
```
|
||||
zone.fork({
|
||||
afterTask: function () {
|
||||
// do some cleanup
|
||||
}
|
||||
}).run(function () {
|
||||
// do stuff
|
||||
});
|
||||
```
|
||||
|
||||
The above example will execute the `afterTask` function not only after the `run` finishes, but also after any callback
|
||||
execution which was registered in the `run` block.
|
||||
|
||||
## Putting it all together in Angular
|
||||
|
||||
In Angular2 it is not necessary to notify Angular of changes manually after async callback, because a relevant
|
||||
async callbacks are intercepted. The question is how do we know which callbacks are Angular relevant?
|
||||
|
||||
// TODO(vicb): outdated, rework.
|
||||
|
||||
```
|
||||
/// Some other code running on page can do async operation
|
||||
document.addEventListener('mousemove', function () {
|
||||
console.log('Mouse moved.');
|
||||
});
|
||||
|
||||
var AngularZone = {
|
||||
afterTask: function () {
|
||||
console.log('ANGULAR AUTO-DIGEST!');
|
||||
}
|
||||
};
|
||||
|
||||
var ngZone = zone.fork(AngularZone);
|
||||
ngZone.run(function() {
|
||||
console.log('I aware of angular, I should cause digest.');
|
||||
document.addEventListener('click', function () {
|
||||
console.log('Mouse clicked.');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Will produce:
|
||||
|
||||
```
|
||||
I aware of angular, I should cause digest.
|
||||
ANGULAR AUTO-DIGEST!
|
||||
```
|
||||
|
||||
Moving the mouse will produce many:
|
||||
```
|
||||
Mouse moved.
|
||||
```
|
||||
|
||||
But clicking will produce:
|
||||
```
|
||||
Mouse clicked.
|
||||
ANGULAR AUTO-DIGEST!
|
||||
```
|
||||
|
||||
Notice how the place where the listener was registered will effect whether or not Angular will be notified of the
|
||||
async call and cause a change detection to run to update the UI.
|
||||
|
||||
Being able to globally intercept the async operation is important to have a seamless integration with all existing
|
||||
libraries. But it is equally important to be able to differentiate between Angular and non-Angular code running
|
||||
on the same page concurrently.
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
# Dependency Injection (DI): Documentation
|
||||
|
||||
This document describes in detail how the DI module works in Angular 2.
|
||||
|
||||
## Core Abstractions
|
||||
|
||||
The library is built on top of the following core abstractions: `Injector`, `Binding`, and `Dependency`.
|
||||
|
||||
* An injector is created from a set of bindings.
|
||||
* An injector resolves dependencies and creates objects.
|
||||
* A binding maps a token, such as a string or class, to a factory function and a list of dependencies. So a binding defines how to create an object.
|
||||
* A dependency points to a token and contains extra information on how the object corresponding to that token should be injected.
|
||||
|
||||
```
|
||||
[Injector]
|
||||
|
|
||||
|
|
||||
|*
|
||||
[Binding]
|
||||
|----------|-----------------|
|
||||
| | |*
|
||||
[Token] [FactoryFn] [Dependency]
|
||||
|---------|
|
||||
| |
|
||||
[Token] [Flags]
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```
|
||||
class Engine {
|
||||
}
|
||||
|
||||
class Car {
|
||||
constructor(@Inject(Engine) engine) {
|
||||
}
|
||||
}
|
||||
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Car).toClass(Car),
|
||||
bind(Engine).toClass(Engine)
|
||||
]);
|
||||
var car = inj.get(Car);
|
||||
```
|
||||
|
||||
In this example we create two bindings: one for `Car` and one for `Engine`. `@Inject(Engine)` declares a dependency on Engine.
|
||||
|
||||
## Injector
|
||||
|
||||
An injector instantiates objects lazily, only when asked for, and then caches them.
|
||||
|
||||
Compare
|
||||
|
||||
```
|
||||
var car = inj.get(Car); //instantiates both an Engine and a Car
|
||||
```
|
||||
|
||||
with
|
||||
|
||||
```
|
||||
var engine = inj.get(Engine); //instantiates an Engine
|
||||
var car = inj.get(Car); //instantiates a Car (reuses Engine)
|
||||
```
|
||||
|
||||
and with
|
||||
|
||||
```
|
||||
var car = inj.get(Car); //instantiates both an Engine and a Car
|
||||
var engine = inj.get(Engine); //reads the Engine from the cache
|
||||
```
|
||||
|
||||
To avoid bugs make sure the registered objects have side-effect-free constructors. In this case, an injector acts like a hash map, where the order in which the objects got created does not matter.
|
||||
|
||||
|
||||
|
||||
## Child Injectors and Dependencies
|
||||
|
||||
Injectors are hierarchical.
|
||||
|
||||
```
|
||||
var parent = Injector.resolveAndCreate([
|
||||
bind(Engine).toClass(TurboEngine)
|
||||
]);
|
||||
var child = parent.resolveAndCreateChild([Car]);
|
||||
|
||||
var car = child.get(Car); // uses the Car binding from the child injector and Engine from the parent injector.
|
||||
```
|
||||
|
||||
Injectors form a tree.
|
||||
|
||||
```
|
||||
GrandParentInjector
|
||||
/ \
|
||||
Parent1Injector Parent2Injector
|
||||
|
|
||||
ChildInjector
|
||||
```
|
||||
|
||||
The dependency resolution algorithm works as follows:
|
||||
|
||||
```
|
||||
// this is pseudocode.
|
||||
var inj = this;
|
||||
while (inj) {
|
||||
if (inj.hasKey(requestedKey)) {
|
||||
return inj.get(requestedKey);
|
||||
} else {
|
||||
inj = inj.parent;
|
||||
}
|
||||
}
|
||||
throw new NoProviderError(requestedKey);
|
||||
```
|
||||
|
||||
So in the following example
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(e: Engine){}
|
||||
}
|
||||
```
|
||||
|
||||
DI will start resolving `Engine` in the same injector where the `Car` binding is defined. It will check whether that injector has the `Engine` binding. If it is the case, it will return that instance. If not, the injector will ask its parent whether it has an instance of `Engine`. The process continues until either an instance of `Engine` has been found, or we have reached the root of the injector tree.
|
||||
|
||||
### Constraints
|
||||
|
||||
You can put upper and lower bound constraints on a dependency. For instance, the `@Self` decorator tells DI to look for `Engine` only in the same injector where `Car` is defined. So it will not walk up the tree.
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@Self() e: Engine){}
|
||||
}
|
||||
```
|
||||
|
||||
A more realistic example is having two bindings that have to be provided together (e.g., NgModel and NgRequiredValidator.)
|
||||
|
||||
The `@Host` decorator tells DI to look for `Engine` in this injector, its parent, until it reaches a host (see the section on hosts.)
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@Host() e: Engine){}
|
||||
}
|
||||
```
|
||||
|
||||
The `@SkipSelf` decorator tells DI to look for `Engine` in the whole tree starting from the parent injector.
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@SkipSelf() e: Engine){}
|
||||
}
|
||||
```
|
||||
|
||||
### DI Does Not Walk Down
|
||||
|
||||
|
||||
Dependency resolution only walks up the tree. The following will throw because DI will look for an instance of `Engine` starting from `parent`.
|
||||
|
||||
```
|
||||
var parent = Injector.resolveAndCreate([Car]);
|
||||
var child = parent.resolveAndCreateChild([
|
||||
bind(Engine).toClass(TurboEngine)
|
||||
]);
|
||||
|
||||
parent.get(Car); // will throw NoProviderError
|
||||
```
|
||||
|
||||
|
||||
## Bindings
|
||||
|
||||
You can bind to a class, a value, or a factory. It is also possible to alias existing bindings.
|
||||
|
||||
```
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Car).toClass(Car),
|
||||
bind(Engine).toClass(Engine)
|
||||
]);
|
||||
|
||||
var inj = Injector.resolveAndCreate([
|
||||
Car, // syntax sugar for bind(Car).toClass(Car)
|
||||
Engine
|
||||
]);
|
||||
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Car).toValue(new Car(new Engine()))
|
||||
]);
|
||||
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Car).toFactory((e) => new Car(e), [Engine]),
|
||||
bind(Engine).toFactory(() => new Engine())
|
||||
]);
|
||||
```
|
||||
|
||||
You can bind any token.
|
||||
|
||||
```
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Car).toFactory((e) => new Car(), ["engine!"]),
|
||||
bind("engine!").toClass(Engine)
|
||||
]);
|
||||
```
|
||||
|
||||
If you want to alias an existing binding, you can do so using `toAlias`:
|
||||
|
||||
```
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Engine).toClass(Engine),
|
||||
bind("engine!").toAlias(Engine)
|
||||
]);
|
||||
```
|
||||
which implies `inj.get(Engine) === inj.get("engine!")`.
|
||||
|
||||
Note that tokens and factory functions are decoupled.
|
||||
|
||||
```
|
||||
bind("some token").toFactory(someFactory);
|
||||
```
|
||||
|
||||
The `someFactory` function does not have to know that it creates an object for `some token`.
|
||||
|
||||
### Resolved Bindings
|
||||
|
||||
When DI receives `bind(Car).toClass(Car)`, it needs to do a few things before it can create an instance of `Car`:
|
||||
|
||||
- It needs to reflect on `Car` to create a factory function.
|
||||
- It needs to normalize the dependencies (e.g., calculate lower and upper bounds).
|
||||
|
||||
The result of these two operations is a `ResolvedBinding`.
|
||||
|
||||
The `resolveAndCreate` and `resolveAndCreateChild` functions resolve passed-in bindings before creating an injector. But you can resolve bindings yourself using `Injector.resolve([bind(Car).toClass(Car)])`. Creating an injector from pre-resolved bindings is faster, and may be needed for performance sensitive areas.
|
||||
|
||||
You can create an injector using a list of resolved bindings.
|
||||
|
||||
```
|
||||
var listOfResolvingBindings = Injector.resolve([Binding1, Binding2]);
|
||||
var inj = Injector.fromResolvedBindings(listOfResolvingBindings);
|
||||
inj.createChildFromResolvedBindings(listOfResolvedBindings);
|
||||
```
|
||||
|
||||
|
||||
### Transient Dependencies
|
||||
|
||||
An injector has only one instance created by each registered binding.
|
||||
|
||||
```
|
||||
inj.get(MyClass) === inj.get(MyClass); //always holds
|
||||
```
|
||||
|
||||
If we need a transient dependency, something that we want a new instance of every single time, we have two options.
|
||||
|
||||
We can create a child injector for each new instance:
|
||||
|
||||
```
|
||||
var child = inj.resolveAndCreateChild([MyClass]);
|
||||
child.get(MyClass);
|
||||
```
|
||||
|
||||
Or we can register a factory function:
|
||||
|
||||
```
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind('MyClassFactory').toFactory(dep => () => new MyClass(dep), [SomeDependency])
|
||||
]);
|
||||
|
||||
var factory = inj.get('MyClassFactory');
|
||||
var instance1 = factory(), instance2 = factory();
|
||||
// Depends on the implementation of MyClass, but generally holds.
|
||||
expect(instance1).not.toBe(instance2);
|
||||
```
|
||||
@@ -0,0 +1,237 @@
|
||||
# Dependency Injection (DI): Documentation (Advanced Topics)
|
||||
|
||||
This document talks about advanced topics related to the DI module and how it is used in Angular. You don't have to know this to use DI in Angular or independently.
|
||||
|
||||
### Key
|
||||
|
||||
Most of the time we do not have to deal with keys.
|
||||
|
||||
```
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(Engine).toFactory(() => new TurboEngine()) //the passed in token Engine gets mapped to a key
|
||||
]);
|
||||
var engine = inj.get(Engine); //the passed in token Engine gets mapped to a key
|
||||
```
|
||||
|
||||
Now, the same example, but with keys.
|
||||
|
||||
```
|
||||
var ENGINE_KEY = Key.get(Engine);
|
||||
|
||||
var inj = Injector.resolveAndCreate([
|
||||
bind(ENGINE_KEY).toFactory(() => new TurboEngine()) // no mapping
|
||||
]);
|
||||
var engine = inj.get(ENGINE_KEY); // no mapping
|
||||
```
|
||||
|
||||
Every key has an id, which we utilize to store bindings and instances. So Injector uses keys internally for performance reasons.
|
||||
|
||||
### ProtoInjector and Injector
|
||||
|
||||
Often there is a need to create multiple instances of essentially the same injector. In Angular 2, for example, every component element type gets an injector configured in the same way.
|
||||
|
||||
Doing the following would be very inefficient.
|
||||
|
||||
```
|
||||
function createComponetInjector(parent, bindings: Binding[]) {
|
||||
return parent.resolveAndCreateChild(bindings);
|
||||
}
|
||||
```
|
||||
|
||||
This would require us to resolve and store bindings for every single component instance. Instead, we want to resolve and store the bindings for every component type, and create a set of instances for every component. To enable that DI separates the meta information about injectables (Bindings and their dependencies), which are stored in `ProtoInjector`, and injectables themselves, which are stored in `Injector`.
|
||||
|
||||
```
|
||||
var proto = new ProtoInjector(bindings); // done once
|
||||
function createComponentInjector(parent, proto) {
|
||||
return new Injector(proto, parent);
|
||||
}
|
||||
```
|
||||
|
||||
`Injector.resolveAndCreate` creates both a `ProtoInjector` and an `Injector`.
|
||||
|
||||
### Host & Visibility
|
||||
|
||||
An injector can have a parent. The parent relationship can be marked as a "host" as follows:
|
||||
|
||||
```
|
||||
var child = new Injector(proto, parent, true /* host */);
|
||||
```
|
||||
|
||||
Hosts are used to constraint dependency resolution. For instance, in the following example, DI will stop looking for `Engine` after reaching the host.
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@Host() e: Engine) {}
|
||||
}
|
||||
```
|
||||
|
||||
Imagine the following scenario:
|
||||
|
||||
```
|
||||
ParentInjector
|
||||
/ \
|
||||
/ \ host
|
||||
Child1 Child2
|
||||
```
|
||||
|
||||
Here both Child1 and Child2 are children of ParentInjector. Child2 marks this relationship as host. ParentInjector might want to expose two different sets of bindings for its "regular" children and its "host" children. Bindings visible to "regular" children are called "public" and bindings visible to "host" children are called "private". This is an advanced use case used by Angular, where components can provide different sets of bindings for their children and their view.
|
||||
|
||||
Let's look at this example.
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@Host() e: Engine) {}
|
||||
}
|
||||
|
||||
var parentProto = new ProtoInjector([
|
||||
new BindingWithVisibility(Engine, Visibility.Public),
|
||||
new BindingWithVisibility(Car, Visibility.Public)
|
||||
]);
|
||||
var parent = new Injector(parentProto);
|
||||
|
||||
var hostChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
|
||||
var hostChild = new Injector(hostChildProto, parent, true);
|
||||
|
||||
var regularChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
|
||||
var regularChild = new Injector(regularChildProto, parent, false);
|
||||
|
||||
hostChild.get(Car); // will throw because public dependencies declared at the host cannot be seen by child injectors
|
||||
parent.get(Car); // this works
|
||||
regularChild.get(Car); // this works
|
||||
```
|
||||
|
||||
Now, let's mark `Engine` as private:
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@Host() e: Engine) {}
|
||||
}
|
||||
|
||||
var parentProto = new ProtoInjector([
|
||||
new BindingWithVisibility(Engine, Visibility.Private),
|
||||
new BindingWithVisibility(Car, Visibility.Public)
|
||||
]);
|
||||
var parent = new Injector(parentProto);
|
||||
|
||||
var hostChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
|
||||
var hostChild = new Injector(hostChildProto, parent, true);
|
||||
|
||||
var regularChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
|
||||
var regularChild = new Injector(regularChildProto, parent, false);
|
||||
|
||||
hostChild.get(Car); // this works
|
||||
parent.get(Car); // this throws
|
||||
regularChild.get(Car); // this throws
|
||||
```
|
||||
|
||||
Now, let's mark `Engine` as both public and private:
|
||||
|
||||
```
|
||||
class Car {
|
||||
constructor(@Host() e: Engine) {}
|
||||
}
|
||||
|
||||
var parentProto = new ProtoInjector([
|
||||
new BindingWithVisibility(Engine, Visibility.PublicAndPrivate),
|
||||
new BindingWithVisibility(Car, Visibility.Public)
|
||||
]);
|
||||
var parent = new Injector(parentProto);
|
||||
|
||||
var hostChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
|
||||
var hostChild = new Injector(hostChildProto, parent, true);
|
||||
|
||||
var regularChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
|
||||
var regularChild = new Injector(regularChildProto, parent, false);
|
||||
|
||||
hostChild.get(Car); // this works
|
||||
parent.get(Car); // this works
|
||||
regularChild.get(Car); // this works
|
||||
```
|
||||
|
||||
## Angular 2 and DI
|
||||
|
||||
Now let's see how Angular 2 uses DI behind the scenes.
|
||||
|
||||
The right mental model is to think that every DOM element has an Injector. (In practice, only interesting elements containing directives will have an injector, but this is a performance optimization)
|
||||
|
||||
There are two properties that can be used to configure DI: bindings and viewBindings.
|
||||
|
||||
- `bindings` affects the element and its children.
|
||||
- `viewBindings` affects the component's view.
|
||||
|
||||
Every directive can declare injectables via `bindings`, but only components can declare `viewBindings`.
|
||||
|
||||
Let's look at a complex example that shows how the injector tree gets created.
|
||||
|
||||
```
|
||||
<my-component my-directive>
|
||||
<needs-service></needs-service>
|
||||
</my-component>
|
||||
```
|
||||
|
||||
Both `MyComponent` and `MyDirective` are created on the same element.
|
||||
|
||||
```
|
||||
@Component({
|
||||
selector: 'my-component',
|
||||
bindings: [
|
||||
bind('componentService').toValue('Host_MyComponentService')
|
||||
],
|
||||
viewBindings: [
|
||||
bind('viewService').toValue('View_MyComponentService')
|
||||
]
|
||||
})
|
||||
@View({
|
||||
template: `<needs-view-service></needs-view-service>`,
|
||||
directives: [NeedsViewService]
|
||||
})
|
||||
class MyComponent {}
|
||||
|
||||
@Directive({
|
||||
selector: '[my-directive]',
|
||||
bindings: [
|
||||
bind('directiveService').toValue('MyDirectiveService')
|
||||
]
|
||||
})
|
||||
class MyDirective {
|
||||
}
|
||||
```
|
||||
|
||||
`NeedsService` and `NeedsViewService` look like this:
|
||||
|
||||
```
|
||||
@Directive({
|
||||
selector: 'needs-view-service'
|
||||
})
|
||||
class NeedsViewService {
|
||||
constructor(@Host() @Inject('viewService') viewService) {}
|
||||
}
|
||||
|
||||
@Directive({
|
||||
selector: 'needs-service'
|
||||
})
|
||||
class NeedsService {
|
||||
constructor(@Host() @Inject('componentService') service1,
|
||||
@Host() @Inject('directiveService') service2) {}
|
||||
}
|
||||
```
|
||||
|
||||
This will create the following injector tree.
|
||||
|
||||
```
|
||||
Injector1 [
|
||||
{binding: MyComponent, visibility: Visibility.PublicAndPrivate},
|
||||
{binding: 'componentService', visibility: Visibility.PublicAndPrivate},
|
||||
{binding: 'viewService', visibility: Visibility.Private},
|
||||
{binding: MyDirective visibility: Visibility.Public},
|
||||
{binding: 'directiveService', visibility: Visibility.Public}
|
||||
]
|
||||
/ \
|
||||
| \ host
|
||||
Injector2 [ Injector3 [
|
||||
{binding: NeedsService, visibility: Visibility.Public} {binding: NeedsViewService, visibility: Visibility.Public}
|
||||
] ]
|
||||
```
|
||||
|
||||
As you can see the component and its bindings can be seen by its children and its view. The view bindings can be seen only by the view. And the bindings of other directives can be seen only their children.
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
# WebWorkers in Angular 2: Documentation
|
||||
|
||||
Angular 2 includes native support for writing applications which live in a
|
||||
WebWorker. This document describes how to write applications that take advantage
|
||||
of this feature.
|
||||
It also provides a detailed description of the underlying messaging
|
||||
infrastructure that angular uses to communicate between the main process and the
|
||||
worker. This infrastructure can be modified by an application developer to
|
||||
enable driving an angular 2 application from an iFrame, different window / tab,
|
||||
server, etc..
|
||||
|
||||
## Introduction
|
||||
WebWorker support in Angular2 is designed to make it easy to leverage parallelization in your web application.
|
||||
When you choose to run your application in a WebWorker angular runs both your application's logic and the
|
||||
majority of the core angular framework in a WebWorker.
|
||||
By offloading as much code as possible to the WebWorker we keep the UI thread
|
||||
free to handle events, manipulate the DOM, and run animations. This provides a
|
||||
better framerate and UX for applications.
|
||||
|
||||
## Bootstrapping a WebWorker Application
|
||||
Bootstrapping a WebWorker application is not much different than bootstrapping a normal application.
|
||||
The primary difference is that you don't pass your root component directly to ```bootstrap```.
|
||||
Instead you pass the name of a background script that calls ```bootstrapWebWorker``` with your root component.
|
||||
|
||||
### Example
|
||||
To bootstrap Hello World in a WebWorker we do the following in TypeScript
|
||||
```HTML
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js"></script>
|
||||
<script src="https://jspm.io/system@0.16.js"></script>
|
||||
<script src="angular2/web_worker/ui.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<hello-world></hello-world>
|
||||
<script>System.import("index")</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
```TypeScript
|
||||
// index.js
|
||||
import {bootstrap} from "angular2/web_worker/ui";
|
||||
bootstrap("loader.js");
|
||||
```
|
||||
```JavaScript
|
||||
// loader.js
|
||||
importScripts("https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js", "https://jspm.io/system@0.16.js", "angular2/web_worker/worker.js");
|
||||
System.import("app");
|
||||
```
|
||||
```TypeScript
|
||||
// app.ts
|
||||
import {Component, View, bootstrapWebWorker} from "angular2/web_worker/worker";
|
||||
@Component({
|
||||
selector: "hello-world"
|
||||
})
|
||||
@View({
|
||||
template: "<h1>Hello {{name}}</h1>
|
||||
})
|
||||
export class HelloWorld {
|
||||
name: string = "Jane";
|
||||
}
|
||||
|
||||
bootstrapWebWorker(HelloWorld);
|
||||
```
|
||||
There's a few important things to note here:
|
||||
* On the UI side we import all angular types from `angular2/web_worker/ui` and on the worker side we import from
|
||||
`angular2/web_worker/worker`. These modules include all the typings in the WebWorker bundle. By importing from
|
||||
these URLs instead of `angular2/angular2` we can statically ensure that our app does not reference a type that
|
||||
doesn't exist in the context it's mean to execute in. For example, if we tried to import DomRenderer in the Worker
|
||||
or NgFor on the UI we would get a compiler error.
|
||||
* The UI loads angular from the file `angular2/web_worker/ui.js` and the Worker loads angular from
|
||||
`angular2/web_worker/worker.js`. These bundles are created specifically for using WebWorkers and should be used
|
||||
instead of the normal angular2.js file. Both files contain subsets of the angular2 codebase that is designed to
|
||||
run specifically on the UI or Worker. Additionally, they contain the core messaging infrastructure used to
|
||||
communicate between the Worker and the UI. This messaging code is not in the standard angular2.js file.
|
||||
* We pass `loader.js` to bootstrap and not `app.ts`. You can think of `loader.js` as the `index.html` of the
|
||||
Worker. Since WebWorkers share no memory with the UI we need to reload the angular2 dependencies before
|
||||
bootstrapping our application. We do this with `importScripts`. Additionally, we need to do this in a different
|
||||
file than `app.ts` because our module loader (System.js in this example) has not been loaded yet, and `app.ts`
|
||||
will be compiled with a `System.define` call at the top.
|
||||
* The HelloWorld Component looks exactly like a normal Angular2 HelloWorld Component! The goal of WebWorker
|
||||
support was to allow as much of Angular to live in the worker as possible.
|
||||
As such, *most* angular2 components can be bootstrapped in a WebWorker with minimal to no changes required.
|
||||
|
||||
For reference, here's the same HelloWorld example in Dart.
|
||||
```HTML
|
||||
<html>
|
||||
<body>
|
||||
<script type="application/dart" src="index.dart"></script>
|
||||
<script src="packages/browser.dart.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
```Dart
|
||||
// index.dart
|
||||
import "package:angular2/web_worker/ui.dart";
|
||||
import "package:angular2/src/core/reflection/reflection.dart";
|
||||
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
|
||||
|
||||
main() {
|
||||
reflector.reflectionCapabilities = new ReflectionCabilities();
|
||||
bootstrap("app.dart");
|
||||
}
|
||||
```
|
||||
```Dart
|
||||
import "package:angular2/web_worker/worker.dart";
|
||||
import "package:angular2/src/core/reflection/reflection.dart";
|
||||
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
|
||||
|
||||
@Component(
|
||||
selector: "hello-world"
|
||||
)
|
||||
@View(
|
||||
template: "<h1>Hello {{name}}</h1>"
|
||||
)
|
||||
class HelloWorld {
|
||||
String name = "Jane";
|
||||
}
|
||||
|
||||
main(List<String> args, SendPort replyTo) {
|
||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
bootstrapWebWorker(replyTo, HelloWorld);
|
||||
}
|
||||
|
||||
```
|
||||
This code is nearly the same as the TypeScript version with just a couple key differences:
|
||||
* We don't have a `loader.js` file. Dart applications don't need this file because you don't need a module loader.
|
||||
* We pass a `SendPort` to `bootstrapWebWorker`. Dart applications use the Isolate API, which communicates via
|
||||
Dart's Port abstraction. When you call `bootstrap` from the UI thread, angular starts a new Isolate to run
|
||||
your application logic. When Dart starts a new Isolate it passes a `SendPort` to that Isolate so that it
|
||||
can communicate with the Isolate that spawned it. You need to pass this `SendPort` to `bootstrapWebWorker`
|
||||
so that Angular can communicate with the UI.
|
||||
* You need to set up `ReflectionCapabilities` on both the UI and Worker. Just like writing non-concurrent
|
||||
Angular2 Dart applications you need to set up the reflector. You should not use Reflection in production,
|
||||
but should use the angular 2 transformer to remove it in your final JS code. Note there's currently a bug
|
||||
with running the transformer on your UI code (#3971). You can (and should) pass the file where you call
|
||||
`bootstrapWebWorker` as an entry point to the transformer, but you should not pass your UI index file
|
||||
to the transformer until that bug is fixed.
|
||||
|
||||
## Writing WebWorker Compatible Components
|
||||
You can do almost everything in a WebWorker component that you can do in a typical Angular 2 Component.
|
||||
The main exception is that there is **no** DOM access from a WebWorker component. In Dart this means you can't
|
||||
import anything from `dart:html` and in JavaScript it means you can't use `document` or `window`. Instead you
|
||||
should use data bindings and if needed you can inject the `Renderer` along with your component's `ElementRef`
|
||||
directly into your component and use methods such as `setElementProperty`, `setElementAttribute`,
|
||||
`setElementClass`, `setElementStyle`, `invokeElementMethod`, and `setText`. Note that you **cannot** call
|
||||
`getNativeElementSync`. Doing so will always return `null` when running in a WebWorker.
|
||||
If you need DOM access see [Running Code on the UI](#running-code-on-the-ui).
|
||||
|
||||
## WebWorker Design Overview
|
||||
When running your application in a WebWorker, the majority of the angular core along with your application logic
|
||||
runs on the worker. The two main components that run on the UI are the `Renderer` and the `RenderCompiler`. When
|
||||
running angular in a WebWorker the bindings for these two components are replaced by the `WebWorkerRenderer` and
|
||||
the `WebWorkerRenderCompiler`. When these components are used at runtime, they pass messages through the
|
||||
[MessageBroker](#messagebroker) instructing the UI to run the actual method and return the result. The
|
||||
[MessageBroker](#messagebroker) abstraction allows either side of the WebWorker boundary to schedule code to run
|
||||
on the opposite side and receive the result. You can use the [MessageBroker](#messagebroker)
|
||||
Additionally, the [MessageBroker](#messagebroker) sits on top of the [MessageBus](#messagebus).
|
||||
MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary such as `WebWorker <--> UI` communication, `UI <--> Server` communication,
|
||||
or `Window <--> Window` communication.
|
||||
|
||||
See the diagram below for a high level overview of how this code is structured:
|
||||
|
||||

|
||||
|
||||
## Running Code on the UI
|
||||
If your application needs to run code on the UI, there are a few options. The easiest way is to use a
|
||||
CustomElement in your view. You can then register this custom element from your html file and run code in response
|
||||
to the element's lifecycle hooks. Note, Custom Elements are still experimental. See
|
||||
[MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) for the latest details on how
|
||||
to use them.
|
||||
|
||||
If you require more robust communication between the WebWorker and the UI you can use the [MessageBroker](#using-the-messagebroker-in-your-application) or
|
||||
[MessageBus](#using-the-messagebus-in-your-application) directly.
|
||||
|
||||
## MessageBus
|
||||
The MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary. It supports multiplex communication through the use of a channel
|
||||
abstraction.
|
||||
|
||||
Angular currently includes two stable MessageBus implementations, which are used by default when you run your
|
||||
application inside a WebWorker.
|
||||
|
||||
1. The `PostMessageBus` is used by JavaScript applications to communicate between a WebWorker and the UI.
|
||||
2. The `IsolateMessageBus` is used by Dart applications to communicate between a background Isolate and the UI.
|
||||
|
||||
Angular also includes three experimental MessageBus implementations:
|
||||
|
||||
1. The `WebSocketMessageBus` is a Dart MessageBus that lives on the UI and communicates with an angular
|
||||
application running on a server. It's intended to be used with either the `SingleClientServerMessageBus` or the
|
||||
`MultiClientServerMessageBus`.
|
||||
2. The `SingleClientServerMessageBus` is a Dart MessageBus that lives on a Dart Server. It allows an angular
|
||||
application to run on a server and communicate with a single browser that's running the `WebSocketMessageBus`.
|
||||
3. The `MultiClientServerMessageBus` is like the `SingleClientServerMessageBus` except it allows an arbitrary
|
||||
number of clients to connect to the server. It keeps all connected browsers in sync and if an event fires in
|
||||
any connected browser it propagates the result to all connected clients. This can be especially useful as a
|
||||
debugging tool, by allowing you to connect multiple browsers / devices to the same angular application,
|
||||
change the state of that application, and ensure that all the clients render the view correctly. Using these tools
|
||||
can make it easy to catch tricky browser compatibility issues.
|
||||
|
||||
### Using the MessageBus in Your Application
|
||||
**Note**: If you want to pass custom messages between the UI and WebWorker, it's recommended you use the
|
||||
[MessageBroker](#using-the-messagebroker-in-your-application). However, if you want to control the messaging
|
||||
protocol yourself you can use the MessageBus directly.
|
||||
|
||||
To use the MessageBus you need to initialize a new channel on both the UI and WebWorker.
|
||||
In TypeScript that would look like this:
|
||||
```TypeScript
|
||||
// index.ts, which is running on the UI.
|
||||
var instance = bootstrap("loader.js");
|
||||
var bus = instance.bus;
|
||||
bus.initChannel("My Custom Channel");
|
||||
```
|
||||
```TypeScript
|
||||
// background_index.ts, which is running on the WebWorker
|
||||
import {MessageBus} from 'angular2/web_worker/worker';
|
||||
@Component({...})
|
||||
@View({...})
|
||||
export class MyComponent {
|
||||
constructor (bus: MessageBus) {
|
||||
bus.initChannel("My Custom Channel");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once the channel has been initialized either side can use the `from` and `to` methods on the MessageBus to send
|
||||
and receive messages. Both methods return EventEmitter. Expanding on the example from earlier:
|
||||
```TypeScript
|
||||
// index.ts, which is running on the UI.
|
||||
import {bootstrap} from 'angular2/web_worker/ui';
|
||||
var instance = bootstrap("loader.js");
|
||||
var bus = instance.bus;
|
||||
bus.initChannel("My Custom Channel");
|
||||
bus.to("My Custom Channel").next("hello from the UI");
|
||||
```
|
||||
```TypeScript
|
||||
// background_index.ts, which is running on the WebWorker
|
||||
import {MessageBus, Component, View} from 'angular2/web_worker/worker';
|
||||
@Component({...})
|
||||
@View({...})
|
||||
export class MyComponent {
|
||||
constructor (bus: MessageBus) {
|
||||
bus.initChannel("My Custom Channel");
|
||||
bus.from("My Custom Channel").observer((message) => {
|
||||
console.log(message); // will print "hello from the UI"
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This example is nearly identical in Dart, and is included below for reference:
|
||||
```Dart
|
||||
// index.dart, which is running on the UI.
|
||||
import 'package:angular2/web_workers/ui.dart';
|
||||
|
||||
main() {
|
||||
var instance = bootstrap("background_index.dart");
|
||||
var bus = instance.bus;
|
||||
bus.initChannel("My Custom Channel");
|
||||
bus.to("My Custom Channel").add("hello from the UI");
|
||||
}
|
||||
|
||||
```
|
||||
```Dart
|
||||
// background_index.dart, which is running on the WebWorker
|
||||
import 'package:angular2/web_worker/worker.dart';
|
||||
@Component(...)
|
||||
@View(...)
|
||||
class MyComponent {
|
||||
MyComponent (MessageBus bus) {
|
||||
bus.initChannel("My Custom Channel");
|
||||
bus.from("My Custom Channel").listen((message) {
|
||||
print(message); // will print "hello from the UI"
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
The only substantial difference between these APIs in Dart and TypeScript is the different APIs for the
|
||||
`EventEmitter`.
|
||||
|
||||
**Note:** Because the messages passed through the MessageBus cross a WebWorker boundary, they must be serializable.
|
||||
If you use the MessageBus directly, you are responsible for serializing your messages.
|
||||
In JavaScript / TypeScript this means they must be serializable via JavaScript's
|
||||
[structured cloning algorithim](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
|
||||
|
||||
In Dart this means they must be valid messages that can be passed through a
|
||||
[SendPort](https://api.dartlang.org/1.12.1/dart-isolate/SendPort/send.html).
|
||||
|
||||
|
||||
### MessageBus and Zones
|
||||
The MessageBus API includes support for [zones](http://www.github.com/angular/zone.js).
|
||||
A MessageBus can be attached to a specific zone (by calling `attachToZone`). Then specific channels can be
|
||||
specified to run in the zone when they are initialized.
|
||||
If a channel is running in the zone, that means that any events emitted from that channel will be executed within
|
||||
the given zone. For example, by default angular runs the EventDispatch channel inside the angular zone. That means
|
||||
when an event is fired from the DOM and received on the WebWorker the event handler automatically runs inside the
|
||||
angular zone. This is desired because after the event handler exits we want to exit the zone so that we trigger
|
||||
change detection. Generally, you want your channels to run inside the zone unless you have a good reason for why
|
||||
they need to run outside the zone.
|
||||
|
||||
### Implementing and Using a Custom MessageBus
|
||||
**Note:** Implementing and using a Custom MessageBus is experimental and requires importing from private APIs.
|
||||
|
||||
If you want to drive your application from something other than a WebWorker you can implement a custom message
|
||||
bus. Implementing a custom message bus just means creating a class that fulfills the API specified by the
|
||||
abstract MessageBus class.
|
||||
|
||||
If you're implementing your MessageBus in Dart you can extend the `GenericMessageBus` class included in angular.
|
||||
if you do this, you don't need to implement zone or channel support yourself. You only need to implement a
|
||||
`MessageBusSink` that extends `GenericMessageBusSink` and a `MessageBusSource` that extends
|
||||
`GenericMessageBusSource`. The `MessageBusSink` must override the `sendMessages` method. This method is
|
||||
given a list of serialized messages that it is required to send through the sink.
|
||||
The `MessageBusSource` needs to provide a [Stream](https://api.dartlang.org/1.12.1/dart-async/Stream-class.html)
|
||||
of incoming messages (either by passing the stream to `GenericMessageBusSource's` constructor or by calling
|
||||
attachTo() with the stream). It also needs to override the abstract `decodeMessages` method. This method is
|
||||
given a List of serialized messages received by the source and should perform any decoding work that needs to be
|
||||
done before the application can read the messages.
|
||||
|
||||
For example, if your MessageBus sends and receives JSON data you would do the following:
|
||||
```Dart
|
||||
import 'package:angular2/src/web_workers/shared/generic_message_bus.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class JsonMessageBusSink extends GenericMessageBusSink {
|
||||
@override
|
||||
void sendMessages(List<dynamic> messages) {
|
||||
String encodedMessages = JSON.encode(messages);
|
||||
// Send encodedMessages here
|
||||
}
|
||||
}
|
||||
|
||||
class JsonMessageBusSource extends GenericMessageBuSource {
|
||||
JsonMessageBusSource(Stream incomingMessages) : super (incomingMessages);
|
||||
|
||||
@override
|
||||
List<dynamic> decodeMessages(dynamic messages) {
|
||||
return JSON.decode(messages);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once you've implemented your custom MessageBus in either TypeScript or Dart, you can tell angular to use it like
|
||||
so:
|
||||
In TypeScript:
|
||||
```TypeScript
|
||||
// index.ts, running on the UI side
|
||||
import {bootstrapUICommon} from 'angular2/src/web_workers/ui/impl';
|
||||
var bus = new MyAwesomeMessageBus();
|
||||
bootstrapUICommon(bus);
|
||||
```
|
||||
```TypeScript
|
||||
// background_index.ts, running on the application side
|
||||
import {bootstrapWebWorkerCommon} from 'angular2/src/web_workers/worker/application_common';
|
||||
import {MyApp} from './app';
|
||||
var bus = new MyAwesomeMessageBus();
|
||||
bootstrapWebWorkerCommon(MyApp, bus);
|
||||
```
|
||||
In Dart:
|
||||
```Dart
|
||||
// index.dart, running on the UI side
|
||||
import 'package:angular2/src/web_workers/ui/impl.dart' show bootstrapUICommon;
|
||||
import "package:angular2/src/core/reflection/reflection.dart";
|
||||
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
|
||||
|
||||
main() {
|
||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
var bus = new MyAwesomeMessageBus();
|
||||
bootstrapUiCommon(bus);
|
||||
}
|
||||
```
|
||||
```Dart
|
||||
// background_index.dart, running on the application side
|
||||
import "package:angular2/src/web_workers/worker/application_common.dart" show bootstrapWebWorkerCommon;
|
||||
import "package:angular2/src/core/reflection/reflection.dart";
|
||||
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
|
||||
import "./app.dart" show MyApp;
|
||||
|
||||
main() {
|
||||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
var bus = new MyAwesomeMessageBus();
|
||||
bootstrapWebWorkerCommon(MyApp, bus);
|
||||
}
|
||||
```
|
||||
Notice how we call `bootstrapUICommon` instead of `bootstrap` from the UI side. `bootstrap` spans a new WebWorker
|
||||
/ Isolate and attaches the default angular MessageBus to it. If you're using a custom MessageBus you are
|
||||
responsible for setting up the application side and initiating communication with it. `bootstrapUICommon` assumes
|
||||
that the given MessageBus is already set up and can communicate with the application.
|
||||
Similarly, we call `bootstrapWebWorkerCommon` instead of `boostrapWebWorker` from the application side. This is
|
||||
because `bootstrapWebWorker` assumes you're using the default angular MessageBus and initializes a new one for you.
|
||||
|
||||
## MessageBroker
|
||||
The MessageBroker is a higher level messaging abstraction that sits on top of the MessageBus. It is used when you
|
||||
want to execute code on the other side of a runtime boundary and may want to receive the result.
|
||||
There are two types of MessageBrokers:
|
||||
|
||||
1. The `ServiceMessageBroker` is used by the side that actually performs
|
||||
an operation and may return a result;
|
||||
2. The `ClientMessageBroker` is used by the side that requests that
|
||||
an operation be performed and may want to receive the result.
|
||||
|
||||
### Using the MessageBroker In Your Application
|
||||
To use MessageBrokers in your application you must initialize both a `ClientMessageBroker` and a
|
||||
`ServiceMessageBroker` on the same channel. You can then register methods with the `ServiceMessageBroker` and
|
||||
instruct the `ClientMessageBroker` to run those methods. Below is a lightweight example of using
|
||||
MessageBrokers in an application. For a more complete example, check out the `WebWorkerRenderer` and
|
||||
`MessageBasedRenderer` inside the Angular WebWorker code.
|
||||
|
||||
#### Using the MessageBroker in TypeScript
|
||||
```TypeScript
|
||||
// index.ts, which is running on the UI with a method that we want to expose to a WebWorker
|
||||
import {bootstrap} from 'angular2/web_worker/ui';
|
||||
|
||||
var instance = bootstrap("loader.js");
|
||||
var broker = instance.app.createServiceMessageBroker("My Broker Channel");
|
||||
|
||||
// assume we have some function doCoolThings that takes a string argument and returns a Promise<string>
|
||||
broker.registerMethod("awesomeMethod", [PRIMITIVE], (arg1: string) => doCoolThing(arg1), PRIMITIVE);
|
||||
```
|
||||
```TypeScript
|
||||
// background.ts, which is running on a WebWorker and wants to execute a method on the UI
|
||||
import {Component, View, ClientMessageBrokerFactory, PRIMITIVE, UiArguments, FnArgs}
|
||||
from 'angular2/web_worker/worker';
|
||||
|
||||
@Component(...)
|
||||
@View(...)
|
||||
export class MyComponent {
|
||||
constructor(brokerFactory: ClientMessageBrokerFactory) {
|
||||
var broker = brokerFactory.createMessageBroker("My Broker Channel");
|
||||
|
||||
var arguments = [new FnArg(value, PRIMITIVE)];
|
||||
var methodInfo = new UiArguments("awesomeMethod", arguments);
|
||||
broker.runOnService(methodInfo, PRIMTIVE).then((result: string) => {
|
||||
// result will be equal to the return value of doCoolThing(value) that ran on the UI.
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
#### Using the MessageBroker in Dart
|
||||
```Dart
|
||||
// index.dart, which is running on the UI with a method that we want to expose to a WebWorker
|
||||
import 'package:angular2/web_worker/ui.dart';
|
||||
|
||||
main() {
|
||||
var instance = bootstrap("background.dart");
|
||||
var broker = instance.app.createServiceMessageBroker("My Broker Channel");
|
||||
|
||||
// assume we have some function doCoolThings that takes a String argument and returns a Future<String>
|
||||
broker.registerMethod("awesomeMethod", [PRIMITIVE], (String arg1) => doCoolThing(arg1), PRIMITIVE);
|
||||
}
|
||||
|
||||
```
|
||||
```Dart
|
||||
// background.dart, which is running on a WebWorker and wants to execute a method on the UI
|
||||
import 'package:angular2/web_worker/worker.dart';
|
||||
|
||||
@Component(...)
|
||||
@View(...)
|
||||
class MyComponent {
|
||||
MyComponent(ClientMessageBrokerFactory brokerFactory) {
|
||||
var broker = brokerFactory.createMessageBroker("My Broker Channel");
|
||||
|
||||
var arguments = [new FnArg(value, PRIMITIVE)];
|
||||
var methodInfo = new UiArguments("awesomeMethod", arguments);
|
||||
broker.runOnService(methodInfo, PRIMTIVE).then((String result) {
|
||||
// result will be equal to the return value of doCoolThing(value) that ran on the UI.
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
Both the client and the service create new MessageBrokers and attach them to the same channel.
|
||||
The service then calls `registerMethod` to register the method that it wants to listen to. Register method takes
|
||||
four arguments. The first is the name of the method, the second is the Types of that method's parameters, the
|
||||
third is the method itself, and the fourth (which is optional) is the return Type of that method.
|
||||
The MessageBroker handles serializing / deserializing your parameters and return types using angular's serializer.
|
||||
However, at the moment the serializer only knows how to serialize angular classes like those used by the Renderer.
|
||||
If you're passing anything other than those types around in your application you can handle serialization yourself
|
||||
and then use the `PRIMITIVE` type to tell the MessageBroker to avoid serializing your data.
|
||||
|
||||
The last thing that happens is that the client calls `runOnService` with the name of the method it wants to run,
|
||||
a list of that method's arguments and their types, and (optionally) the expected return type.
|
||||
@@ -0,0 +1,6 @@
|
||||
# API Examples
|
||||
|
||||
This folder contains small example apps that get in-lined into our API docs.
|
||||
These examples are written with idiomatic TypeScript, and are not transpiled to Dart.
|
||||
Each example contains tests for application behavior (as opposed to testing Angular's
|
||||
behavior) just like an Angular application developer would write.
|
||||
@@ -0,0 +1,7 @@
|
||||
// #docregion enableDevMode
|
||||
var core_1 = require('angular2/core');
|
||||
var my_component_1 = require('my_component');
|
||||
core_1.enableDevMode();
|
||||
core_1.bootstrap(my_component_1.MyComponent);
|
||||
// #enddocregion
|
||||
//# sourceMappingURL=dev_mode_example.js.map
|
||||
@@ -0,0 +1,23 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var core_1 = require('angular2/core');
|
||||
var MyComponent = (function () {
|
||||
function MyComponent() {
|
||||
}
|
||||
MyComponent = __decorate([
|
||||
core_1.Component({ selector: 'my-component', template: '<h1>My Component</h1>' }),
|
||||
__metadata('design:paramtypes', [])
|
||||
], MyComponent);
|
||||
return MyComponent;
|
||||
})();
|
||||
exports.MyComponent = MyComponent;
|
||||
//# sourceMappingURL=my_component.js.map
|
||||
@@ -0,0 +1,63 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
var router_1 = require('angular2/router');
|
||||
function checkIfWeHavePermission(instruction) {
|
||||
return instruction.params['id'] == '1';
|
||||
}
|
||||
// #docregion canActivate
|
||||
var ControlPanelCmp = (function () {
|
||||
function ControlPanelCmp() {
|
||||
}
|
||||
ControlPanelCmp = __decorate([
|
||||
angular2_1.Component({ selector: 'control-panel-cmp', template: "<div>Settings: ...</div>" }),
|
||||
router_1.CanActivate(checkIfWeHavePermission),
|
||||
__metadata('design:paramtypes', [])
|
||||
], ControlPanelCmp);
|
||||
return ControlPanelCmp;
|
||||
})();
|
||||
// #enddocregion
|
||||
var HomeCmp = (function () {
|
||||
function HomeCmp() {
|
||||
}
|
||||
HomeCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'home-cmp',
|
||||
template: "\n <h1>Welcome Home!</h1>\n <div>\n Edit <a [router-link]=\"['/ControlPanelCmp', {id: 1}]\" id=\"user-1-link\">User 1</a> |\n Edit <a [router-link]=\"['/ControlPanelCmp', {id: 2}]\" id=\"user-2-link\">User 2</a>\n </div>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES]
|
||||
}),
|
||||
__metadata('design:paramtypes', [])
|
||||
], HomeCmp);
|
||||
return HomeCmp;
|
||||
})();
|
||||
var AppCmp = (function () {
|
||||
function AppCmp() {
|
||||
}
|
||||
AppCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'example-app',
|
||||
template: "\n <h1>My App</h1>\n <router-outlet></router-outlet>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES]
|
||||
}),
|
||||
router_1.RouteConfig([
|
||||
{ path: '/user-settings/:id', component: ControlPanelCmp, name: 'ControlPanelCmp' },
|
||||
{ path: '/', component: HomeCmp, name: 'HomeCmp' }
|
||||
]),
|
||||
__metadata('design:paramtypes', [])
|
||||
], AppCmp);
|
||||
return AppCmp;
|
||||
})();
|
||||
function main() {
|
||||
return angular2_1.bootstrap(AppCmp, [angular2_1.provide(router_1.APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/can_activate' })]);
|
||||
}
|
||||
exports.main = main;
|
||||
//# sourceMappingURL=can_activate_example.js.map
|
||||
@@ -0,0 +1,26 @@
|
||||
var e2e_util_1 = require('angular2/src/testing/e2e_util');
|
||||
function waitForElement(selector) {
|
||||
var EC = protractor.ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
describe('reuse example app', function () {
|
||||
afterEach(e2e_util_1.verifyNoBrowserErrors);
|
||||
var URL = 'angular2/examples/router/ts/can_activate/';
|
||||
it('should navigate to user 1', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('home-cmp');
|
||||
element(by.css('#user-1-link')).click();
|
||||
waitForElement('control-panel-cmp');
|
||||
expect(browser.getCurrentUrl()).toMatch(/\/user-settings\/1$/);
|
||||
expect(element(by.css('control-panel-cmp')).getText()).toContain('Settings');
|
||||
});
|
||||
it('should not navigate to user 2', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('home-cmp');
|
||||
element(by.css('#user-2-link')).click();
|
||||
waitForElement('home-cmp');
|
||||
expect(element(by.css('home-cmp')).getText()).toContain('Welcome Home!');
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=can_activate_spec.js.map
|
||||
@@ -0,0 +1,66 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
var router_1 = require('angular2/router');
|
||||
// #docregion canDeactivate
|
||||
var NoteCmp = (function () {
|
||||
function NoteCmp(params) {
|
||||
this.id = params.get('id');
|
||||
}
|
||||
NoteCmp.prototype.canDeactivate = function (next, prev) {
|
||||
return confirm('Are you sure you want to leave?');
|
||||
};
|
||||
NoteCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'note-cmp',
|
||||
template: "\n <div>\n <h2>id: {{id}}</h2>\n <textarea cols=\"40\" rows=\"10\"></textarea>\n </div>"
|
||||
}),
|
||||
__metadata('design:paramtypes', [router_1.RouteParams])
|
||||
], NoteCmp);
|
||||
return NoteCmp;
|
||||
})();
|
||||
// #enddocregion
|
||||
var NoteIndexCmp = (function () {
|
||||
function NoteIndexCmp() {
|
||||
}
|
||||
NoteIndexCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'note-index-cmp',
|
||||
template: "\n <h1>Your Notes</h1>\n <div>\n Edit <a [router-link]=\"['/NoteCmp', {id: 1}]\" id=\"note-1-link\">Note 1</a> |\n Edit <a [router-link]=\"['/NoteCmp', {id: 2}]\" id=\"note-2-link\">Note 2</a>\n </div>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES]
|
||||
}),
|
||||
__metadata('design:paramtypes', [])
|
||||
], NoteIndexCmp);
|
||||
return NoteIndexCmp;
|
||||
})();
|
||||
var AppCmp = (function () {
|
||||
function AppCmp() {
|
||||
}
|
||||
AppCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'example-app',
|
||||
template: "\n <h1>My App</h1>\n <router-outlet></router-outlet>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES]
|
||||
}),
|
||||
router_1.RouteConfig([
|
||||
{ path: '/note/:id', component: NoteCmp, name: 'NoteCmp' },
|
||||
{ path: '/', component: NoteIndexCmp, name: 'NoteIndexCmp' }
|
||||
]),
|
||||
__metadata('design:paramtypes', [])
|
||||
], AppCmp);
|
||||
return AppCmp;
|
||||
})();
|
||||
function main() {
|
||||
return angular2_1.bootstrap(AppCmp, [angular2_1.provide(router_1.APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/can_deactivate' })]);
|
||||
}
|
||||
exports.main = main;
|
||||
//# sourceMappingURL=can_deactivate_example.js.map
|
||||
@@ -0,0 +1,36 @@
|
||||
var e2e_util_1 = require('angular2/src/testing/e2e_util');
|
||||
function waitForElement(selector) {
|
||||
var EC = protractor.ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
function waitForAlert() {
|
||||
var EC = protractor.ExpectedConditions;
|
||||
browser.wait(EC.alertIsPresent(), 1000);
|
||||
}
|
||||
describe('can deactivate example app', function () {
|
||||
afterEach(e2e_util_1.verifyNoBrowserErrors);
|
||||
var URL = 'angular2/examples/router/ts/can_deactivate/';
|
||||
it('should not navigate away when prompt is cancelled', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('note-index-cmp');
|
||||
element(by.css('#note-1-link')).click();
|
||||
waitForElement('note-cmp');
|
||||
browser.navigate().back();
|
||||
waitForAlert();
|
||||
browser.switchTo().alert().dismiss(); // Use to simulate cancel button
|
||||
expect(element(by.css('note-cmp')).getText()).toContain('id: 1');
|
||||
});
|
||||
it('should navigate away when prompt is confirmed', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('note-index-cmp');
|
||||
element(by.css('#note-1-link')).click();
|
||||
waitForElement('note-cmp');
|
||||
browser.navigate().back();
|
||||
waitForAlert();
|
||||
browser.switchTo().alert().accept();
|
||||
waitForElement('note-index-cmp');
|
||||
expect(element(by.css('note-index-cmp')).getText()).toContain('Your Notes');
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=can_deactivate_spec.js.map
|
||||
@@ -0,0 +1,50 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
var router_1 = require('angular2/router');
|
||||
// #docregion onActivate
|
||||
var MyCmp = (function () {
|
||||
function MyCmp() {
|
||||
this.log = '';
|
||||
}
|
||||
MyCmp.prototype.onActivate = function (next, prev) {
|
||||
this.log = "Finished navigating from \"" + (prev ? prev.urlPath : 'null') + "\" to \"" + next.urlPath + "\"";
|
||||
};
|
||||
MyCmp = __decorate([
|
||||
angular2_1.Component({ selector: 'my-cmp', template: "<div>onActivate: {{log}}</div>" }),
|
||||
__metadata('design:paramtypes', [])
|
||||
], MyCmp);
|
||||
return MyCmp;
|
||||
})();
|
||||
// #enddocregion
|
||||
var AppCmp = (function () {
|
||||
function AppCmp() {
|
||||
}
|
||||
AppCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'example-app',
|
||||
template: "\n <h1>My App</h1>\n <nav>\n <a [router-link]=\"['/HomeCmp']\" id=\"home-link\">Navigate Home</a> |\n <a [router-link]=\"['/ParamCmp', {param: 1}]\" id=\"param-link\">Navigate with a Param</a>\n </nav>\n <router-outlet></router-outlet>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES]
|
||||
}),
|
||||
router_1.RouteConfig([
|
||||
{ path: '/', component: MyCmp, name: 'HomeCmp' },
|
||||
{ path: '/:param', component: MyCmp, name: 'ParamCmp' }
|
||||
]),
|
||||
__metadata('design:paramtypes', [])
|
||||
], AppCmp);
|
||||
return AppCmp;
|
||||
})();
|
||||
function main() {
|
||||
return angular2_1.bootstrap(AppCmp, [angular2_1.provide(router_1.APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/on_activate' })]);
|
||||
}
|
||||
exports.main = main;
|
||||
//# sourceMappingURL=on_activate_example.js.map
|
||||
@@ -0,0 +1,25 @@
|
||||
var e2e_util_1 = require('angular2/src/testing/e2e_util');
|
||||
function waitForElement(selector) {
|
||||
var EC = protractor.ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
describe('on activate example app', function () {
|
||||
afterEach(e2e_util_1.verifyNoBrowserErrors);
|
||||
var URL = 'angular2/examples/router/ts/on_activate/';
|
||||
it('should update the text when navigating between routes', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('my-cmp');
|
||||
expect(element(by.css('my-cmp')).getText())
|
||||
.toContain('onActivate: Finished navigating from "null" to ""');
|
||||
element(by.css('#param-link')).click();
|
||||
waitForElement('my-cmp');
|
||||
expect(element(by.css('my-cmp')).getText())
|
||||
.toContain('onActivate: Finished navigating from "" to "1"');
|
||||
browser.navigate().back();
|
||||
waitForElement('my-cmp');
|
||||
expect(element(by.css('my-cmp')).getText())
|
||||
.toContain('onActivate: Finished navigating from "1" to ""');
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=on_activate_spec.js.map
|
||||
@@ -0,0 +1,65 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
var router_1 = require('angular2/router');
|
||||
var LogService = (function () {
|
||||
function LogService() {
|
||||
this.logs = [];
|
||||
}
|
||||
LogService.prototype.addLog = function (message) { this.logs.push(message); };
|
||||
LogService = __decorate([
|
||||
angular2_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], LogService);
|
||||
return LogService;
|
||||
})();
|
||||
// #docregion onDeactivate
|
||||
var MyCmp = (function () {
|
||||
function MyCmp(logService) {
|
||||
this.logService = logService;
|
||||
}
|
||||
MyCmp.prototype.onDeactivate = function (next, prev) {
|
||||
this.logService.addLog("Navigating from \"" + (prev ? prev.urlPath : 'null') + "\" to \"" + next.urlPath + "\"");
|
||||
};
|
||||
MyCmp = __decorate([
|
||||
angular2_1.Component({ selector: 'my-cmp', template: "<div>hello</div>" }),
|
||||
__metadata('design:paramtypes', [LogService])
|
||||
], MyCmp);
|
||||
return MyCmp;
|
||||
})();
|
||||
// #enddocregion
|
||||
var AppCmp = (function () {
|
||||
function AppCmp(logService) {
|
||||
this.logService = logService;
|
||||
}
|
||||
AppCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'example-app',
|
||||
template: "\n <h1>My App</h1>\n <nav>\n <a [router-link]=\"['/HomeCmp']\" id=\"home-link\">Navigate Home</a> |\n <a [router-link]=\"['/ParamCmp', {param: 1}]\" id=\"param-link\">Navigate with a Param</a>\n </nav>\n <router-outlet></router-outlet>\n <div id=\"log\">\n <h2>Log:</h2>\n <p *ng-for=\"#logItem of logService.logs\">{{ logItem }}</p>\n </div>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES, angular2_1.NgFor]
|
||||
}),
|
||||
router_1.RouteConfig([
|
||||
{ path: '/', component: MyCmp, name: 'HomeCmp' },
|
||||
{ path: '/:param', component: MyCmp, name: 'ParamCmp' }
|
||||
]),
|
||||
__metadata('design:paramtypes', [LogService])
|
||||
], AppCmp);
|
||||
return AppCmp;
|
||||
})();
|
||||
function main() {
|
||||
return angular2_1.bootstrap(AppCmp, [
|
||||
angular2_1.provide(router_1.APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/on_deactivate' }),
|
||||
LogService
|
||||
]);
|
||||
}
|
||||
exports.main = main;
|
||||
//# sourceMappingURL=on_deactivate_example.js.map
|
||||
@@ -0,0 +1,23 @@
|
||||
var e2e_util_1 = require('angular2/src/testing/e2e_util');
|
||||
function waitForElement(selector) {
|
||||
var EC = protractor.ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
describe('on activate example app', function () {
|
||||
afterEach(e2e_util_1.verifyNoBrowserErrors);
|
||||
var URL = 'angular2/examples/router/ts/on_deactivate/';
|
||||
it('should update the text when navigating between routes', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('my-cmp');
|
||||
expect(element(by.css('#log')).getText()).toEqual('Log:');
|
||||
element(by.css('#param-link')).click();
|
||||
waitForElement('my-cmp');
|
||||
expect(element(by.css('#log')).getText()).toEqual('Log:\nNavigating from "" to "1"');
|
||||
browser.navigate().back();
|
||||
waitForElement('my-cmp');
|
||||
expect(element(by.css('#log')).getText())
|
||||
.toEqual('Log:\nNavigating from "" to "1"\nNavigating from "1" to ""');
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=on_deactivate_spec.js.map
|
||||
@@ -0,0 +1,54 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
var router_1 = require('angular2/router');
|
||||
// #docregion reuseCmp
|
||||
var MyCmp = (function () {
|
||||
function MyCmp(params) {
|
||||
this.name = params.get('name') || 'NOBODY';
|
||||
}
|
||||
MyCmp.prototype.canReuse = function (next, prev) { return true; };
|
||||
MyCmp.prototype.onReuse = function (next, prev) {
|
||||
this.name = next.params['name'];
|
||||
};
|
||||
MyCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'my-cmp',
|
||||
template: "\n <div>hello {{name}}!</div>\n <div>message: <input id=\"message\"></div>\n "
|
||||
}),
|
||||
__metadata('design:paramtypes', [router_1.RouteParams])
|
||||
], MyCmp);
|
||||
return MyCmp;
|
||||
})();
|
||||
// #enddocregion
|
||||
var AppCmp = (function () {
|
||||
function AppCmp() {
|
||||
}
|
||||
AppCmp = __decorate([
|
||||
angular2_1.Component({
|
||||
selector: 'example-app',
|
||||
template: "\n <h1>Say hi to...</h1>\n <a [router-link]=\"['/HomeCmp', {name: 'naomi'}]\" id=\"naomi-link\">Naomi</a> |\n <a [router-link]=\"['/HomeCmp', {name: 'brad'}]\" id=\"brad-link\">Brad</a>\n <router-outlet></router-outlet>\n ",
|
||||
directives: [router_1.ROUTER_DIRECTIVES]
|
||||
}),
|
||||
router_1.RouteConfig([
|
||||
{ path: '/', component: MyCmp, name: 'HomeCmp' },
|
||||
{ path: '/:name', component: MyCmp, name: 'HomeCmp' }
|
||||
]),
|
||||
__metadata('design:paramtypes', [])
|
||||
], AppCmp);
|
||||
return AppCmp;
|
||||
})();
|
||||
function main() {
|
||||
return angular2_1.bootstrap(AppCmp, [angular2_1.provide(router_1.APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/reuse' })]);
|
||||
}
|
||||
exports.main = main;
|
||||
//# sourceMappingURL=reuse_example.js.map
|
||||
@@ -0,0 +1,26 @@
|
||||
var e2e_util_1 = require('angular2/src/testing/e2e_util');
|
||||
function waitForElement(selector) {
|
||||
var EC = protractor.ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
describe('reuse example app', function () {
|
||||
afterEach(e2e_util_1.verifyNoBrowserErrors);
|
||||
var URL = 'angular2/examples/router/ts/reuse/';
|
||||
it('should build a link which points to the detail page', function () {
|
||||
browser.get(URL);
|
||||
waitForElement('my-cmp');
|
||||
element(by.css('#naomi-link')).click();
|
||||
waitForElement('my-cmp');
|
||||
expect(browser.getCurrentUrl()).toMatch(/\/naomi$/);
|
||||
// type something into input
|
||||
element(by.css('#message')).sendKeys('long time no see!');
|
||||
// navigate to Brad
|
||||
element(by.css('#brad-link')).click();
|
||||
waitForElement('my-cmp');
|
||||
expect(browser.getCurrentUrl()).toMatch(/\/brad$/);
|
||||
// check that typed input is the same
|
||||
expect(element(by.css('#message')).getAttribute('value')).toEqual('long time no see!');
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=reuse_spec.js.map
|
||||
@@ -0,0 +1,296 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* The http module provides services to perform http requests. To get started, see the {@link Http}
|
||||
* class.
|
||||
*/
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
var http_1 = require('./src/http/http');
|
||||
var xhr_backend_1 = require('./src/http/backends/xhr_backend');
|
||||
var jsonp_backend_1 = require('./src/http/backends/jsonp_backend');
|
||||
var browser_xhr_1 = require('./src/http/backends/browser_xhr');
|
||||
var browser_jsonp_1 = require('./src/http/backends/browser_jsonp');
|
||||
var base_request_options_1 = require('./src/http/base_request_options');
|
||||
var base_response_options_1 = require('./src/http/base_response_options');
|
||||
var mock_backend_1 = require('./src/http/backends/mock_backend');
|
||||
exports.MockConnection = mock_backend_1.MockConnection;
|
||||
exports.MockBackend = mock_backend_1.MockBackend;
|
||||
var static_request_1 = require('./src/http/static_request');
|
||||
exports.Request = static_request_1.Request;
|
||||
var static_response_1 = require('./src/http/static_response');
|
||||
exports.Response = static_response_1.Response;
|
||||
var interfaces_1 = require('./src/http/interfaces');
|
||||
exports.Connection = interfaces_1.Connection;
|
||||
exports.ConnectionBackend = interfaces_1.ConnectionBackend;
|
||||
var browser_xhr_2 = require('./src/http/backends/browser_xhr');
|
||||
exports.BrowserXhr = browser_xhr_2.BrowserXhr;
|
||||
var base_request_options_2 = require('./src/http/base_request_options');
|
||||
exports.BaseRequestOptions = base_request_options_2.BaseRequestOptions;
|
||||
exports.RequestOptions = base_request_options_2.RequestOptions;
|
||||
var base_response_options_2 = require('./src/http/base_response_options');
|
||||
exports.BaseResponseOptions = base_response_options_2.BaseResponseOptions;
|
||||
exports.ResponseOptions = base_response_options_2.ResponseOptions;
|
||||
var xhr_backend_2 = require('./src/http/backends/xhr_backend');
|
||||
exports.XHRBackend = xhr_backend_2.XHRBackend;
|
||||
exports.XHRConnection = xhr_backend_2.XHRConnection;
|
||||
var jsonp_backend_2 = require('./src/http/backends/jsonp_backend');
|
||||
exports.JSONPBackend = jsonp_backend_2.JSONPBackend;
|
||||
exports.JSONPConnection = jsonp_backend_2.JSONPConnection;
|
||||
var http_2 = require('./src/http/http');
|
||||
exports.Http = http_2.Http;
|
||||
exports.Jsonp = http_2.Jsonp;
|
||||
var headers_1 = require('./src/http/headers');
|
||||
exports.Headers = headers_1.Headers;
|
||||
var enums_1 = require('./src/http/enums');
|
||||
exports.ResponseTypes = enums_1.ResponseTypes;
|
||||
exports.ReadyStates = enums_1.ReadyStates;
|
||||
exports.RequestMethods = enums_1.RequestMethods;
|
||||
var url_search_params_1 = require('./src/http/url_search_params');
|
||||
exports.URLSearchParams = url_search_params_1.URLSearchParams;
|
||||
/**
|
||||
* Provides a basic set of injectables to use the {@link Http} service in any application.
|
||||
*
|
||||
* The `HTTP_PROVIDERS` should be included either in a component's injector,
|
||||
* or in the root injector when bootstrapping an application.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/snj7Nv?p=preview))
|
||||
*
|
||||
* ```
|
||||
* import {bootstrap, Component, NgFor, View} from 'angular2/angular2';
|
||||
* import {HTTP_PROVIDERS, Http} from 'angular2/http';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'app',
|
||||
* providers: [HTTP_PROVIDERS],
|
||||
* template: `
|
||||
* <div>
|
||||
* <h1>People</h1>
|
||||
* <ul>
|
||||
* <li *ng-for="#person of people">
|
||||
* {{person.name}}
|
||||
* </li>
|
||||
* </ul>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [NgFor]
|
||||
* })
|
||||
* export class App {
|
||||
* people: Object[];
|
||||
* constructor(http:Http) {
|
||||
* http.get('people.json').subscribe(res => {
|
||||
* this.people = res.json();
|
||||
* });
|
||||
* }
|
||||
* active:boolean = false;
|
||||
* toggleActiveState() {
|
||||
* this.active = !this.active;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* bootstrap(App)
|
||||
* .catch(err => console.error(err));
|
||||
* ```
|
||||
*
|
||||
* The primary public API included in `HTTP_PROVIDERS` is the {@link Http} class.
|
||||
* However, other providers required by `Http` are included,
|
||||
* which may be beneficial to override in certain cases.
|
||||
*
|
||||
* The providers included in `HTTP_PROVIDERS` include:
|
||||
* * {@link Http}
|
||||
* * {@link XHRBackend}
|
||||
* * `BrowserXHR` - Private factory to create `XMLHttpRequest` instances
|
||||
* * {@link RequestOptions} - Bound to {@link BaseRequestOptions} class
|
||||
* * {@link ResponseOptions} - Bound to {@link BaseResponseOptions} class
|
||||
*
|
||||
* There may be cases where it makes sense to extend the base request options,
|
||||
* such as to add a search string to be appended to all URLs.
|
||||
* To accomplish this, a new provider for {@link RequestOptions} should
|
||||
* be added in the same injector as `HTTP_PROVIDERS`.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/aCMEXi?p=preview))
|
||||
*
|
||||
* ```
|
||||
* import {provide, bootstrap} from 'angular2/angular2';
|
||||
* import {HTTP_PROVIDERS, BaseRequestOptions, RequestOptions} from 'angular2/http';
|
||||
*
|
||||
* class MyOptions extends BaseRequestOptions {
|
||||
* search: string = 'coreTeam=true';
|
||||
* }
|
||||
*
|
||||
* bootstrap(App, [HTTP_PROVIDERS, provide(RequestOptions, {useClass: MyOptions})])
|
||||
* .catch(err => console.error(err));
|
||||
* ```
|
||||
*
|
||||
* Likewise, to use a mock backend for unit tests, the {@link XHRBackend}
|
||||
* provider should be bound to {@link MockBackend}.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/7LWALD?p=preview))
|
||||
*
|
||||
* ```
|
||||
* import {provide, Injector} from 'angular2/angular2';
|
||||
* import {HTTP_PROVIDERS, Http, Response, XHRBackend, MockBackend} from 'angular2/http';
|
||||
*
|
||||
* var people = [{name: 'Jeff'}, {name: 'Tobias'}];
|
||||
*
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* HTTP_PROVIDERS,
|
||||
* MockBackend,
|
||||
* provide(XHRBackend, {useExisting: MockBackend})
|
||||
* ]);
|
||||
* var http = injector.get(Http);
|
||||
* var backend = injector.get(MockBackend);
|
||||
*
|
||||
* // Listen for any new requests
|
||||
* backend.connections.observer({
|
||||
* next: connection => {
|
||||
* var response = new Response({body: people});
|
||||
* setTimeout(() => {
|
||||
* // Send a response to the request
|
||||
* connection.mockRespond(response);
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* http.get('people.json').observer({
|
||||
* next: res => {
|
||||
* // Response came from mock backend
|
||||
* console.log('first person', res.json()[0].name);
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
exports.HTTP_PROVIDERS = [
|
||||
// TODO(pascal): use factory type annotations once supported in DI
|
||||
// issue: https://github.com/angular/angular/issues/3183
|
||||
angular2_1.provide(http_1.Http, {
|
||||
useFactory: function (xhrBackend, requestOptions) { return new http_1.Http(xhrBackend, requestOptions); },
|
||||
deps: [xhr_backend_1.XHRBackend, base_request_options_1.RequestOptions]
|
||||
}),
|
||||
browser_xhr_1.BrowserXhr,
|
||||
angular2_1.provide(base_request_options_1.RequestOptions, { useClass: base_request_options_1.BaseRequestOptions }),
|
||||
angular2_1.provide(base_response_options_1.ResponseOptions, { useClass: base_response_options_1.BaseResponseOptions }),
|
||||
xhr_backend_1.XHRBackend
|
||||
];
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
exports.HTTP_BINDINGS = exports.HTTP_PROVIDERS;
|
||||
/**
|
||||
* Provides a basic set of providers to use the {@link Jsonp} service in any application.
|
||||
*
|
||||
* The `JSONP_PROVIDERS` should be included either in a component's injector,
|
||||
* or in the root injector when bootstrapping an application.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/vmeN4F?p=preview))
|
||||
*
|
||||
* ```
|
||||
* import {Component, NgFor, View} from 'angular2/angular2';
|
||||
* import {JSONP_PROVIDERS, Jsonp} from 'angular2/http';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'app',
|
||||
* providers: [JSONP_PROVIDERS],
|
||||
* template: `
|
||||
* <div>
|
||||
* <h1>People</h1>
|
||||
* <ul>
|
||||
* <li *ng-for="#person of people">
|
||||
* {{person.name}}
|
||||
* </li>
|
||||
* </ul>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [NgFor]
|
||||
* })
|
||||
* export class App {
|
||||
* people: Array<Object>;
|
||||
* constructor(jsonp:Jsonp) {
|
||||
* jsonp.request('people.json').subscribe(res => {
|
||||
* this.people = res.json();
|
||||
* })
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The primary public API included in `JSONP_PROVIDERS` is the {@link Jsonp} class.
|
||||
* However, other providers required by `Jsonp` are included,
|
||||
* which may be beneficial to override in certain cases.
|
||||
*
|
||||
* The providers included in `JSONP_PROVIDERS` include:
|
||||
* * {@link Jsonp}
|
||||
* * {@link JSONPBackend}
|
||||
* * `BrowserJsonp` - Private factory
|
||||
* * {@link RequestOptions} - Bound to {@link BaseRequestOptions} class
|
||||
* * {@link ResponseOptions} - Bound to {@link BaseResponseOptions} class
|
||||
*
|
||||
* There may be cases where it makes sense to extend the base request options,
|
||||
* such as to add a search string to be appended to all URLs.
|
||||
* To accomplish this, a new provider for {@link RequestOptions} should
|
||||
* be added in the same injector as `JSONP_PROVIDERS`.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/TFug7x?p=preview))
|
||||
*
|
||||
* ```
|
||||
* import {provide, bootstrap} from 'angular2/angular2';
|
||||
* import {JSONP_PROVIDERS, BaseRequestOptions, RequestOptions} from 'angular2/http';
|
||||
*
|
||||
* class MyOptions extends BaseRequestOptions {
|
||||
* search: string = 'coreTeam=true';
|
||||
* }
|
||||
*
|
||||
* bootstrap(App, [JSONP_PROVIDERS, provide(RequestOptions, {useClass: MyOptions})])
|
||||
* .catch(err => console.error(err));
|
||||
* ```
|
||||
*
|
||||
* Likewise, to use a mock backend for unit tests, the {@link JSONPBackend}
|
||||
* provider should be bound to {@link MockBackend}.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/HDqZWL?p=preview))
|
||||
*
|
||||
* ```
|
||||
* import {provide, Injector} from 'angular2/angular2';
|
||||
* import {JSONP_PROVIDERS, Jsonp, Response, JSONPBackend, MockBackend} from 'angular2/http';
|
||||
*
|
||||
* var people = [{name: 'Jeff'}, {name: 'Tobias'}];
|
||||
* var injector = Injector.resolveAndCreate([
|
||||
* JSONP_PROVIDERS,
|
||||
* MockBackend,
|
||||
* provide(JSONPBackend, {useExisting: MockBackend})
|
||||
* ]);
|
||||
* var jsonp = injector.get(Jsonp);
|
||||
* var backend = injector.get(MockBackend);
|
||||
*
|
||||
* // Listen for any new requests
|
||||
* backend.connections.observer({
|
||||
* next: connection => {
|
||||
* var response = new Response({body: people});
|
||||
* setTimeout(() => {
|
||||
* // Send a response to the request
|
||||
* connection.mockRespond(response);
|
||||
* });
|
||||
* });
|
||||
|
||||
* jsonp.get('people.json').observer({
|
||||
* next: res => {
|
||||
* // Response came from mock backend
|
||||
* console.log('first person', res.json()[0].name);
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
exports.JSONP_PROVIDERS = [
|
||||
// TODO(pascal): use factory type annotations once supported in DI
|
||||
// issue: https://github.com/angular/angular/issues/3183
|
||||
angular2_1.provide(http_1.Jsonp, {
|
||||
useFactory: function (jsonpBackend, requestOptions) { return new http_1.Jsonp(jsonpBackend, requestOptions); },
|
||||
deps: [jsonp_backend_1.JSONPBackend, base_request_options_1.RequestOptions]
|
||||
}),
|
||||
browser_jsonp_1.BrowserJsonp,
|
||||
angular2_1.provide(base_request_options_1.RequestOptions, { useClass: base_request_options_1.BaseRequestOptions }),
|
||||
angular2_1.provide(base_response_options_1.ResponseOptions, { useClass: base_response_options_1.BaseResponseOptions }),
|
||||
angular2_1.provide(jsonp_backend_1.JSONPBackend, { useClass: jsonp_backend_1.JSONPBackend_ })
|
||||
];
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
exports.JSON_BINDINGS = exports.JSONP_PROVIDERS;
|
||||
//# sourceMappingURL=http.js.map
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Defines interfaces to be implemented by directives when they need to hook into the change
|
||||
* detection mechanism.
|
||||
*/
|
||||
//# sourceMappingURL=lifecycle_hooks.js.map
|
||||
@@ -0,0 +1,11 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
__export(require('./src/mock/mock_location_strategy'));
|
||||
var location_strategy_1 = require('./src/router/location_strategy');
|
||||
exports.LocationStrategy = location_strategy_1.LocationStrategy;
|
||||
var view_resolver_mock_1 = require('angular2/src/mock/view_resolver_mock');
|
||||
exports.MockViewResolver = view_resolver_mock_1.MockViewResolver;
|
||||
var xhr_mock_1 = require('angular2/src/compiler/xhr_mock');
|
||||
exports.MockXHR = xhr_mock_1.MockXHR;
|
||||
//# sourceMappingURL=mock.js.map
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "angular2",
|
||||
"version": "<%= packageJson.version %>",
|
||||
"description": "Angular 2 - a web framework for modern web apps",
|
||||
"homepage": "<%= packageJson.homepage %>",
|
||||
"bugs": "<%= packageJson.bugs %>",
|
||||
"contributors": <%= JSON.stringify(packageJson.contributors) %>,
|
||||
"license": "<%= packageJson.license %>",
|
||||
"repository": <%= JSON.stringify(packageJson.repository) %>,
|
||||
"dependencies": {
|
||||
"reflect-metadata": "<%= packageJson.dependencies['reflect-metadata'] %>",
|
||||
"@reactivex/rxjs": "<%= packageJson.dependencies['@reactivex/rxjs'] %>",
|
||||
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
|
||||
},
|
||||
"devDependencies": <%= JSON.stringify(packageJson.defaultDevDependencies) %>,
|
||||
"typings": "./angular2.d.ts"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
var profile_1 = require('./src/core/profile/profile');
|
||||
exports.wtfCreateScope = profile_1.wtfCreateScope;
|
||||
exports.wtfLeave = profile_1.wtfLeave;
|
||||
exports.wtfStartTimeRange = profile_1.wtfStartTimeRange;
|
||||
exports.wtfEndTimeRange = profile_1.wtfEndTimeRange;
|
||||
//# sourceMappingURL=profile.js.map
|
||||
@@ -0,0 +1,31 @@
|
||||
name: angular2
|
||||
version: <%= packageJson.version %>
|
||||
authors:
|
||||
<%= Object.keys(packageJson.contributors).map(function(name) {
|
||||
return '- '+name+' <'+packageJson.contributors[name]+'>';
|
||||
}).join('\n') %>
|
||||
description: Angular 2 for Dart - a web framework for modern web apps
|
||||
homepage: <%= packageJson.homepage %>
|
||||
environment:
|
||||
sdk: '>=1.10.0 <2.0.0'
|
||||
dependencies:
|
||||
analyzer: '>=0.24.4 <0.27.0'
|
||||
barback: '^0.15.2+2'
|
||||
code_transformers: '^0.2.8'
|
||||
dart_style: '>=0.1.8 <0.3.0'
|
||||
glob: '^1.0.0'
|
||||
html: '^0.12.0'
|
||||
intl: '^0.12.4'
|
||||
logging: '>=0.9.0 <0.12.0'
|
||||
observe: '^0.13.1'
|
||||
protobuf: '^0.5.0'
|
||||
quiver: '^0.21.4'
|
||||
source_span: '^1.0.0'
|
||||
stack_trace: '^1.1.1'
|
||||
dev_dependencies:
|
||||
guinness: '^0.1.18'
|
||||
transformers:
|
||||
- angular2
|
||||
- $dart2js:
|
||||
commandLineOptions:
|
||||
- --show-package-warnings
|
||||
@@ -0,0 +1,11 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
/**
|
||||
* This file is only used for dart applications and for internal examples
|
||||
* that compile with both JavaScript and Dart.
|
||||
*
|
||||
* JavaScript users should import from angular2/core.
|
||||
*/
|
||||
__export(require('./src/core/render'));
|
||||
//# sourceMappingURL=render.js.map
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Maps application URLs into application states, to support deep-linking and navigation.
|
||||
*/
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
var router_1 = require('./src/router/router');
|
||||
exports.Router = router_1.Router;
|
||||
var router_outlet_1 = require('./src/router/router_outlet');
|
||||
exports.RouterOutlet = router_outlet_1.RouterOutlet;
|
||||
var router_link_1 = require('./src/router/router_link');
|
||||
exports.RouterLink = router_link_1.RouterLink;
|
||||
var instruction_1 = require('./src/router/instruction');
|
||||
exports.RouteParams = instruction_1.RouteParams;
|
||||
exports.RouteData = instruction_1.RouteData;
|
||||
var route_registry_1 = require('./src/router/route_registry');
|
||||
exports.RouteRegistry = route_registry_1.RouteRegistry;
|
||||
var location_strategy_1 = require('./src/router/location_strategy');
|
||||
exports.LocationStrategy = location_strategy_1.LocationStrategy;
|
||||
var hash_location_strategy_1 = require('./src/router/hash_location_strategy');
|
||||
exports.HashLocationStrategy = hash_location_strategy_1.HashLocationStrategy;
|
||||
var path_location_strategy_1 = require('./src/router/path_location_strategy');
|
||||
exports.PathLocationStrategy = path_location_strategy_1.PathLocationStrategy;
|
||||
var location_1 = require('./src/router/location');
|
||||
exports.Location = location_1.Location;
|
||||
exports.APP_BASE_HREF = location_1.APP_BASE_HREF;
|
||||
__export(require('./src/router/route_config_decorator'));
|
||||
__export(require('./src/router/route_definition'));
|
||||
var lifecycle_annotations_1 = require('./src/router/lifecycle_annotations');
|
||||
exports.CanActivate = lifecycle_annotations_1.CanActivate;
|
||||
var instruction_2 = require('./src/router/instruction');
|
||||
exports.Instruction = instruction_2.Instruction;
|
||||
exports.ComponentInstruction = instruction_2.ComponentInstruction;
|
||||
var angular2_1 = require('angular2/angular2');
|
||||
exports.OpaqueToken = angular2_1.OpaqueToken;
|
||||
var location_strategy_2 = require('./src/router/location_strategy');
|
||||
var path_location_strategy_2 = require('./src/router/path_location_strategy');
|
||||
var router_2 = require('./src/router/router');
|
||||
var router_outlet_2 = require('./src/router/router_outlet');
|
||||
var router_link_2 = require('./src/router/router_link');
|
||||
var route_registry_2 = require('./src/router/route_registry');
|
||||
var location_2 = require('./src/router/location');
|
||||
var angular2_2 = require('angular2/angular2');
|
||||
var lang_1 = require('./src/facade/lang');
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
/**
|
||||
* Token used to bind the component with the top-level {@link RouteConfig}s for the
|
||||
* application.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
|
||||
*
|
||||
* ```
|
||||
* import {Component} from 'angular2/angular2';
|
||||
* import {
|
||||
* ROUTER_DIRECTIVES,
|
||||
* ROUTER_PROVIDERS,
|
||||
* RouteConfig
|
||||
* } from 'angular2/router';
|
||||
*
|
||||
* @Component({directives: [ROUTER_DIRECTIVES]})
|
||||
* @RouteConfig([
|
||||
* {...},
|
||||
* ])
|
||||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
exports.ROUTER_PRIMARY_COMPONENT = lang_1.CONST_EXPR(new angular2_2.OpaqueToken('RouterPrimaryComponent'));
|
||||
/**
|
||||
* A list of directives. To use the router directives like {@link RouterOutlet} and
|
||||
* {@link RouterLink}, add this to your `directives` array in the {@link View} decorator of your
|
||||
* component.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
|
||||
*
|
||||
* ```
|
||||
* import {Component} from 'angular2/angular2';
|
||||
* import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from 'angular2/router';
|
||||
*
|
||||
* @Component({directives: [ROUTER_DIRECTIVES]})
|
||||
* @RouteConfig([
|
||||
* {...},
|
||||
* ])
|
||||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
exports.ROUTER_DIRECTIVES = lang_1.CONST_EXPR([router_outlet_2.RouterOutlet, router_link_2.RouterLink]);
|
||||
/**
|
||||
* A list of {@link Provider}s. To use the router, you must add this to your application.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
|
||||
*
|
||||
* ```
|
||||
* import {Component} from 'angular2/angular2';
|
||||
* import {
|
||||
* ROUTER_DIRECTIVES,
|
||||
* ROUTER_PROVIDERS,
|
||||
* RouteConfig
|
||||
* } from 'angular2/router';
|
||||
*
|
||||
* @Component({directives: [ROUTER_DIRECTIVES]})
|
||||
* @RouteConfig([
|
||||
* {...},
|
||||
* ])
|
||||
* class AppCmp {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
exports.ROUTER_PROVIDERS = lang_1.CONST_EXPR([
|
||||
route_registry_2.RouteRegistry,
|
||||
lang_1.CONST_EXPR(new angular2_2.Provider(location_strategy_2.LocationStrategy, { useClass: path_location_strategy_2.PathLocationStrategy })),
|
||||
location_2.Location,
|
||||
lang_1.CONST_EXPR(new angular2_2.Provider(router_2.Router, {
|
||||
useFactory: routerFactory,
|
||||
deps: lang_1.CONST_EXPR([route_registry_2.RouteRegistry, location_2.Location, exports.ROUTER_PRIMARY_COMPONENT, angular2_2.ApplicationRef])
|
||||
})),
|
||||
lang_1.CONST_EXPR(new angular2_2.Provider(exports.ROUTER_PRIMARY_COMPONENT, { useFactory: routerPrimaryComponentFactory, deps: lang_1.CONST_EXPR([angular2_2.ApplicationRef]) }))
|
||||
]);
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
exports.ROUTER_BINDINGS = exports.ROUTER_PROVIDERS;
|
||||
function routerFactory(registry, location, primaryComponent, appRef) {
|
||||
var rootRouter = new router_2.RootRouter(registry, location, primaryComponent);
|
||||
appRef.registerDisposeListener(function () { return rootRouter.dispose(); });
|
||||
return rootRouter;
|
||||
}
|
||||
function routerPrimaryComponentFactory(app) {
|
||||
if (app.componentTypes.length == 0) {
|
||||
throw new exceptions_1.BaseException("Bootstrap at least one component before injecting Router.");
|
||||
}
|
||||
return app.componentTypes[0];
|
||||
}
|
||||
//# sourceMappingURL=router.js.map
|
||||
@@ -0,0 +1,182 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var math_1 = require('angular2/src/facade/math');
|
||||
var util_1 = require('angular2/src/core/render/dom/util');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var dom_adapter_1 = require('angular2/src/core/dom/dom_adapter');
|
||||
var Animation = (function () {
|
||||
/**
|
||||
* Stores the start time and starts the animation
|
||||
* @param element
|
||||
* @param data
|
||||
* @param browserDetails
|
||||
*/
|
||||
function Animation(element, data, browserDetails) {
|
||||
var _this = this;
|
||||
this.element = element;
|
||||
this.data = data;
|
||||
this.browserDetails = browserDetails;
|
||||
/** functions to be called upon completion */
|
||||
this.callbacks = [];
|
||||
/** functions for removing event listeners */
|
||||
this.eventClearFunctions = [];
|
||||
/** flag used to track whether or not the animation has finished */
|
||||
this.completed = false;
|
||||
this._stringPrefix = '';
|
||||
this.startTime = lang_1.DateWrapper.toMillis(lang_1.DateWrapper.now());
|
||||
this._stringPrefix = dom_adapter_1.DOM.getAnimationPrefix();
|
||||
this.setup();
|
||||
this.wait(function (timestamp) { return _this.start(); });
|
||||
}
|
||||
Object.defineProperty(Animation.prototype, "totalTime", {
|
||||
/** total amount of time that the animation should take including delay */
|
||||
get: function () {
|
||||
var delay = this.computedDelay != null ? this.computedDelay : 0;
|
||||
var duration = this.computedDuration != null ? this.computedDuration : 0;
|
||||
return delay + duration;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Animation.prototype.wait = function (callback) {
|
||||
// Firefox requires 2 frames for some reason
|
||||
this.browserDetails.raf(callback, 2);
|
||||
};
|
||||
/**
|
||||
* Sets up the initial styles before the animation is started
|
||||
*/
|
||||
Animation.prototype.setup = function () {
|
||||
if (this.data.fromStyles != null)
|
||||
this.applyStyles(this.data.fromStyles);
|
||||
if (this.data.duration != null)
|
||||
this.applyStyles({ 'transitionDuration': this.data.duration.toString() + 'ms' });
|
||||
if (this.data.delay != null)
|
||||
this.applyStyles({ 'transitionDelay': this.data.delay.toString() + 'ms' });
|
||||
};
|
||||
/**
|
||||
* After the initial setup has occurred, this method adds the animation styles
|
||||
*/
|
||||
Animation.prototype.start = function () {
|
||||
this.addClasses(this.data.classesToAdd);
|
||||
this.addClasses(this.data.animationClasses);
|
||||
this.removeClasses(this.data.classesToRemove);
|
||||
if (this.data.toStyles != null)
|
||||
this.applyStyles(this.data.toStyles);
|
||||
var computedStyles = dom_adapter_1.DOM.getComputedStyle(this.element);
|
||||
this.computedDelay =
|
||||
math_1.Math.max(this.parseDurationString(computedStyles.getPropertyValue(this._stringPrefix + 'transition-delay')), this.parseDurationString(this.element.style.getPropertyValue(this._stringPrefix + 'transition-delay')));
|
||||
this.computedDuration = math_1.Math.max(this.parseDurationString(computedStyles.getPropertyValue(this._stringPrefix + 'transition-duration')), this.parseDurationString(this.element.style.getPropertyValue(this._stringPrefix + 'transition-duration')));
|
||||
this.addEvents();
|
||||
};
|
||||
/**
|
||||
* Applies the provided styles to the element
|
||||
* @param styles
|
||||
*/
|
||||
Animation.prototype.applyStyles = function (styles) {
|
||||
var _this = this;
|
||||
collection_1.StringMapWrapper.forEach(styles, function (value, key) {
|
||||
var dashCaseKey = util_1.camelCaseToDashCase(key);
|
||||
if (lang_1.isPresent(dom_adapter_1.DOM.getStyle(_this.element, dashCaseKey))) {
|
||||
dom_adapter_1.DOM.setStyle(_this.element, dashCaseKey, value.toString());
|
||||
}
|
||||
else {
|
||||
dom_adapter_1.DOM.setStyle(_this.element, _this._stringPrefix + dashCaseKey, value.toString());
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Adds the provided classes to the element
|
||||
* @param classes
|
||||
*/
|
||||
Animation.prototype.addClasses = function (classes) {
|
||||
for (var i = 0, len = classes.length; i < len; i++)
|
||||
dom_adapter_1.DOM.addClass(this.element, classes[i]);
|
||||
};
|
||||
/**
|
||||
* Removes the provided classes from the element
|
||||
* @param classes
|
||||
*/
|
||||
Animation.prototype.removeClasses = function (classes) {
|
||||
for (var i = 0, len = classes.length; i < len; i++)
|
||||
dom_adapter_1.DOM.removeClass(this.element, classes[i]);
|
||||
};
|
||||
/**
|
||||
* Adds events to track when animations have finished
|
||||
*/
|
||||
Animation.prototype.addEvents = function () {
|
||||
var _this = this;
|
||||
if (this.totalTime > 0) {
|
||||
this.eventClearFunctions.push(dom_adapter_1.DOM.onAndCancel(this.element, dom_adapter_1.DOM.getTransitionEnd(), function (event) { return _this.handleAnimationEvent(event); }));
|
||||
}
|
||||
else {
|
||||
this.handleAnimationCompleted();
|
||||
}
|
||||
};
|
||||
Animation.prototype.handleAnimationEvent = function (event) {
|
||||
var elapsedTime = math_1.Math.round(event.elapsedTime * 1000);
|
||||
if (!this.browserDetails.elapsedTimeIncludesDelay)
|
||||
elapsedTime += this.computedDelay;
|
||||
event.stopPropagation();
|
||||
if (elapsedTime >= this.totalTime)
|
||||
this.handleAnimationCompleted();
|
||||
};
|
||||
/**
|
||||
* Runs all animation callbacks and removes temporary classes
|
||||
*/
|
||||
Animation.prototype.handleAnimationCompleted = function () {
|
||||
this.removeClasses(this.data.animationClasses);
|
||||
this.callbacks.forEach(function (callback) { return callback(); });
|
||||
this.callbacks = [];
|
||||
this.eventClearFunctions.forEach(function (fn) { return fn(); });
|
||||
this.eventClearFunctions = [];
|
||||
this.completed = true;
|
||||
};
|
||||
/**
|
||||
* Adds animation callbacks to be called upon completion
|
||||
* @param callback
|
||||
* @returns {Animation}
|
||||
*/
|
||||
Animation.prototype.onComplete = function (callback) {
|
||||
if (this.completed) {
|
||||
callback();
|
||||
}
|
||||
else {
|
||||
this.callbacks.push(callback);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Converts the duration string to the number of milliseconds
|
||||
* @param duration
|
||||
* @returns {number}
|
||||
*/
|
||||
Animation.prototype.parseDurationString = function (duration) {
|
||||
var maxValue = 0;
|
||||
// duration must have at least 2 characters to be valid. (number + type)
|
||||
if (duration == null || duration.length < 2) {
|
||||
return maxValue;
|
||||
}
|
||||
else if (duration.substring(duration.length - 2) == 'ms') {
|
||||
var value = lang_1.NumberWrapper.parseInt(this.stripLetters(duration), 10);
|
||||
if (value > maxValue)
|
||||
maxValue = value;
|
||||
}
|
||||
else if (duration.substring(duration.length - 1) == 's') {
|
||||
var ms = lang_1.NumberWrapper.parseFloat(this.stripLetters(duration)) * 1000;
|
||||
var value = math_1.Math.floor(ms);
|
||||
if (value > maxValue)
|
||||
maxValue = value;
|
||||
}
|
||||
return maxValue;
|
||||
};
|
||||
/**
|
||||
* Strips the letters from the duration string
|
||||
* @param str
|
||||
* @returns {string}
|
||||
*/
|
||||
Animation.prototype.stripLetters = function (str) {
|
||||
return lang_1.StringWrapper.replaceAll(str, lang_1.RegExpWrapper.create('[^0-9]+$', ''), '');
|
||||
};
|
||||
return Animation;
|
||||
})();
|
||||
exports.Animation = Animation;
|
||||
//# sourceMappingURL=animation.js.map
|
||||
@@ -0,0 +1,35 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var css_animation_builder_1 = require('./css_animation_builder');
|
||||
var browser_details_1 = require('./browser_details');
|
||||
var AnimationBuilder = (function () {
|
||||
/**
|
||||
* Used for DI
|
||||
* @param browserDetails
|
||||
*/
|
||||
function AnimationBuilder(browserDetails) {
|
||||
this.browserDetails = browserDetails;
|
||||
}
|
||||
/**
|
||||
* Creates a new CSS Animation
|
||||
* @returns {CssAnimationBuilder}
|
||||
*/
|
||||
AnimationBuilder.prototype.css = function () { return new css_animation_builder_1.CssAnimationBuilder(this.browserDetails); };
|
||||
AnimationBuilder = __decorate([
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [browser_details_1.BrowserDetails])
|
||||
], AnimationBuilder);
|
||||
return AnimationBuilder;
|
||||
})();
|
||||
exports.AnimationBuilder = AnimationBuilder;
|
||||
//# sourceMappingURL=animation_builder.js.map
|
||||
@@ -0,0 +1,75 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var math_1 = require('angular2/src/facade/math');
|
||||
var dom_adapter_1 = require('angular2/src/core/dom/dom_adapter');
|
||||
var BrowserDetails = (function () {
|
||||
function BrowserDetails() {
|
||||
this.elapsedTimeIncludesDelay = false;
|
||||
this.doesElapsedTimeIncludesDelay();
|
||||
}
|
||||
/**
|
||||
* Determines if `event.elapsedTime` includes transition delay in the current browser. At this
|
||||
* time, Chrome and Opera seem to be the only browsers that include this.
|
||||
*/
|
||||
BrowserDetails.prototype.doesElapsedTimeIncludesDelay = function () {
|
||||
var _this = this;
|
||||
var div = dom_adapter_1.DOM.createElement('div');
|
||||
dom_adapter_1.DOM.setAttribute(div, 'style', "position: absolute; top: -9999px; left: -9999px; width: 1px;\n height: 1px; transition: all 1ms linear 1ms;");
|
||||
// Firefox requires that we wait for 2 frames for some reason
|
||||
this.raf(function (timestamp) {
|
||||
dom_adapter_1.DOM.on(div, 'transitionend', function (event) {
|
||||
var elapsed = math_1.Math.round(event.elapsedTime * 1000);
|
||||
_this.elapsedTimeIncludesDelay = elapsed == 2;
|
||||
dom_adapter_1.DOM.remove(div);
|
||||
});
|
||||
dom_adapter_1.DOM.setStyle(div, 'width', '2px');
|
||||
}, 2);
|
||||
};
|
||||
BrowserDetails.prototype.raf = function (callback, frames) {
|
||||
if (frames === void 0) { frames = 1; }
|
||||
var queue = new RafQueue(callback, frames);
|
||||
return function () { return queue.cancel(); };
|
||||
};
|
||||
BrowserDetails = __decorate([
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], BrowserDetails);
|
||||
return BrowserDetails;
|
||||
})();
|
||||
exports.BrowserDetails = BrowserDetails;
|
||||
var RafQueue = (function () {
|
||||
function RafQueue(callback, frames) {
|
||||
this.callback = callback;
|
||||
this.frames = frames;
|
||||
this._raf();
|
||||
}
|
||||
RafQueue.prototype._raf = function () {
|
||||
var _this = this;
|
||||
this.currentFrameId = dom_adapter_1.DOM.requestAnimationFrame(function (timestamp) { return _this._nextFrame(timestamp); });
|
||||
};
|
||||
RafQueue.prototype._nextFrame = function (timestamp) {
|
||||
this.frames--;
|
||||
if (this.frames > 0) {
|
||||
this._raf();
|
||||
}
|
||||
else {
|
||||
this.callback(timestamp);
|
||||
}
|
||||
};
|
||||
RafQueue.prototype.cancel = function () {
|
||||
dom_adapter_1.DOM.cancelAnimationFrame(this.currentFrameId);
|
||||
this.currentFrameId = null;
|
||||
};
|
||||
return RafQueue;
|
||||
})();
|
||||
//# sourceMappingURL=browser_details.js.map
|
||||
@@ -0,0 +1,86 @@
|
||||
var css_animation_options_1 = require('./css_animation_options');
|
||||
var animation_1 = require('./animation');
|
||||
var CssAnimationBuilder = (function () {
|
||||
/**
|
||||
* Accepts public properties for CssAnimationBuilder
|
||||
*/
|
||||
function CssAnimationBuilder(browserDetails) {
|
||||
this.browserDetails = browserDetails;
|
||||
/** @type {CssAnimationOptions} */
|
||||
this.data = new css_animation_options_1.CssAnimationOptions();
|
||||
}
|
||||
/**
|
||||
* Adds a temporary class that will be removed at the end of the animation
|
||||
* @param className
|
||||
*/
|
||||
CssAnimationBuilder.prototype.addAnimationClass = function (className) {
|
||||
this.data.animationClasses.push(className);
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Adds a class that will remain on the element after the animation has finished
|
||||
* @param className
|
||||
*/
|
||||
CssAnimationBuilder.prototype.addClass = function (className) {
|
||||
this.data.classesToAdd.push(className);
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Removes a class from the element
|
||||
* @param className
|
||||
*/
|
||||
CssAnimationBuilder.prototype.removeClass = function (className) {
|
||||
this.data.classesToRemove.push(className);
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Sets the animation duration (and overrides any defined through CSS)
|
||||
* @param duration
|
||||
*/
|
||||
CssAnimationBuilder.prototype.setDuration = function (duration) {
|
||||
this.data.duration = duration;
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Sets the animation delay (and overrides any defined through CSS)
|
||||
* @param delay
|
||||
*/
|
||||
CssAnimationBuilder.prototype.setDelay = function (delay) {
|
||||
this.data.delay = delay;
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Sets styles for both the initial state and the destination state
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
CssAnimationBuilder.prototype.setStyles = function (from, to) {
|
||||
return this.setFromStyles(from).setToStyles(to);
|
||||
};
|
||||
/**
|
||||
* Sets the initial styles for the animation
|
||||
* @param from
|
||||
*/
|
||||
CssAnimationBuilder.prototype.setFromStyles = function (from) {
|
||||
this.data.fromStyles = from;
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Sets the destination styles for the animation
|
||||
* @param to
|
||||
*/
|
||||
CssAnimationBuilder.prototype.setToStyles = function (to) {
|
||||
this.data.toStyles = to;
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Starts the animation and returns a promise
|
||||
* @param element
|
||||
*/
|
||||
CssAnimationBuilder.prototype.start = function (element) {
|
||||
return new animation_1.Animation(element, this.data, this.browserDetails);
|
||||
};
|
||||
return CssAnimationBuilder;
|
||||
})();
|
||||
exports.CssAnimationBuilder = CssAnimationBuilder;
|
||||
//# sourceMappingURL=css_animation_builder.js.map
|
||||
@@ -0,0 +1,13 @@
|
||||
var CssAnimationOptions = (function () {
|
||||
function CssAnimationOptions() {
|
||||
/** classes to be added to the element */
|
||||
this.classesToAdd = [];
|
||||
/** classes to be removed from the element */
|
||||
this.classesToRemove = [];
|
||||
/** classes to be added for the duration of the animation */
|
||||
this.animationClasses = [];
|
||||
}
|
||||
return CssAnimationOptions;
|
||||
})();
|
||||
exports.CssAnimationOptions = CssAnimationOptions;
|
||||
//# sourceMappingURL=css_animation_options.js.map
|
||||
@@ -0,0 +1,48 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var forms_1 = require('./forms');
|
||||
var directives_1 = require('./directives');
|
||||
/**
|
||||
* A collection of Angular core directives that are likely to be used in each and every Angular
|
||||
* application. This includes core directives (e.g., NgIf and NgFor), and forms directives (e.g.,
|
||||
* NgModel).
|
||||
*
|
||||
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
|
||||
* property of the `@Component` or `@View` decorators.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* Instead of writing:
|
||||
*
|
||||
* ```typescript
|
||||
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm} from
|
||||
* 'angular2/angular2';
|
||||
* import {OtherDirective} from './myDirectives';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* templateUrl: 'myComponent.html',
|
||||
* directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm,
|
||||
* OtherDirective]
|
||||
* })
|
||||
* export class MyComponent {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
* one could import all the common directives at once:
|
||||
*
|
||||
* ```typescript
|
||||
* import {COMMON_DIRECTIVES} from 'angular2/angular2';
|
||||
* import {OtherDirective} from './myDirectives';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* templateUrl: 'myComponent.html',
|
||||
* directives: [COMMON_DIRECTIVES, OtherDirective]
|
||||
* })
|
||||
* export class MyComponent {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
exports.COMMON_DIRECTIVES = lang_1.CONST_EXPR([directives_1.CORE_DIRECTIVES, forms_1.FORM_DIRECTIVES]);
|
||||
//# sourceMappingURL=common_directives.js.map
|
||||
@@ -0,0 +1,24 @@
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* Common directives shipped with Angular.
|
||||
*/
|
||||
var ng_class_1 = require('./directives/ng_class');
|
||||
exports.NgClass = ng_class_1.NgClass;
|
||||
var ng_for_1 = require('./directives/ng_for');
|
||||
exports.NgFor = ng_for_1.NgFor;
|
||||
var ng_if_1 = require('./directives/ng_if');
|
||||
exports.NgIf = ng_if_1.NgIf;
|
||||
var ng_style_1 = require('./directives/ng_style');
|
||||
exports.NgStyle = ng_style_1.NgStyle;
|
||||
var ng_switch_1 = require('./directives/ng_switch');
|
||||
exports.NgSwitch = ng_switch_1.NgSwitch;
|
||||
exports.NgSwitchWhen = ng_switch_1.NgSwitchWhen;
|
||||
exports.NgSwitchDefault = ng_switch_1.NgSwitchDefault;
|
||||
__export(require('./directives/observable_list_diff'));
|
||||
var core_directives_1 = require('./directives/core_directives');
|
||||
exports.CORE_DIRECTIVES = core_directives_1.CORE_DIRECTIVES;
|
||||
//# sourceMappingURL=directives.js.map
|
||||
@@ -0,0 +1,48 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var ng_class_1 = require('./ng_class');
|
||||
var ng_for_1 = require('./ng_for');
|
||||
var ng_if_1 = require('./ng_if');
|
||||
var ng_style_1 = require('./ng_style');
|
||||
var ng_switch_1 = require('./ng_switch');
|
||||
/**
|
||||
* A collection of Angular core directives that are likely to be used in each and every Angular
|
||||
* application.
|
||||
*
|
||||
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
|
||||
* property of the `@View` annotation.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/yakGwpCdUkg0qfzX5m8g?p=preview))
|
||||
*
|
||||
* Instead of writing:
|
||||
*
|
||||
* ```typescript
|
||||
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from 'angular2/angular2';
|
||||
* import {OtherDirective} from './myDirectives';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* templateUrl: 'myComponent.html',
|
||||
* directives: [NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, OtherDirective]
|
||||
* })
|
||||
* export class MyComponent {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
* one could import all the core directives at once:
|
||||
*
|
||||
* ```typescript
|
||||
* import {CORE_DIRECTIVES} from 'angular2/angular2';
|
||||
* import {OtherDirective} from './myDirectives';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'my-component',
|
||||
* templateUrl: 'myComponent.html',
|
||||
* directives: [CORE_DIRECTIVES, OtherDirective]
|
||||
* })
|
||||
* export class MyComponent {
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
exports.CORE_DIRECTIVES = lang_1.CONST_EXPR([ng_class_1.NgClass, ng_for_1.NgFor, ng_if_1.NgIf, ng_style_1.NgStyle, ng_switch_1.NgSwitch, ng_switch_1.NgSwitchWhen, ng_switch_1.NgSwitchDefault]);
|
||||
//# sourceMappingURL=core_directives.js.map
|
||||
@@ -0,0 +1,185 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var change_detection_1 = require('angular2/src/core/change_detection');
|
||||
var render_1 = require('angular2/src/core/render');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
/**
|
||||
* The `NgClass` directive conditionally adds and removes CSS classes on an HTML element based on
|
||||
* an expression's evaluation result.
|
||||
*
|
||||
* The result of an expression evaluation is interpreted differently depending on type of
|
||||
* the expression evaluation result:
|
||||
* - `string` - all the CSS classes listed in a string (space delimited) are added
|
||||
* - `Array` - all the CSS classes (Array elements) are added
|
||||
* - `Object` - each key corresponds to a CSS class name while values are interpreted as expressions
|
||||
* evaluating to `Boolean`. If a given expression evaluates to `true` a corresponding CSS class
|
||||
* is added - otherwise it is removed.
|
||||
*
|
||||
* While the `NgClass` directive can interpret expressions evaluating to `string`, `Array`
|
||||
* or `Object`, the `Object`-based version is the most often used and has an advantage of keeping
|
||||
* all the CSS class names in a template.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/a4YdtmWywhJ33uqfpPPn?p=preview)):
|
||||
*
|
||||
* ```
|
||||
* import {Component, NgClass} from 'angular2/angular2';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'toggle-button',
|
||||
* inputs: ['isDisabled'],
|
||||
* template: `
|
||||
* <div class="button" [ng-class]="{active: isOn, disabled: isDisabled}"
|
||||
* (click)="toggle(!isOn)">
|
||||
* Click me!
|
||||
* </div>`,
|
||||
* styles: [`
|
||||
* .button {
|
||||
* width: 120px;
|
||||
* border: medium solid black;
|
||||
* }
|
||||
*
|
||||
* .active {
|
||||
* background-color: red;
|
||||
* }
|
||||
*
|
||||
* .disabled {
|
||||
* color: gray;
|
||||
* border: medium solid gray;
|
||||
* }
|
||||
* `]
|
||||
* directives: [NgClass]
|
||||
* })
|
||||
* class ToggleButton {
|
||||
* isOn = false;
|
||||
* isDisabled = false;
|
||||
*
|
||||
* toggle(newState) {
|
||||
* if (!this.isDisabled) {
|
||||
* this.isOn = newState;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var NgClass = (function () {
|
||||
function NgClass(_iterableDiffers, _keyValueDiffers, _ngEl, _renderer) {
|
||||
this._iterableDiffers = _iterableDiffers;
|
||||
this._keyValueDiffers = _keyValueDiffers;
|
||||
this._ngEl = _ngEl;
|
||||
this._renderer = _renderer;
|
||||
this._initialClasses = [];
|
||||
}
|
||||
Object.defineProperty(NgClass.prototype, "initialClasses", {
|
||||
set: function (v) {
|
||||
this._applyInitialClasses(true);
|
||||
this._initialClasses = lang_1.isPresent(v) && lang_1.isString(v) ? v.split(' ') : [];
|
||||
this._applyInitialClasses(false);
|
||||
this._applyClasses(this._rawClass, false);
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgClass.prototype, "rawClass", {
|
||||
set: function (v) {
|
||||
this._cleanupClasses(this._rawClass);
|
||||
if (lang_1.isString(v)) {
|
||||
v = v.split(' ');
|
||||
}
|
||||
this._rawClass = v;
|
||||
if (lang_1.isPresent(v)) {
|
||||
if (collection_1.isListLikeIterable(v)) {
|
||||
this._differ = this._iterableDiffers.find(v).create(null);
|
||||
this._mode = 'iterable';
|
||||
}
|
||||
else {
|
||||
this._differ = this._keyValueDiffers.find(v).create(null);
|
||||
this._mode = 'keyValue';
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._differ = null;
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgClass.prototype.doCheck = function () {
|
||||
if (lang_1.isPresent(this._differ)) {
|
||||
var changes = this._differ.diff(this._rawClass);
|
||||
if (lang_1.isPresent(changes)) {
|
||||
if (this._mode == 'iterable') {
|
||||
this._applyIterableChanges(changes);
|
||||
}
|
||||
else {
|
||||
this._applyKeyValueChanges(changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
NgClass.prototype.onDestroy = function () { this._cleanupClasses(this._rawClass); };
|
||||
NgClass.prototype._cleanupClasses = function (rawClassVal) {
|
||||
this._applyClasses(rawClassVal, true);
|
||||
this._applyInitialClasses(false);
|
||||
};
|
||||
NgClass.prototype._applyKeyValueChanges = function (changes) {
|
||||
var _this = this;
|
||||
changes.forEachAddedItem(function (record) { _this._toggleClass(record.key, record.currentValue); });
|
||||
changes.forEachChangedItem(function (record) { _this._toggleClass(record.key, record.currentValue); });
|
||||
changes.forEachRemovedItem(function (record) {
|
||||
if (record.previousValue) {
|
||||
_this._toggleClass(record.key, false);
|
||||
}
|
||||
});
|
||||
};
|
||||
NgClass.prototype._applyIterableChanges = function (changes) {
|
||||
var _this = this;
|
||||
changes.forEachAddedItem(function (record) { _this._toggleClass(record.item, true); });
|
||||
changes.forEachRemovedItem(function (record) { _this._toggleClass(record.item, false); });
|
||||
};
|
||||
NgClass.prototype._applyInitialClasses = function (isCleanup) {
|
||||
var _this = this;
|
||||
this._initialClasses.forEach(function (className) { return _this._toggleClass(className, !isCleanup); });
|
||||
};
|
||||
NgClass.prototype._applyClasses = function (rawClassVal, isCleanup) {
|
||||
var _this = this;
|
||||
if (lang_1.isPresent(rawClassVal)) {
|
||||
if (lang_1.isArray(rawClassVal)) {
|
||||
rawClassVal.forEach(function (className) { return _this._toggleClass(className, !isCleanup); });
|
||||
}
|
||||
else if (rawClassVal instanceof Set) {
|
||||
rawClassVal.forEach(function (className) { return _this._toggleClass(className, !isCleanup); });
|
||||
}
|
||||
else {
|
||||
collection_1.StringMapWrapper.forEach(rawClassVal, function (expVal, className) {
|
||||
if (expVal)
|
||||
_this._toggleClass(className, !isCleanup);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
NgClass.prototype._toggleClass = function (className, enabled) {
|
||||
className = className.trim();
|
||||
if (className.length > 0) {
|
||||
this._renderer.setElementClass(this._ngEl, className, enabled);
|
||||
}
|
||||
};
|
||||
NgClass = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-class]', inputs: ['rawClass: ng-class', 'initialClasses: class'] }),
|
||||
__metadata('design:paramtypes', [change_detection_1.IterableDiffers, change_detection_1.KeyValueDiffers, linker_1.ElementRef, render_1.Renderer])
|
||||
], NgClass);
|
||||
return NgClass;
|
||||
})();
|
||||
exports.NgClass = NgClass;
|
||||
//# sourceMappingURL=ng_class.js.map
|
||||
@@ -0,0 +1,170 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var change_detection_1 = require('angular2/src/core/change_detection');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
/**
|
||||
* The `NgFor` directive instantiates a template once per item from an iterable. The context for
|
||||
* each instantiated template inherits from the outer context with the given loop variable set
|
||||
* to the current item from the iterable.
|
||||
*
|
||||
* # Local Variables
|
||||
*
|
||||
* `NgFor` provides several exported values that can be aliased to local variables:
|
||||
*
|
||||
* * `index` will be set to the current loop iteration for each template context.
|
||||
* * `last` will be set to a boolean value indicating whether the item is the last one in the
|
||||
* iteration.
|
||||
* * `even` will be set to a boolean value indicating whether this item has an even index.
|
||||
* * `odd` will be set to a boolean value indicating whether this item has an odd index.
|
||||
*
|
||||
* # Change Propagation
|
||||
*
|
||||
* When the contents of the iterator changes, `NgFor` makes the corresponding changes to the DOM:
|
||||
*
|
||||
* * When an item is added, a new instance of the template is added to the DOM.
|
||||
* * When an item is removed, its template instance is removed from the DOM.
|
||||
* * When items are reordered, their respective templates are reordered in the DOM.
|
||||
* * Otherwise, the DOM element for that item will remain the same.
|
||||
*
|
||||
* Angular uses object identity to track insertions and deletions within the iterator and reproduce
|
||||
* those changes in the DOM. This has important implications for animations and any stateful
|
||||
* controls
|
||||
* (such as `<input>` elements which accept user input) that are present. Inserted rows can be
|
||||
* animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state such
|
||||
* as user input.
|
||||
*
|
||||
* It is possible for the identities of elements in the iterator to change while the data does not.
|
||||
* This can happen, for example, if the iterator produced from an RPC to the server, and that
|
||||
* RPC is re-run. Even if the data hasn't changed, the second response will produce objects with
|
||||
* different identities, and Angular will tear down the entire DOM and rebuild it (as if all old
|
||||
* elements were deleted and all new elements inserted). This is an expensive operation and should
|
||||
* be avoided if possible.
|
||||
*
|
||||
* # Syntax
|
||||
*
|
||||
* - `<li *ng-for="#item of items; #i = index">...</li>`
|
||||
* - `<li template="ng-for #item of items; #i = index">...</li>`
|
||||
* - `<template ng-for #item [ng-for-of]="items" #i="index"><li>...</li></template>`
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* See a [live demo](http://plnkr.co/edit/KVuXxDp0qinGDyo307QW?p=preview) for a more detailed
|
||||
* example.
|
||||
*/
|
||||
var NgFor = (function () {
|
||||
function NgFor(_viewContainer, _templateRef, _iterableDiffers, _cdr) {
|
||||
this._viewContainer = _viewContainer;
|
||||
this._templateRef = _templateRef;
|
||||
this._iterableDiffers = _iterableDiffers;
|
||||
this._cdr = _cdr;
|
||||
}
|
||||
Object.defineProperty(NgFor.prototype, "ngForOf", {
|
||||
set: function (value) {
|
||||
this._ngForOf = value;
|
||||
if (lang_1.isBlank(this._differ) && lang_1.isPresent(value)) {
|
||||
this._differ = this._iterableDiffers.find(value).create(this._cdr);
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgFor.prototype, "ngForTemplate", {
|
||||
set: function (value) {
|
||||
if (lang_1.isPresent(value)) {
|
||||
this._templateRef = value;
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgFor.prototype.doCheck = function () {
|
||||
if (lang_1.isPresent(this._differ)) {
|
||||
var changes = this._differ.diff(this._ngForOf);
|
||||
if (lang_1.isPresent(changes))
|
||||
this._applyChanges(changes);
|
||||
}
|
||||
};
|
||||
NgFor.prototype._applyChanges = function (changes) {
|
||||
// TODO(rado): check if change detection can produce a change record that is
|
||||
// easier to consume than current.
|
||||
var recordViewTuples = [];
|
||||
changes.forEachRemovedItem(function (removedRecord) {
|
||||
return recordViewTuples.push(new RecordViewTuple(removedRecord, null));
|
||||
});
|
||||
changes.forEachMovedItem(function (movedRecord) {
|
||||
return recordViewTuples.push(new RecordViewTuple(movedRecord, null));
|
||||
});
|
||||
var insertTuples = this._bulkRemove(recordViewTuples);
|
||||
changes.forEachAddedItem(function (addedRecord) {
|
||||
return insertTuples.push(new RecordViewTuple(addedRecord, null));
|
||||
});
|
||||
this._bulkInsert(insertTuples);
|
||||
for (var i = 0; i < insertTuples.length; i++) {
|
||||
this._perViewChange(insertTuples[i].view, insertTuples[i].record);
|
||||
}
|
||||
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
|
||||
this._viewContainer.get(i).setLocal('last', i === ilen - 1);
|
||||
}
|
||||
};
|
||||
NgFor.prototype._perViewChange = function (view, record) {
|
||||
view.setLocal('\$implicit', record.item);
|
||||
view.setLocal('index', record.currentIndex);
|
||||
view.setLocal('even', (record.currentIndex % 2 == 0));
|
||||
view.setLocal('odd', (record.currentIndex % 2 == 1));
|
||||
};
|
||||
NgFor.prototype._bulkRemove = function (tuples) {
|
||||
tuples.sort(function (a, b) { return a.record.previousIndex - b.record.previousIndex; });
|
||||
var movedTuples = [];
|
||||
for (var i = tuples.length - 1; i >= 0; i--) {
|
||||
var tuple = tuples[i];
|
||||
// separate moved views from removed views.
|
||||
if (lang_1.isPresent(tuple.record.currentIndex)) {
|
||||
tuple.view = this._viewContainer.detach(tuple.record.previousIndex);
|
||||
movedTuples.push(tuple);
|
||||
}
|
||||
else {
|
||||
this._viewContainer.remove(tuple.record.previousIndex);
|
||||
}
|
||||
}
|
||||
return movedTuples;
|
||||
};
|
||||
NgFor.prototype._bulkInsert = function (tuples) {
|
||||
tuples.sort(function (a, b) { return a.record.currentIndex - b.record.currentIndex; });
|
||||
for (var i = 0; i < tuples.length; i++) {
|
||||
var tuple = tuples[i];
|
||||
if (lang_1.isPresent(tuple.view)) {
|
||||
this._viewContainer.insert(tuple.view, tuple.record.currentIndex);
|
||||
}
|
||||
else {
|
||||
tuple.view =
|
||||
this._viewContainer.createEmbeddedView(this._templateRef, tuple.record.currentIndex);
|
||||
}
|
||||
}
|
||||
return tuples;
|
||||
};
|
||||
NgFor = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-for][ng-for-of]', inputs: ['ngForOf', 'ngForTemplate'] }),
|
||||
__metadata('design:paramtypes', [linker_1.ViewContainerRef, linker_1.TemplateRef, change_detection_1.IterableDiffers, change_detection_1.ChangeDetectorRef])
|
||||
], NgFor);
|
||||
return NgFor;
|
||||
})();
|
||||
exports.NgFor = NgFor;
|
||||
var RecordViewTuple = (function () {
|
||||
function RecordViewTuple(record, view) {
|
||||
this.record = record;
|
||||
this.view = view;
|
||||
}
|
||||
return RecordViewTuple;
|
||||
})();
|
||||
//# sourceMappingURL=ng_for.js.map
|
||||
@@ -0,0 +1,64 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
/**
|
||||
* Removes or recreates a portion of the DOM tree based on an {expression}.
|
||||
*
|
||||
* If the expression assigned to `ng-if` evaluates to a false value then the element
|
||||
* is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)):
|
||||
*
|
||||
* ```
|
||||
* <div *ng-if="errorCount > 0" class="error">
|
||||
* <!-- Error message displayed when the errorCount property on the current context is greater
|
||||
* than 0. -->
|
||||
* {{errorCount}} errors detected
|
||||
* </div>
|
||||
* ```
|
||||
*
|
||||
*##Syntax
|
||||
*
|
||||
* - `<div *ng-if="condition">...</div>`
|
||||
* - `<div template="ng-if condition">...</div>`
|
||||
* - `<template [ng-if]="condition"><div>...</div></template>`
|
||||
*/
|
||||
var NgIf = (function () {
|
||||
function NgIf(_viewContainer, _templateRef) {
|
||||
this._viewContainer = _viewContainer;
|
||||
this._templateRef = _templateRef;
|
||||
this._prevCondition = null;
|
||||
}
|
||||
Object.defineProperty(NgIf.prototype, "ngIf", {
|
||||
set: function (newCondition /* boolean */) {
|
||||
if (newCondition && (lang_1.isBlank(this._prevCondition) || !this._prevCondition)) {
|
||||
this._prevCondition = true;
|
||||
this._viewContainer.createEmbeddedView(this._templateRef);
|
||||
}
|
||||
else if (!newCondition && (lang_1.isBlank(this._prevCondition) || this._prevCondition)) {
|
||||
this._prevCondition = false;
|
||||
this._viewContainer.clear();
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgIf = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-if]', inputs: ['ngIf'] }),
|
||||
__metadata('design:paramtypes', [linker_1.ViewContainerRef, linker_1.TemplateRef])
|
||||
], NgIf);
|
||||
return NgIf;
|
||||
})();
|
||||
exports.NgIf = NgIf;
|
||||
//# sourceMappingURL=ng_if.js.map
|
||||
@@ -0,0 +1,107 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var change_detection_1 = require('angular2/src/core/change_detection');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var render_1 = require('angular2/src/core/render');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
/**
|
||||
* The `NgStyle` directive changes styles based on a result of expression evaluation.
|
||||
*
|
||||
* An expression assigned to the `ng-style` property must evaluate to an object and the
|
||||
* corresponding element styles are updated based on changes to this object. Style names to update
|
||||
* are taken from the object's keys, and values - from the corresponding object's values.
|
||||
*
|
||||
*##Syntax
|
||||
*
|
||||
* - `<div [ng-style]="{'font-style': style}"></div>`
|
||||
* - `<div [ng-style]="styleExp"></div>` - here the `styleExp` must evaluate to an object
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/YamGS6GkUh9GqWNQhCyM?p=preview)):
|
||||
*
|
||||
* ```
|
||||
* import {Component, NgStyle} from 'angular2/angular2';
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'ng-style-example',
|
||||
* template: `
|
||||
* <h1 [ng-style]="{'font-style': style, 'font-size': size, 'font-weight': weight}">
|
||||
* Change style of this text!
|
||||
* </h1>
|
||||
*
|
||||
* <hr>
|
||||
*
|
||||
* <label>Italic: <input type="checkbox" (change)="changeStyle($event)"></label>
|
||||
* <label>Bold: <input type="checkbox" (change)="changeWeight($event)"></label>
|
||||
* <label>Size: <input type="text" [value]="size" (change)="size = $event.target.value"></label>
|
||||
* `,
|
||||
* directives: [NgStyle]
|
||||
* })
|
||||
* export class NgStyleExample {
|
||||
* style = 'normal';
|
||||
* weight = 'normal';
|
||||
* size = '20px';
|
||||
*
|
||||
* changeStyle($event: any) {
|
||||
* this.style = $event.target.checked ? 'italic' : 'normal';
|
||||
* }
|
||||
*
|
||||
* changeWeight($event: any) {
|
||||
* this.weight = $event.target.checked ? 'bold' : 'normal';
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* In this example the `font-style`, `font-size` and `font-weight` styles will be updated
|
||||
* based on the `style` property's value changes.
|
||||
*/
|
||||
var NgStyle = (function () {
|
||||
function NgStyle(_differs, _ngEl, _renderer) {
|
||||
this._differs = _differs;
|
||||
this._ngEl = _ngEl;
|
||||
this._renderer = _renderer;
|
||||
}
|
||||
Object.defineProperty(NgStyle.prototype, "rawStyle", {
|
||||
set: function (v) {
|
||||
this._rawStyle = v;
|
||||
if (lang_1.isBlank(this._differ) && lang_1.isPresent(v)) {
|
||||
this._differ = this._differs.find(this._rawStyle).create(null);
|
||||
}
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgStyle.prototype.doCheck = function () {
|
||||
if (lang_1.isPresent(this._differ)) {
|
||||
var changes = this._differ.diff(this._rawStyle);
|
||||
if (lang_1.isPresent(changes)) {
|
||||
this._applyChanges(changes);
|
||||
}
|
||||
}
|
||||
};
|
||||
NgStyle.prototype._applyChanges = function (changes) {
|
||||
var _this = this;
|
||||
changes.forEachAddedItem(function (record) { _this._setStyle(record.key, record.currentValue); });
|
||||
changes.forEachChangedItem(function (record) { _this._setStyle(record.key, record.currentValue); });
|
||||
changes.forEachRemovedItem(function (record) { _this._setStyle(record.key, null); });
|
||||
};
|
||||
NgStyle.prototype._setStyle = function (name, val) {
|
||||
this._renderer.setElementStyle(this._ngEl, name, val);
|
||||
};
|
||||
NgStyle = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-style]', inputs: ['rawStyle: ng-style'] }),
|
||||
__metadata('design:paramtypes', [change_detection_1.KeyValueDiffers, linker_1.ElementRef, render_1.Renderer])
|
||||
], NgStyle);
|
||||
return NgStyle;
|
||||
})();
|
||||
exports.NgStyle = NgStyle;
|
||||
//# sourceMappingURL=ng_style.js.map
|
||||
@@ -0,0 +1,210 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var _WHEN_DEFAULT = lang_1.CONST_EXPR(new Object());
|
||||
var SwitchView = (function () {
|
||||
function SwitchView(_viewContainerRef, _templateRef) {
|
||||
this._viewContainerRef = _viewContainerRef;
|
||||
this._templateRef = _templateRef;
|
||||
}
|
||||
SwitchView.prototype.create = function () { this._viewContainerRef.createEmbeddedView(this._templateRef); };
|
||||
SwitchView.prototype.destroy = function () { this._viewContainerRef.clear(); };
|
||||
return SwitchView;
|
||||
})();
|
||||
exports.SwitchView = SwitchView;
|
||||
/**
|
||||
* The `NgSwitch` directive is used to conditionally swap DOM structure on your template based on a
|
||||
* scope expression.
|
||||
* Elements within `NgSwitch` but without `NgSwitchWhen` or `NgSwitchDefault` directives will be
|
||||
* preserved at the location as specified in the template.
|
||||
*
|
||||
* `NgSwitch` simply chooses nested elements and makes them visible based on which element matches
|
||||
* the value obtained from the evaluated expression. In other words, you define a container element
|
||||
* (where you place the directive), place an expression on the **`[ng-switch]="..."` attribute**),
|
||||
* define any inner elements inside of the directive and place a `[ng-switch-when]` attribute per
|
||||
* element.
|
||||
* The when attribute is used to inform NgSwitch which element to display when the expression is
|
||||
* evaluated. If a matching expression is not found via a when attribute then an element with the
|
||||
* default attribute is displayed.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```
|
||||
* <ANY [ng-switch]="expression">
|
||||
* <template [ng-switch-when]="whenExpression1">...</template>
|
||||
* <template [ng-switch-when]="whenExpression1">...</template>
|
||||
* <template ng-switch-default>...</template>
|
||||
* </ANY>
|
||||
* ```
|
||||
*/
|
||||
var NgSwitch = (function () {
|
||||
function NgSwitch() {
|
||||
this._useDefault = false;
|
||||
this._valueViews = new collection_1.Map();
|
||||
this._activeViews = [];
|
||||
}
|
||||
Object.defineProperty(NgSwitch.prototype, "ngSwitch", {
|
||||
set: function (value) {
|
||||
// Empty the currently active ViewContainers
|
||||
this._emptyAllActiveViews();
|
||||
// Add the ViewContainers matching the value (with a fallback to default)
|
||||
this._useDefault = false;
|
||||
var views = this._valueViews.get(value);
|
||||
if (lang_1.isBlank(views)) {
|
||||
this._useDefault = true;
|
||||
views = lang_1.normalizeBlank(this._valueViews.get(_WHEN_DEFAULT));
|
||||
}
|
||||
this._activateViews(views);
|
||||
this._switchValue = value;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
/** @internal */
|
||||
NgSwitch.prototype._onWhenValueChanged = function (oldWhen, newWhen, view) {
|
||||
this._deregisterView(oldWhen, view);
|
||||
this._registerView(newWhen, view);
|
||||
if (oldWhen === this._switchValue) {
|
||||
view.destroy();
|
||||
collection_1.ListWrapper.remove(this._activeViews, view);
|
||||
}
|
||||
else if (newWhen === this._switchValue) {
|
||||
if (this._useDefault) {
|
||||
this._useDefault = false;
|
||||
this._emptyAllActiveViews();
|
||||
}
|
||||
view.create();
|
||||
this._activeViews.push(view);
|
||||
}
|
||||
// Switch to default when there is no more active ViewContainers
|
||||
if (this._activeViews.length === 0 && !this._useDefault) {
|
||||
this._useDefault = true;
|
||||
this._activateViews(this._valueViews.get(_WHEN_DEFAULT));
|
||||
}
|
||||
};
|
||||
/** @internal */
|
||||
NgSwitch.prototype._emptyAllActiveViews = function () {
|
||||
var activeContainers = this._activeViews;
|
||||
for (var i = 0; i < activeContainers.length; i++) {
|
||||
activeContainers[i].destroy();
|
||||
}
|
||||
this._activeViews = [];
|
||||
};
|
||||
/** @internal */
|
||||
NgSwitch.prototype._activateViews = function (views) {
|
||||
// TODO(vicb): assert(this._activeViews.length === 0);
|
||||
if (lang_1.isPresent(views)) {
|
||||
for (var i = 0; i < views.length; i++) {
|
||||
views[i].create();
|
||||
}
|
||||
this._activeViews = views;
|
||||
}
|
||||
};
|
||||
/** @internal */
|
||||
NgSwitch.prototype._registerView = function (value, view) {
|
||||
var views = this._valueViews.get(value);
|
||||
if (lang_1.isBlank(views)) {
|
||||
views = [];
|
||||
this._valueViews.set(value, views);
|
||||
}
|
||||
views.push(view);
|
||||
};
|
||||
/** @internal */
|
||||
NgSwitch.prototype._deregisterView = function (value, view) {
|
||||
// `_WHEN_DEFAULT` is used a marker for non-registered whens
|
||||
if (value === _WHEN_DEFAULT)
|
||||
return;
|
||||
var views = this._valueViews.get(value);
|
||||
if (views.length == 1) {
|
||||
this._valueViews.delete(value);
|
||||
}
|
||||
else {
|
||||
collection_1.ListWrapper.remove(views, view);
|
||||
}
|
||||
};
|
||||
NgSwitch = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-switch]', inputs: ['ngSwitch'] }),
|
||||
__metadata('design:paramtypes', [])
|
||||
], NgSwitch);
|
||||
return NgSwitch;
|
||||
})();
|
||||
exports.NgSwitch = NgSwitch;
|
||||
/**
|
||||
* Defines a case statement as an expression.
|
||||
*
|
||||
* If multiple `NgSwitchWhen` match the `NgSwitch` value, all of them are displayed.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* // match against a context variable
|
||||
* <template [ng-switch-when]="contextVariable">...</template>
|
||||
*
|
||||
* // match against a constant string
|
||||
* <template ng-switch-when="stringValue">...</template>
|
||||
* ```
|
||||
*/
|
||||
var NgSwitchWhen = (function () {
|
||||
function NgSwitchWhen(viewContainer, templateRef, _switch) {
|
||||
this._switch = _switch;
|
||||
// `_WHEN_DEFAULT` is used as a marker for a not yet initialized value
|
||||
/** @internal */
|
||||
this._value = _WHEN_DEFAULT;
|
||||
this._view = new SwitchView(viewContainer, templateRef);
|
||||
}
|
||||
Object.defineProperty(NgSwitchWhen.prototype, "ngSwitchWhen", {
|
||||
set: function (value) {
|
||||
this._switch._onWhenValueChanged(this._value, value, this._view);
|
||||
this._value = value;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgSwitchWhen = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-switch-when]', inputs: ['ngSwitchWhen'] }),
|
||||
__param(2, di_1.Host()),
|
||||
__metadata('design:paramtypes', [linker_1.ViewContainerRef, linker_1.TemplateRef, NgSwitch])
|
||||
], NgSwitchWhen);
|
||||
return NgSwitchWhen;
|
||||
})();
|
||||
exports.NgSwitchWhen = NgSwitchWhen;
|
||||
/**
|
||||
* Defines a default case statement.
|
||||
*
|
||||
* Default case statements are displayed when no `NgSwitchWhen` match the `ng-switch` value.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* <template ng-switch-default>...</template>
|
||||
* ```
|
||||
*/
|
||||
var NgSwitchDefault = (function () {
|
||||
function NgSwitchDefault(viewContainer, templateRef, sswitch) {
|
||||
sswitch._registerView(_WHEN_DEFAULT, new SwitchView(viewContainer, templateRef));
|
||||
}
|
||||
NgSwitchDefault = __decorate([
|
||||
metadata_1.Directive({ selector: '[ng-switch-default]' }),
|
||||
__param(2, di_1.Host()),
|
||||
__metadata('design:paramtypes', [linker_1.ViewContainerRef, linker_1.TemplateRef, NgSwitch])
|
||||
], NgSwitchDefault);
|
||||
return NgSwitchDefault;
|
||||
})();
|
||||
exports.NgSwitchDefault = NgSwitchDefault;
|
||||
//# sourceMappingURL=ng_switch.js.map
|
||||
@@ -0,0 +1,2 @@
|
||||
// TS does not have Observables
|
||||
//# sourceMappingURL=observable_list_diff.js.map
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* This module is used for handling user input, by defining and building a {@link ControlGroup} that
|
||||
* consists of
|
||||
* {@link Control} objects, and mapping them onto the DOM. {@link Control} objects can then be used
|
||||
* to read information
|
||||
* from the form DOM elements.
|
||||
*
|
||||
* This module is not included in the `angular2` module; you must import the forms module
|
||||
* explicitly.
|
||||
*
|
||||
*/
|
||||
var model_1 = require('./forms/model');
|
||||
exports.AbstractControl = model_1.AbstractControl;
|
||||
exports.Control = model_1.Control;
|
||||
exports.ControlGroup = model_1.ControlGroup;
|
||||
exports.ControlArray = model_1.ControlArray;
|
||||
var abstract_control_directive_1 = require('./forms/directives/abstract_control_directive');
|
||||
exports.AbstractControlDirective = abstract_control_directive_1.AbstractControlDirective;
|
||||
var control_container_1 = require('./forms/directives/control_container');
|
||||
exports.ControlContainer = control_container_1.ControlContainer;
|
||||
var ng_control_name_1 = require('./forms/directives/ng_control_name');
|
||||
exports.NgControlName = ng_control_name_1.NgControlName;
|
||||
var ng_form_control_1 = require('./forms/directives/ng_form_control');
|
||||
exports.NgFormControl = ng_form_control_1.NgFormControl;
|
||||
var ng_model_1 = require('./forms/directives/ng_model');
|
||||
exports.NgModel = ng_model_1.NgModel;
|
||||
var ng_control_1 = require('./forms/directives/ng_control');
|
||||
exports.NgControl = ng_control_1.NgControl;
|
||||
var ng_control_group_1 = require('./forms/directives/ng_control_group');
|
||||
exports.NgControlGroup = ng_control_group_1.NgControlGroup;
|
||||
var ng_form_model_1 = require('./forms/directives/ng_form_model');
|
||||
exports.NgFormModel = ng_form_model_1.NgFormModel;
|
||||
var ng_form_1 = require('./forms/directives/ng_form');
|
||||
exports.NgForm = ng_form_1.NgForm;
|
||||
var control_value_accessor_1 = require('./forms/directives/control_value_accessor');
|
||||
exports.NG_VALUE_ACCESSOR = control_value_accessor_1.NG_VALUE_ACCESSOR;
|
||||
var default_value_accessor_1 = require('./forms/directives/default_value_accessor');
|
||||
exports.DefaultValueAccessor = default_value_accessor_1.DefaultValueAccessor;
|
||||
var ng_control_status_1 = require('./forms/directives/ng_control_status');
|
||||
exports.NgControlStatus = ng_control_status_1.NgControlStatus;
|
||||
var checkbox_value_accessor_1 = require('./forms/directives/checkbox_value_accessor');
|
||||
exports.CheckboxControlValueAccessor = checkbox_value_accessor_1.CheckboxControlValueAccessor;
|
||||
var select_control_value_accessor_1 = require('./forms/directives/select_control_value_accessor');
|
||||
exports.NgSelectOption = select_control_value_accessor_1.NgSelectOption;
|
||||
exports.SelectControlValueAccessor = select_control_value_accessor_1.SelectControlValueAccessor;
|
||||
var directives_1 = require('./forms/directives');
|
||||
exports.FORM_DIRECTIVES = directives_1.FORM_DIRECTIVES;
|
||||
var validators_1 = require('./forms/validators');
|
||||
exports.NG_VALIDATORS = validators_1.NG_VALIDATORS;
|
||||
exports.NG_ASYNC_VALIDATORS = validators_1.NG_ASYNC_VALIDATORS;
|
||||
exports.Validators = validators_1.Validators;
|
||||
var validators_2 = require('./forms/directives/validators');
|
||||
exports.RequiredValidator = validators_2.RequiredValidator;
|
||||
exports.MinLengthValidator = validators_2.MinLengthValidator;
|
||||
exports.MaxLengthValidator = validators_2.MaxLengthValidator;
|
||||
var form_builder_1 = require('./forms/form_builder');
|
||||
exports.FormBuilder = form_builder_1.FormBuilder;
|
||||
exports.FORM_PROVIDERS = form_builder_1.FORM_PROVIDERS;
|
||||
exports.FORM_BINDINGS = form_builder_1.FORM_BINDINGS;
|
||||
//# sourceMappingURL=forms.js.map
|
||||
@@ -0,0 +1,76 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var ng_control_name_1 = require('./directives/ng_control_name');
|
||||
var ng_form_control_1 = require('./directives/ng_form_control');
|
||||
var ng_model_1 = require('./directives/ng_model');
|
||||
var ng_control_group_1 = require('./directives/ng_control_group');
|
||||
var ng_form_model_1 = require('./directives/ng_form_model');
|
||||
var ng_form_1 = require('./directives/ng_form');
|
||||
var default_value_accessor_1 = require('./directives/default_value_accessor');
|
||||
var checkbox_value_accessor_1 = require('./directives/checkbox_value_accessor');
|
||||
var number_value_accessor_1 = require('./directives/number_value_accessor');
|
||||
var ng_control_status_1 = require('./directives/ng_control_status');
|
||||
var select_control_value_accessor_1 = require('./directives/select_control_value_accessor');
|
||||
var validators_1 = require('./directives/validators');
|
||||
var ng_control_name_2 = require('./directives/ng_control_name');
|
||||
exports.NgControlName = ng_control_name_2.NgControlName;
|
||||
var ng_form_control_2 = require('./directives/ng_form_control');
|
||||
exports.NgFormControl = ng_form_control_2.NgFormControl;
|
||||
var ng_model_2 = require('./directives/ng_model');
|
||||
exports.NgModel = ng_model_2.NgModel;
|
||||
var ng_control_group_2 = require('./directives/ng_control_group');
|
||||
exports.NgControlGroup = ng_control_group_2.NgControlGroup;
|
||||
var ng_form_model_2 = require('./directives/ng_form_model');
|
||||
exports.NgFormModel = ng_form_model_2.NgFormModel;
|
||||
var ng_form_2 = require('./directives/ng_form');
|
||||
exports.NgForm = ng_form_2.NgForm;
|
||||
var default_value_accessor_2 = require('./directives/default_value_accessor');
|
||||
exports.DefaultValueAccessor = default_value_accessor_2.DefaultValueAccessor;
|
||||
var checkbox_value_accessor_2 = require('./directives/checkbox_value_accessor');
|
||||
exports.CheckboxControlValueAccessor = checkbox_value_accessor_2.CheckboxControlValueAccessor;
|
||||
var number_value_accessor_2 = require('./directives/number_value_accessor');
|
||||
exports.NumberValueAccessor = number_value_accessor_2.NumberValueAccessor;
|
||||
var ng_control_status_2 = require('./directives/ng_control_status');
|
||||
exports.NgControlStatus = ng_control_status_2.NgControlStatus;
|
||||
var select_control_value_accessor_2 = require('./directives/select_control_value_accessor');
|
||||
exports.SelectControlValueAccessor = select_control_value_accessor_2.SelectControlValueAccessor;
|
||||
exports.NgSelectOption = select_control_value_accessor_2.NgSelectOption;
|
||||
var validators_2 = require('./directives/validators');
|
||||
exports.RequiredValidator = validators_2.RequiredValidator;
|
||||
exports.MinLengthValidator = validators_2.MinLengthValidator;
|
||||
exports.MaxLengthValidator = validators_2.MaxLengthValidator;
|
||||
var ng_control_1 = require('./directives/ng_control');
|
||||
exports.NgControl = ng_control_1.NgControl;
|
||||
/**
|
||||
*
|
||||
* A list of all the form directives used as part of a `@View` annotation.
|
||||
*
|
||||
* This is a shorthand for importing them each individually.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* directives: [FORM_DIRECTIVES]
|
||||
* })
|
||||
* class MyApp {}
|
||||
* ```
|
||||
*/
|
||||
exports.FORM_DIRECTIVES = lang_1.CONST_EXPR([
|
||||
ng_control_name_1.NgControlName,
|
||||
ng_control_group_1.NgControlGroup,
|
||||
ng_form_control_1.NgFormControl,
|
||||
ng_model_1.NgModel,
|
||||
ng_form_model_1.NgFormModel,
|
||||
ng_form_1.NgForm,
|
||||
select_control_value_accessor_1.NgSelectOption,
|
||||
default_value_accessor_1.DefaultValueAccessor,
|
||||
number_value_accessor_1.NumberValueAccessor,
|
||||
checkbox_value_accessor_1.CheckboxControlValueAccessor,
|
||||
select_control_value_accessor_1.SelectControlValueAccessor,
|
||||
ng_control_status_1.NgControlStatus,
|
||||
validators_1.RequiredValidator,
|
||||
validators_1.MinLengthValidator,
|
||||
validators_1.MaxLengthValidator
|
||||
]);
|
||||
//# sourceMappingURL=directives.js.map
|
||||
@@ -0,0 +1,61 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
/**
|
||||
* Base class for control directives.
|
||||
*
|
||||
* Only used internally in the forms module.
|
||||
*/
|
||||
var AbstractControlDirective = (function () {
|
||||
function AbstractControlDirective() {
|
||||
}
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "control", {
|
||||
get: function () { return exceptions_1.unimplemented(); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "value", {
|
||||
get: function () { return lang_1.isPresent(this.control) ? this.control.value : null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "valid", {
|
||||
get: function () { return lang_1.isPresent(this.control) ? this.control.valid : null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "errors", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this.control) ? this.control.errors : null;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "pristine", {
|
||||
get: function () { return lang_1.isPresent(this.control) ? this.control.pristine : null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "dirty", {
|
||||
get: function () { return lang_1.isPresent(this.control) ? this.control.dirty : null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "touched", {
|
||||
get: function () { return lang_1.isPresent(this.control) ? this.control.touched : null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "untouched", {
|
||||
get: function () { return lang_1.isPresent(this.control) ? this.control.untouched : null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControlDirective.prototype, "path", {
|
||||
get: function () { return null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
return AbstractControlDirective;
|
||||
})();
|
||||
exports.AbstractControlDirective = AbstractControlDirective;
|
||||
//# sourceMappingURL=abstract_control_directive.js.map
|
||||
@@ -0,0 +1,49 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var render_1 = require('angular2/src/core/render');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var shared_1 = require('./shared');
|
||||
var CHECKBOX_VALUE_ACCESSOR = lang_1.CONST_EXPR(new di_1.Provider(control_value_accessor_1.NG_VALUE_ACCESSOR, { useExisting: di_1.forwardRef(function () { return CheckboxControlValueAccessor; }), multi: true }));
|
||||
/**
|
||||
* The accessor for writing a value and listening to changes on a checkbox input element.
|
||||
*
|
||||
* ### Example
|
||||
* ```
|
||||
* <input type="checkbox" ng-control="rememberLogin">
|
||||
* ```
|
||||
*/
|
||||
var CheckboxControlValueAccessor = (function () {
|
||||
function CheckboxControlValueAccessor(_renderer, _elementRef) {
|
||||
this._renderer = _renderer;
|
||||
this._elementRef = _elementRef;
|
||||
this.onChange = function (_) { };
|
||||
this.onTouched = function () { };
|
||||
}
|
||||
CheckboxControlValueAccessor.prototype.writeValue = function (value) { shared_1.setProperty(this._renderer, this._elementRef, "checked", value); };
|
||||
CheckboxControlValueAccessor.prototype.registerOnChange = function (fn) { this.onChange = fn; };
|
||||
CheckboxControlValueAccessor.prototype.registerOnTouched = function (fn) { this.onTouched = fn; };
|
||||
CheckboxControlValueAccessor = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: 'input[type=checkbox][ng-control],input[type=checkbox][ng-form-control],input[type=checkbox][ng-model]',
|
||||
host: { '(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()' },
|
||||
bindings: [CHECKBOX_VALUE_ACCESSOR]
|
||||
}),
|
||||
__metadata('design:paramtypes', [render_1.Renderer, linker_1.ElementRef])
|
||||
], CheckboxControlValueAccessor);
|
||||
return CheckboxControlValueAccessor;
|
||||
})();
|
||||
exports.CheckboxControlValueAccessor = CheckboxControlValueAccessor;
|
||||
//# sourceMappingURL=checkbox_value_accessor.js.map
|
||||
@@ -0,0 +1,36 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var abstract_control_directive_1 = require('./abstract_control_directive');
|
||||
/**
|
||||
* A directive that contains multiple {@link NgControl}s.
|
||||
*
|
||||
* Only used by the forms module.
|
||||
*/
|
||||
var ControlContainer = (function (_super) {
|
||||
__extends(ControlContainer, _super);
|
||||
function ControlContainer() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
Object.defineProperty(ControlContainer.prototype, "formDirective", {
|
||||
/**
|
||||
* Get the form to which this container belongs.
|
||||
*/
|
||||
get: function () { return null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(ControlContainer.prototype, "path", {
|
||||
/**
|
||||
* Get the path to this container.
|
||||
*/
|
||||
get: function () { return null; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
return ControlContainer;
|
||||
})(abstract_control_directive_1.AbstractControlDirective);
|
||||
exports.ControlContainer = ControlContainer;
|
||||
//# sourceMappingURL=control_container.js.map
|
||||
@@ -0,0 +1,4 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
exports.NG_VALUE_ACCESSOR = lang_1.CONST_EXPR(new di_1.OpaqueToken("NgValueAccessor"));
|
||||
//# sourceMappingURL=control_value_accessor.js.map
|
||||
@@ -0,0 +1,60 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var render_1 = require('angular2/src/core/render');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var shared_1 = require('./shared');
|
||||
var DEFAULT_VALUE_ACCESSOR = lang_1.CONST_EXPR(new di_1.Provider(control_value_accessor_1.NG_VALUE_ACCESSOR, { useExisting: di_1.forwardRef(function () { return DefaultValueAccessor; }), multi: true }));
|
||||
/**
|
||||
* The default accessor for writing a value and listening to changes that is used by the
|
||||
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
|
||||
*
|
||||
* ### Example
|
||||
* ```
|
||||
* <input type="text" ng-control="searchQuery">
|
||||
* ```
|
||||
*/
|
||||
var DefaultValueAccessor = (function () {
|
||||
function DefaultValueAccessor(_renderer, _elementRef) {
|
||||
this._renderer = _renderer;
|
||||
this._elementRef = _elementRef;
|
||||
this.onChange = function (_) { };
|
||||
this.onTouched = function () { };
|
||||
}
|
||||
DefaultValueAccessor.prototype.writeValue = function (value) {
|
||||
var normalizedValue = lang_1.isBlank(value) ? '' : value;
|
||||
shared_1.setProperty(this._renderer, this._elementRef, 'value', normalizedValue);
|
||||
};
|
||||
DefaultValueAccessor.prototype.registerOnChange = function (fn) { this.onChange = fn; };
|
||||
DefaultValueAccessor.prototype.registerOnTouched = function (fn) { this.onTouched = fn; };
|
||||
DefaultValueAccessor = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: 'input:not([type=checkbox])[ng-control],textarea[ng-control],input:not([type=checkbox])[ng-form-control],textarea[ng-form-control],input:not([type=checkbox])[ng-model],textarea[ng-model],[ng-default-control]',
|
||||
// TODO: vsavkin replace the above selector with the one below it once
|
||||
// https://github.com/angular/angular/issues/3011 is implemented
|
||||
// selector: '[ng-control],[ng-model],[ng-form-control]',
|
||||
host: {
|
||||
'(change)': 'onChange($event.target.value)',
|
||||
'(input)': 'onChange($event.target.value)',
|
||||
'(blur)': 'onTouched()'
|
||||
},
|
||||
bindings: [DEFAULT_VALUE_ACCESSOR]
|
||||
}),
|
||||
__metadata('design:paramtypes', [render_1.Renderer, linker_1.ElementRef])
|
||||
], DefaultValueAccessor);
|
||||
return DefaultValueAccessor;
|
||||
})();
|
||||
exports.DefaultValueAccessor = DefaultValueAccessor;
|
||||
//# sourceMappingURL=default_value_accessor.js.map
|
||||
@@ -0,0 +1 @@
|
||||
//# sourceMappingURL=form_interface.js.map
|
||||
@@ -0,0 +1,34 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var abstract_control_directive_1 = require('./abstract_control_directive');
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
/**
|
||||
* A base class that all control directive extend.
|
||||
* It binds a {@link Control} object to a DOM element.
|
||||
*
|
||||
* Used internally by Angular forms.
|
||||
*/
|
||||
var NgControl = (function (_super) {
|
||||
__extends(NgControl, _super);
|
||||
function NgControl() {
|
||||
_super.apply(this, arguments);
|
||||
this.name = null;
|
||||
this.valueAccessor = null;
|
||||
}
|
||||
Object.defineProperty(NgControl.prototype, "validator", {
|
||||
get: function () { return exceptions_1.unimplemented(); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControl.prototype, "asyncValidator", {
|
||||
get: function () { return exceptions_1.unimplemented(); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
return NgControl;
|
||||
})(abstract_control_directive_1.AbstractControlDirective);
|
||||
exports.NgControl = NgControl;
|
||||
//# sourceMappingURL=ng_control.js.map
|
||||
@@ -0,0 +1,137 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var control_container_1 = require('./control_container');
|
||||
var shared_1 = require('./shared');
|
||||
var validators_1 = require('../validators');
|
||||
var controlGroupProvider = lang_1.CONST_EXPR(new di_1.Provider(control_container_1.ControlContainer, { useExisting: di_1.forwardRef(function () { return NgControlGroup; }) }));
|
||||
/**
|
||||
* Creates and binds a control group to a DOM element.
|
||||
*
|
||||
* This directive can only be used as a child of {@link NgForm} or {@link NgFormModel}.
|
||||
*
|
||||
* # Example ([live demo](http://plnkr.co/edit/7EJ11uGeaggViYM6T5nq?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* directives: [FORM_DIRECTIVES],
|
||||
* })
|
||||
* @View({
|
||||
* template: `
|
||||
* <div>
|
||||
* <h2>Angular2 Control & ControlGroup Example</h2>
|
||||
* <form #f="form">
|
||||
* <div ng-control-group="name" #cg-name="form">
|
||||
* <h3>Enter your name:</h3>
|
||||
* <p>First: <input ng-control="first" required></p>
|
||||
* <p>Middle: <input ng-control="middle"></p>
|
||||
* <p>Last: <input ng-control="last" required></p>
|
||||
* </div>
|
||||
* <h3>Name value:</h3>
|
||||
* <pre>{{valueOf(cgName)}}</pre>
|
||||
* <p>Name is {{cgName?.control?.valid ? "valid" : "invalid"}}</p>
|
||||
* <h3>What's your favorite food?</h3>
|
||||
* <p><input ng-control="food"></p>
|
||||
* <h3>Form value</h3>
|
||||
* <pre>{{valueOf(f)}}</pre>
|
||||
* </form>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [FORM_DIRECTIVES]
|
||||
* })
|
||||
* export class App {
|
||||
* valueOf(cg: NgControlGroup): string {
|
||||
* if (cg.control == null) {
|
||||
* return null;
|
||||
* }
|
||||
* return JSON.stringify(cg.control.value, null, 2);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* This example declares a control group for a user's name. The value and validation state of
|
||||
* this group can be accessed separately from the overall form.
|
||||
*/
|
||||
var NgControlGroup = (function (_super) {
|
||||
__extends(NgControlGroup, _super);
|
||||
function NgControlGroup(parent, _validators, _asyncValidators) {
|
||||
_super.call(this);
|
||||
this._validators = _validators;
|
||||
this._asyncValidators = _asyncValidators;
|
||||
this._parent = parent;
|
||||
}
|
||||
NgControlGroup.prototype.onInit = function () { this.formDirective.addControlGroup(this); };
|
||||
NgControlGroup.prototype.onDestroy = function () { this.formDirective.removeControlGroup(this); };
|
||||
Object.defineProperty(NgControlGroup.prototype, "control", {
|
||||
/**
|
||||
* Get the {@link ControlGroup} backing this binding.
|
||||
*/
|
||||
get: function () { return this.formDirective.getControlGroup(this); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlGroup.prototype, "path", {
|
||||
/**
|
||||
* Get the path to this control group.
|
||||
*/
|
||||
get: function () { return shared_1.controlPath(this.name, this._parent); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlGroup.prototype, "formDirective", {
|
||||
/**
|
||||
* Get the {@link Form} to which this group belongs.
|
||||
*/
|
||||
get: function () { return this._parent.formDirective; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlGroup.prototype, "validator", {
|
||||
get: function () { return shared_1.composeValidators(this._validators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlGroup.prototype, "asyncValidator", {
|
||||
get: function () { return shared_1.composeAsyncValidators(this._asyncValidators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgControlGroup = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[ng-control-group]',
|
||||
providers: [controlGroupProvider],
|
||||
inputs: ['name: ng-control-group'],
|
||||
exportAs: 'form'
|
||||
}),
|
||||
__param(0, di_1.Host()),
|
||||
__param(0, di_1.SkipSelf()),
|
||||
__param(1, di_1.Optional()),
|
||||
__param(1, di_1.Inject(validators_1.NG_VALIDATORS)),
|
||||
__param(2, di_1.Optional()),
|
||||
__param(2, di_1.Inject(validators_1.NG_ASYNC_VALIDATORS)),
|
||||
__metadata('design:paramtypes', [control_container_1.ControlContainer, Array, Array])
|
||||
], NgControlGroup);
|
||||
return NgControlGroup;
|
||||
})(control_container_1.ControlContainer);
|
||||
exports.NgControlGroup = NgControlGroup;
|
||||
//# sourceMappingURL=ng_control_group.js.map
|
||||
@@ -0,0 +1,158 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_container_1 = require('./control_container');
|
||||
var ng_control_1 = require('./ng_control');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var shared_1 = require('./shared');
|
||||
var validators_1 = require('../validators');
|
||||
var controlNameBinding = lang_1.CONST_EXPR(new di_1.Provider(ng_control_1.NgControl, { useExisting: di_1.forwardRef(function () { return NgControlName; }) }));
|
||||
/**
|
||||
* Creates and binds a control with a specified name to a DOM element.
|
||||
*
|
||||
* This directive can only be used as a child of {@link NgForm} or {@link NgFormModel}.
|
||||
|
||||
* ### Example
|
||||
*
|
||||
* In this example, we create the login and password controls.
|
||||
* We can work with each control separately: check its validity, get its value, listen to its
|
||||
* changes.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "login-comp",
|
||||
* directives: [FORM_DIRECTIVES],
|
||||
* template: `
|
||||
* <form #f="form" (submit)='onLogIn(f.value)'>
|
||||
* Login <input type='text' ng-control='login' #l="form">
|
||||
* <div *ng-if="!l.valid">Login is invalid</div>
|
||||
*
|
||||
* Password <input type='password' ng-control='password'>
|
||||
* <button type='submit'>Log in!</button>
|
||||
* </form>
|
||||
* `})
|
||||
* class LoginComp {
|
||||
* onLogIn(value): void {
|
||||
* // value === {login: 'some login', password: 'some password'}
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* We can also use ng-model to bind a domain model to the form.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "login-comp",
|
||||
* directives: [FORM_DIRECTIVES],
|
||||
* template: `
|
||||
* <form (submit)='onLogIn()'>
|
||||
* Login <input type='text' ng-control='login' [(ng-model)]="credentials.login">
|
||||
* Password <input type='password' ng-control='password'
|
||||
* [(ng-model)]="credentials.password">
|
||||
* <button type='submit'>Log in!</button>
|
||||
* </form>
|
||||
* `})
|
||||
* class LoginComp {
|
||||
* credentials: {login:string, password:string};
|
||||
*
|
||||
* onLogIn(): void {
|
||||
* // this.credentials.login === "some login"
|
||||
* // this.credentials.password === "some password"
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var NgControlName = (function (_super) {
|
||||
__extends(NgControlName, _super);
|
||||
function NgControlName(_parent, _validators, _asyncValidators, valueAccessors) {
|
||||
_super.call(this);
|
||||
this._parent = _parent;
|
||||
this._validators = _validators;
|
||||
this._asyncValidators = _asyncValidators;
|
||||
/** @internal */
|
||||
this.update = new async_1.EventEmitter();
|
||||
this._added = false;
|
||||
this.valueAccessor = shared_1.selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
NgControlName.prototype.onChanges = function (changes) {
|
||||
if (!this._added) {
|
||||
this.formDirective.addControl(this);
|
||||
this._added = true;
|
||||
}
|
||||
if (shared_1.isPropertyUpdated(changes, this.viewModel)) {
|
||||
this.viewModel = this.model;
|
||||
this.formDirective.updateModel(this, this.model);
|
||||
}
|
||||
};
|
||||
NgControlName.prototype.onDestroy = function () { this.formDirective.removeControl(this); };
|
||||
NgControlName.prototype.viewToModelUpdate = function (newValue) {
|
||||
this.viewModel = newValue;
|
||||
async_1.ObservableWrapper.callNext(this.update, newValue);
|
||||
};
|
||||
Object.defineProperty(NgControlName.prototype, "path", {
|
||||
get: function () { return shared_1.controlPath(this.name, this._parent); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlName.prototype, "formDirective", {
|
||||
get: function () { return this._parent.formDirective; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlName.prototype, "validator", {
|
||||
get: function () { return shared_1.composeValidators(this._validators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlName.prototype, "asyncValidator", {
|
||||
get: function () { return shared_1.composeAsyncValidators(this._asyncValidators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlName.prototype, "control", {
|
||||
get: function () { return this.formDirective.getControl(this); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgControlName = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[ng-control]',
|
||||
bindings: [controlNameBinding],
|
||||
inputs: ['name: ngControl', 'model: ngModel'],
|
||||
outputs: ['update: ngModelChange'],
|
||||
exportAs: 'form'
|
||||
}),
|
||||
__param(0, di_1.Host()),
|
||||
__param(0, di_1.SkipSelf()),
|
||||
__param(1, di_1.Optional()),
|
||||
__param(1, di_1.Inject(validators_1.NG_VALIDATORS)),
|
||||
__param(2, di_1.Optional()),
|
||||
__param(2, di_1.Inject(validators_1.NG_ASYNC_VALIDATORS)),
|
||||
__param(3, di_1.Optional()),
|
||||
__param(3, di_1.Inject(control_value_accessor_1.NG_VALUE_ACCESSOR)),
|
||||
__metadata('design:paramtypes', [control_container_1.ControlContainer, Array, Array, Array])
|
||||
], NgControlName);
|
||||
return NgControlName;
|
||||
})(ng_control_1.NgControl);
|
||||
exports.NgControlName = NgControlName;
|
||||
//# sourceMappingURL=ng_control_name.js.map
|
||||
@@ -0,0 +1,83 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var ng_control_1 = require('./ng_control');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var NgControlStatus = (function () {
|
||||
function NgControlStatus(cd) {
|
||||
this._cd = cd;
|
||||
}
|
||||
Object.defineProperty(NgControlStatus.prototype, "ngClassUntouched", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this._cd.control) ? this._cd.control.untouched : false;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlStatus.prototype, "ngClassTouched", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this._cd.control) ? this._cd.control.touched : false;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlStatus.prototype, "ngClassPristine", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this._cd.control) ? this._cd.control.pristine : false;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlStatus.prototype, "ngClassDirty", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this._cd.control) ? this._cd.control.dirty : false;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlStatus.prototype, "ngClassValid", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this._cd.control) ? this._cd.control.valid : false;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgControlStatus.prototype, "ngClassInvalid", {
|
||||
get: function () {
|
||||
return lang_1.isPresent(this._cd.control) ? !this._cd.control.valid : false;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgControlStatus = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[ng-control],[ng-model],[ng-form-control]',
|
||||
host: {
|
||||
'[class.ng-untouched]': 'ngClassUntouched',
|
||||
'[class.ng-touched]': 'ngClassTouched',
|
||||
'[class.ng-pristine]': 'ngClassPristine',
|
||||
'[class.ng-dirty]': 'ngClassDirty',
|
||||
'[class.ng-valid]': 'ngClassValid',
|
||||
'[class.ng-invalid]': 'ngClassInvalid'
|
||||
}
|
||||
}),
|
||||
__param(0, di_1.Self()),
|
||||
__metadata('design:paramtypes', [ng_control_1.NgControl])
|
||||
], NgControlStatus);
|
||||
return NgControlStatus;
|
||||
})();
|
||||
exports.NgControlStatus = NgControlStatus;
|
||||
//# sourceMappingURL=ng_control_status.js.map
|
||||
@@ -0,0 +1,195 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_container_1 = require('./control_container');
|
||||
var model_1 = require('../model');
|
||||
var shared_1 = require('./shared');
|
||||
var validators_1 = require('../validators');
|
||||
var formDirectiveProvider = lang_1.CONST_EXPR(new di_1.Provider(control_container_1.ControlContainer, { useExisting: di_1.forwardRef(function () { return NgForm; }) }));
|
||||
/**
|
||||
* If `NgForm` is bound in a component, `<form>` elements in that component will be
|
||||
* upgraded to use the Angular form system.
|
||||
*
|
||||
*##Typical Use
|
||||
*
|
||||
* Include `FORM_DIRECTIVES` in the `directives` section of a {@link View} annotation
|
||||
* to use `NgForm` and its associated controls.
|
||||
*
|
||||
*##Structure
|
||||
*
|
||||
* An Angular form is a collection of `Control`s in some hierarchy.
|
||||
* `Control`s can be at the top level or can be organized in `ControlGroup`s
|
||||
* or `ControlArray`s. This hierarchy is reflected in the form's `value`, a
|
||||
* JSON object that mirrors the form structure.
|
||||
*
|
||||
*##Submission
|
||||
*
|
||||
* The `ng-submit` event signals when the user triggers a form submission.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/ltdgYj4P0iY64AR71EpL?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* template: `
|
||||
* <div>
|
||||
* <p>Submit the form to see the data object Angular builds</p>
|
||||
* <h2>NgForm demo</h2>
|
||||
* <form #f="form" (ng-submit)="onSubmit(f.value)">
|
||||
* <h3>Control group: credentials</h3>
|
||||
* <div ng-control-group="credentials">
|
||||
* <p>Login: <input type="text" ng-control="login"></p>
|
||||
* <p>Password: <input type="password" ng-control="password"></p>
|
||||
* </div>
|
||||
* <h3>Control group: person</h3>
|
||||
* <div ng-control-group="person">
|
||||
* <p>First name: <input type="text" ng-control="firstName"></p>
|
||||
* <p>Last name: <input type="text" ng-control="lastName"></p>
|
||||
* </div>
|
||||
* <button type="submit">Submit Form</button>
|
||||
* <p>Form data submitted:</p>
|
||||
* </form>
|
||||
* <pre>{{data}}</pre>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [CORE_DIRECTIVES, FORM_DIRECTIVES]
|
||||
* })
|
||||
* export class App {
|
||||
* constructor() {}
|
||||
*
|
||||
* data: string;
|
||||
*
|
||||
* onSubmit(data) {
|
||||
* this.data = JSON.stringify(data, null, 2);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var NgForm = (function (_super) {
|
||||
__extends(NgForm, _super);
|
||||
function NgForm(validators, asyncValidators) {
|
||||
_super.call(this);
|
||||
this.ngSubmit = new async_1.EventEmitter();
|
||||
this.form = new model_1.ControlGroup({}, null, shared_1.composeValidators(validators), shared_1.composeAsyncValidators(asyncValidators));
|
||||
}
|
||||
Object.defineProperty(NgForm.prototype, "formDirective", {
|
||||
get: function () { return this; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgForm.prototype, "control", {
|
||||
get: function () { return this.form; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgForm.prototype, "path", {
|
||||
get: function () { return []; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgForm.prototype, "controls", {
|
||||
get: function () { return this.form.controls; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgForm.prototype.addControl = function (dir) {
|
||||
var _this = this;
|
||||
async_1.PromiseWrapper.scheduleMicrotask(function () {
|
||||
var container = _this._findContainer(dir.path);
|
||||
var ctrl = new model_1.Control();
|
||||
shared_1.setUpControl(ctrl, dir);
|
||||
container.addControl(dir.name, ctrl);
|
||||
ctrl.updateValueAndValidity({ emitEvent: false });
|
||||
});
|
||||
};
|
||||
NgForm.prototype.getControl = function (dir) { return this.form.find(dir.path); };
|
||||
NgForm.prototype.removeControl = function (dir) {
|
||||
var _this = this;
|
||||
async_1.PromiseWrapper.scheduleMicrotask(function () {
|
||||
var container = _this._findContainer(dir.path);
|
||||
if (lang_1.isPresent(container)) {
|
||||
container.removeControl(dir.name);
|
||||
container.updateValueAndValidity({ emitEvent: false });
|
||||
}
|
||||
});
|
||||
};
|
||||
NgForm.prototype.addControlGroup = function (dir) {
|
||||
var _this = this;
|
||||
async_1.PromiseWrapper.scheduleMicrotask(function () {
|
||||
var container = _this._findContainer(dir.path);
|
||||
var group = new model_1.ControlGroup({});
|
||||
shared_1.setUpControlGroup(group, dir);
|
||||
container.addControl(dir.name, group);
|
||||
group.updateValueAndValidity({ emitEvent: false });
|
||||
});
|
||||
};
|
||||
NgForm.prototype.removeControlGroup = function (dir) {
|
||||
var _this = this;
|
||||
async_1.PromiseWrapper.scheduleMicrotask(function () {
|
||||
var container = _this._findContainer(dir.path);
|
||||
if (lang_1.isPresent(container)) {
|
||||
container.removeControl(dir.name);
|
||||
container.updateValueAndValidity({ emitEvent: false });
|
||||
}
|
||||
});
|
||||
};
|
||||
NgForm.prototype.getControlGroup = function (dir) {
|
||||
return this.form.find(dir.path);
|
||||
};
|
||||
NgForm.prototype.updateModel = function (dir, value) {
|
||||
var _this = this;
|
||||
async_1.PromiseWrapper.scheduleMicrotask(function () {
|
||||
var ctrl = _this.form.find(dir.path);
|
||||
ctrl.updateValue(value);
|
||||
});
|
||||
};
|
||||
NgForm.prototype.onSubmit = function () {
|
||||
async_1.ObservableWrapper.callNext(this.ngSubmit, null);
|
||||
return false;
|
||||
};
|
||||
/** @internal */
|
||||
NgForm.prototype._findContainer = function (path) {
|
||||
path.pop();
|
||||
return collection_1.ListWrapper.isEmpty(path) ? this.form : this.form.find(path);
|
||||
};
|
||||
NgForm = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: 'form:not([ng-no-form]):not([ng-form-model]),ng-form,[ng-form]',
|
||||
bindings: [formDirectiveProvider],
|
||||
host: {
|
||||
'(submit)': 'onSubmit()',
|
||||
},
|
||||
outputs: ['ngSubmit'],
|
||||
exportAs: 'form'
|
||||
}),
|
||||
__param(0, di_1.Optional()),
|
||||
__param(0, di_1.Inject(validators_1.NG_VALIDATORS)),
|
||||
__param(1, di_1.Optional()),
|
||||
__param(1, di_1.Inject(validators_1.NG_ASYNC_VALIDATORS)),
|
||||
__metadata('design:paramtypes', [Array, Array])
|
||||
], NgForm);
|
||||
return NgForm;
|
||||
})(control_container_1.ControlContainer);
|
||||
exports.NgForm = NgForm;
|
||||
//# sourceMappingURL=ng_form.js.map
|
||||
@@ -0,0 +1,142 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var ng_control_1 = require('./ng_control');
|
||||
var validators_1 = require('../validators');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var shared_1 = require('./shared');
|
||||
var formControlBinding = lang_1.CONST_EXPR(new di_1.Provider(ng_control_1.NgControl, { useExisting: di_1.forwardRef(function () { return NgFormControl; }) }));
|
||||
/**
|
||||
* Binds an existing {@link Control} to a DOM element.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/jcQlZ2tTh22BZZ2ucNAT?p=preview))
|
||||
*
|
||||
* In this example, we bind the control to an input element. When the value of the input element
|
||||
* changes, the value of the control will reflect that change. Likewise, if the value of the
|
||||
* control changes, the input element reflects that change.
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* template: `
|
||||
* <div>
|
||||
* <h2>NgFormControl Example</h2>
|
||||
* <form>
|
||||
* <p>Element with existing control: <input type="text"
|
||||
* [ng-form-control]="loginControl"></p>
|
||||
* <p>Value of existing control: {{loginControl.value}}</p>
|
||||
* </form>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [CORE_DIRECTIVES, FORM_DIRECTIVES]
|
||||
* })
|
||||
* export class App {
|
||||
* loginControl: Control = new Control('');
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*##ng-model
|
||||
*
|
||||
* We can also use `ng-model` to bind a domain model to the form.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/yHMLuHO7DNgT8XvtjTDH?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: "login-comp",
|
||||
* directives: [FORM_DIRECTIVES],
|
||||
* template: "<input type='text' [ng-form-control]='loginControl' [(ng-model)]='login'>"
|
||||
* })
|
||||
* class LoginComp {
|
||||
* loginControl: Control = new Control('');
|
||||
* login:string;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var NgFormControl = (function (_super) {
|
||||
__extends(NgFormControl, _super);
|
||||
function NgFormControl(_validators, _asyncValidators, valueAccessors) {
|
||||
_super.call(this);
|
||||
this._validators = _validators;
|
||||
this._asyncValidators = _asyncValidators;
|
||||
this.update = new async_1.EventEmitter();
|
||||
this.valueAccessor = shared_1.selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
NgFormControl.prototype.onChanges = function (changes) {
|
||||
if (this._isControlChanged(changes)) {
|
||||
shared_1.setUpControl(this.form, this);
|
||||
this.form.updateValueAndValidity({ emitEvent: false });
|
||||
}
|
||||
if (shared_1.isPropertyUpdated(changes, this.viewModel)) {
|
||||
this.form.updateValue(this.model);
|
||||
this.viewModel = this.model;
|
||||
}
|
||||
};
|
||||
Object.defineProperty(NgFormControl.prototype, "path", {
|
||||
get: function () { return []; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgFormControl.prototype, "validator", {
|
||||
get: function () { return shared_1.composeValidators(this._validators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgFormControl.prototype, "asyncValidator", {
|
||||
get: function () { return shared_1.composeAsyncValidators(this._asyncValidators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgFormControl.prototype, "control", {
|
||||
get: function () { return this.form; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgFormControl.prototype.viewToModelUpdate = function (newValue) {
|
||||
this.viewModel = newValue;
|
||||
async_1.ObservableWrapper.callNext(this.update, newValue);
|
||||
};
|
||||
NgFormControl.prototype._isControlChanged = function (changes) {
|
||||
return collection_1.StringMapWrapper.contains(changes, "form");
|
||||
};
|
||||
NgFormControl = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[ng-form-control]',
|
||||
bindings: [formControlBinding],
|
||||
inputs: ['form: ngFormControl', 'model: ngModel'],
|
||||
outputs: ['update: ngModelChange'],
|
||||
exportAs: 'form'
|
||||
}),
|
||||
__param(0, di_1.Optional()),
|
||||
__param(0, di_1.Inject(validators_1.NG_VALIDATORS)),
|
||||
__param(1, di_1.Optional()),
|
||||
__param(1, di_1.Inject(validators_1.NG_ASYNC_VALIDATORS)),
|
||||
__param(2, di_1.Optional()),
|
||||
__param(2, di_1.Inject(control_value_accessor_1.NG_VALUE_ACCESSOR)),
|
||||
__metadata('design:paramtypes', [Array, Array, Array])
|
||||
], NgFormControl);
|
||||
return NgFormControl;
|
||||
})(ng_control_1.NgControl);
|
||||
exports.NgFormControl = NgFormControl;
|
||||
//# sourceMappingURL=ng_form_control.js.map
|
||||
@@ -0,0 +1,187 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_container_1 = require('./control_container');
|
||||
var shared_1 = require('./shared');
|
||||
var validators_1 = require('../validators');
|
||||
var formDirectiveProvider = lang_1.CONST_EXPR(new di_1.Provider(control_container_1.ControlContainer, { useExisting: di_1.forwardRef(function () { return NgFormModel; }) }));
|
||||
/**
|
||||
* Binds an existing control group to a DOM element.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/jqrVirudY8anJxTMUjTP?p=preview))
|
||||
*
|
||||
* In this example, we bind the control group to the form element, and we bind the login and
|
||||
* password controls to the login and password elements.
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* template: `
|
||||
* <div>
|
||||
* <h2>NgFormModel Example</h2>
|
||||
* <form [ng-form-model]="loginForm">
|
||||
* <p>Login: <input type="text" ng-control="login"></p>
|
||||
* <p>Password: <input type="password" ng-control="password"></p>
|
||||
* </form>
|
||||
* <p>Value:</p>
|
||||
* <pre>{{value}}</pre>
|
||||
* </div>
|
||||
* `,
|
||||
* directives: [FORM_DIRECTIVES]
|
||||
* })
|
||||
* export class App {
|
||||
* loginForm: ControlGroup;
|
||||
*
|
||||
* constructor() {
|
||||
* this.loginForm = new ControlGroup({
|
||||
* login: new Control(""),
|
||||
* password: new Control("")
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* get value(): string {
|
||||
* return JSON.stringify(this.loginForm.value, null, 2);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* We can also use ng-model to bind a domain model to the form.
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: "login-comp",
|
||||
* directives: [FORM_DIRECTIVES],
|
||||
* template: `
|
||||
* <form [ng-form-model]='loginForm'>
|
||||
* Login <input type='text' ng-control='login' [(ng-model)]='credentials.login'>
|
||||
* Password <input type='password' ng-control='password'
|
||||
* [(ng-model)]='credentials.password'>
|
||||
* <button (click)="onLogin()">Login</button>
|
||||
* </form>`
|
||||
* })
|
||||
* class LoginComp {
|
||||
* credentials: {login: string, password: string};
|
||||
* loginForm: ControlGroup;
|
||||
*
|
||||
* constructor() {
|
||||
* this.loginForm = new ControlGroup({
|
||||
* login: new Control(""),
|
||||
* password: new Control("")
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* onLogin(): void {
|
||||
* // this.credentials.login === 'some login'
|
||||
* // this.credentials.password === 'some password'
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var NgFormModel = (function (_super) {
|
||||
__extends(NgFormModel, _super);
|
||||
function NgFormModel(_validators, _asyncValidators) {
|
||||
_super.call(this);
|
||||
this._validators = _validators;
|
||||
this._asyncValidators = _asyncValidators;
|
||||
this.form = null;
|
||||
this.directives = [];
|
||||
this.ngSubmit = new async_1.EventEmitter();
|
||||
}
|
||||
NgFormModel.prototype.onChanges = function (changes) {
|
||||
if (collection_1.StringMapWrapper.contains(changes, "form")) {
|
||||
var sync = shared_1.composeValidators(this._validators);
|
||||
this.form.validator = validators_1.Validators.compose([this.form.validator, sync]);
|
||||
var async = shared_1.composeAsyncValidators(this._asyncValidators);
|
||||
this.form.asyncValidator = validators_1.Validators.composeAsync([this.form.asyncValidator, async]);
|
||||
this.form.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
}
|
||||
this._updateDomValue();
|
||||
};
|
||||
Object.defineProperty(NgFormModel.prototype, "formDirective", {
|
||||
get: function () { return this; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgFormModel.prototype, "control", {
|
||||
get: function () { return this.form; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgFormModel.prototype, "path", {
|
||||
get: function () { return []; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgFormModel.prototype.addControl = function (dir) {
|
||||
var ctrl = this.form.find(dir.path);
|
||||
shared_1.setUpControl(ctrl, dir);
|
||||
ctrl.updateValueAndValidity({ emitEvent: false });
|
||||
this.directives.push(dir);
|
||||
};
|
||||
NgFormModel.prototype.getControl = function (dir) { return this.form.find(dir.path); };
|
||||
NgFormModel.prototype.removeControl = function (dir) { collection_1.ListWrapper.remove(this.directives, dir); };
|
||||
NgFormModel.prototype.addControlGroup = function (dir) {
|
||||
var ctrl = this.form.find(dir.path);
|
||||
shared_1.setUpControlGroup(ctrl, dir);
|
||||
ctrl.updateValueAndValidity({ emitEvent: false });
|
||||
};
|
||||
NgFormModel.prototype.removeControlGroup = function (dir) { };
|
||||
NgFormModel.prototype.getControlGroup = function (dir) {
|
||||
return this.form.find(dir.path);
|
||||
};
|
||||
NgFormModel.prototype.updateModel = function (dir, value) {
|
||||
var ctrl = this.form.find(dir.path);
|
||||
ctrl.updateValue(value);
|
||||
};
|
||||
NgFormModel.prototype.onSubmit = function () {
|
||||
async_1.ObservableWrapper.callNext(this.ngSubmit, null);
|
||||
return false;
|
||||
};
|
||||
/** @internal */
|
||||
NgFormModel.prototype._updateDomValue = function () {
|
||||
var _this = this;
|
||||
this.directives.forEach(function (dir) {
|
||||
var ctrl = _this.form.find(dir.path);
|
||||
dir.valueAccessor.writeValue(ctrl.value);
|
||||
});
|
||||
};
|
||||
NgFormModel = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[ng-form-model]',
|
||||
bindings: [formDirectiveProvider],
|
||||
inputs: ['form: ng-form-model'],
|
||||
host: { '(submit)': 'onSubmit()' },
|
||||
outputs: ['ngSubmit'],
|
||||
exportAs: 'form'
|
||||
}),
|
||||
__param(0, di_1.Optional()),
|
||||
__param(0, di_1.Inject(validators_1.NG_VALIDATORS)),
|
||||
__param(1, di_1.Optional()),
|
||||
__param(1, di_1.Inject(validators_1.NG_ASYNC_VALIDATORS)),
|
||||
__metadata('design:paramtypes', [Array, Array])
|
||||
], NgFormModel);
|
||||
return NgFormModel;
|
||||
})(control_container_1.ControlContainer);
|
||||
exports.NgFormModel = NgFormModel;
|
||||
//# sourceMappingURL=ng_form_model.js.map
|
||||
@@ -0,0 +1,118 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var ng_control_1 = require('./ng_control');
|
||||
var model_1 = require('../model');
|
||||
var validators_1 = require('../validators');
|
||||
var shared_1 = require('./shared');
|
||||
var formControlBinding = lang_1.CONST_EXPR(new di_1.Provider(ng_control_1.NgControl, { useExisting: di_1.forwardRef(function () { return NgModel; }) }));
|
||||
/**
|
||||
* Binds a domain model to a form control.
|
||||
*
|
||||
*##Usage
|
||||
*
|
||||
* `ng-model` binds an existing domain model to a form control. For a
|
||||
* two-way binding, use `[(ng-model)]` to ensure the model updates in
|
||||
* both directions.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/R3UX5qDaUqFO2VYR0UzH?p=preview))
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: "search-comp",
|
||||
* directives: [FORM_DIRECTIVES],
|
||||
* template: `<input type='text' [(ng-model)]="searchQuery">`
|
||||
* })
|
||||
* class SearchComp {
|
||||
* searchQuery: string;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var NgModel = (function (_super) {
|
||||
__extends(NgModel, _super);
|
||||
function NgModel(_validators, _asyncValidators, valueAccessors) {
|
||||
_super.call(this);
|
||||
this._validators = _validators;
|
||||
this._asyncValidators = _asyncValidators;
|
||||
/** @internal */
|
||||
this._control = new model_1.Control();
|
||||
/** @internal */
|
||||
this._added = false;
|
||||
this.update = new async_1.EventEmitter();
|
||||
this.valueAccessor = shared_1.selectValueAccessor(this, valueAccessors);
|
||||
}
|
||||
NgModel.prototype.onChanges = function (changes) {
|
||||
if (!this._added) {
|
||||
shared_1.setUpControl(this._control, this);
|
||||
this._control.updateValueAndValidity({ emitEvent: false });
|
||||
this._added = true;
|
||||
}
|
||||
if (shared_1.isPropertyUpdated(changes, this.viewModel)) {
|
||||
this._control.updateValue(this.model);
|
||||
this.viewModel = this.model;
|
||||
}
|
||||
};
|
||||
Object.defineProperty(NgModel.prototype, "control", {
|
||||
get: function () { return this._control; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgModel.prototype, "path", {
|
||||
get: function () { return []; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgModel.prototype, "validator", {
|
||||
get: function () { return shared_1.composeValidators(this._validators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(NgModel.prototype, "asyncValidator", {
|
||||
get: function () { return shared_1.composeAsyncValidators(this._asyncValidators); },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
NgModel.prototype.viewToModelUpdate = function (newValue) {
|
||||
this.viewModel = newValue;
|
||||
async_1.ObservableWrapper.callNext(this.update, newValue);
|
||||
};
|
||||
NgModel = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[ng-model]:not([ng-control]):not([ng-form-control])',
|
||||
bindings: [formControlBinding],
|
||||
inputs: ['model: ngModel'],
|
||||
outputs: ['update: ngModelChange'],
|
||||
exportAs: 'form'
|
||||
}),
|
||||
__param(0, di_1.Optional()),
|
||||
__param(0, di_1.Inject(validators_1.NG_VALIDATORS)),
|
||||
__param(1, di_1.Optional()),
|
||||
__param(1, di_1.Inject(validators_1.NG_ASYNC_VALIDATORS)),
|
||||
__param(2, di_1.Optional()),
|
||||
__param(2, di_1.Inject(control_value_accessor_1.NG_VALUE_ACCESSOR)),
|
||||
__metadata('design:paramtypes', [Array, Array, Array])
|
||||
], NgModel);
|
||||
return NgModel;
|
||||
})(ng_control_1.NgControl);
|
||||
exports.NgModel = NgModel;
|
||||
//# sourceMappingURL=ng_model.js.map
|
||||
@@ -0,0 +1,10 @@
|
||||
function normalizeValidator(validator) {
|
||||
if (validator.validate !== undefined) {
|
||||
return function (c) { return validator.validate(c); };
|
||||
}
|
||||
else {
|
||||
return validator;
|
||||
}
|
||||
}
|
||||
exports.normalizeValidator = normalizeValidator;
|
||||
//# sourceMappingURL=normalize_validator.js.map
|
||||
@@ -0,0 +1,56 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var render_1 = require('angular2/src/core/render');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var shared_1 = require('./shared');
|
||||
var NUMBER_VALUE_ACCESSOR = lang_1.CONST_EXPR(new di_1.Provider(control_value_accessor_1.NG_VALUE_ACCESSOR, { useExisting: di_1.forwardRef(function () { return NumberValueAccessor; }), multi: true }));
|
||||
/**
|
||||
* The accessor for writing a number value and listening to changes that is used by the
|
||||
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
|
||||
*
|
||||
* ### Example
|
||||
* ```
|
||||
* <input type="number" [(ng-model)]="age">
|
||||
* ```
|
||||
*/
|
||||
var NumberValueAccessor = (function () {
|
||||
function NumberValueAccessor(_renderer, _elementRef) {
|
||||
this._renderer = _renderer;
|
||||
this._elementRef = _elementRef;
|
||||
this.onChange = function (_) { };
|
||||
this.onTouched = function () { };
|
||||
}
|
||||
NumberValueAccessor.prototype.writeValue = function (value) { shared_1.setProperty(this._renderer, this._elementRef, 'value', value); };
|
||||
NumberValueAccessor.prototype.registerOnChange = function (fn) {
|
||||
this.onChange = function (value) { fn(lang_1.NumberWrapper.parseFloat(value)); };
|
||||
};
|
||||
NumberValueAccessor.prototype.registerOnTouched = function (fn) { this.onTouched = fn; };
|
||||
NumberValueAccessor = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: 'input[type=number][ng-control],input[type=number][ng-form-control],input[type=number][ng-model]',
|
||||
host: {
|
||||
'(change)': 'onChange($event.target.value)',
|
||||
'(input)': 'onChange($event.target.value)',
|
||||
'(blur)': 'onTouched()'
|
||||
},
|
||||
bindings: [NUMBER_VALUE_ACCESSOR]
|
||||
}),
|
||||
__metadata('design:paramtypes', [render_1.Renderer, linker_1.ElementRef])
|
||||
], NumberValueAccessor);
|
||||
return NumberValueAccessor;
|
||||
})();
|
||||
exports.NumberValueAccessor = NumberValueAccessor;
|
||||
//# sourceMappingURL=number_value_accessor.js.map
|
||||
@@ -0,0 +1,82 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var render_1 = require('angular2/src/core/render');
|
||||
var linker_1 = require('angular2/src/core/linker');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var control_value_accessor_1 = require('./control_value_accessor');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var shared_1 = require('./shared');
|
||||
var SELECT_VALUE_ACCESSOR = lang_1.CONST_EXPR(new di_1.Provider(control_value_accessor_1.NG_VALUE_ACCESSOR, { useExisting: di_1.forwardRef(function () { return SelectControlValueAccessor; }), multi: true }));
|
||||
/**
|
||||
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```
|
||||
* <select ng-control="city">
|
||||
* <option *ng-for="#c of cities" [value]="c"></option>
|
||||
* </select>
|
||||
* ```
|
||||
*/
|
||||
var NgSelectOption = (function () {
|
||||
function NgSelectOption() {
|
||||
}
|
||||
NgSelectOption = __decorate([
|
||||
metadata_1.Directive({ selector: 'option' }),
|
||||
__metadata('design:paramtypes', [])
|
||||
], NgSelectOption);
|
||||
return NgSelectOption;
|
||||
})();
|
||||
exports.NgSelectOption = NgSelectOption;
|
||||
/**
|
||||
* The accessor for writing a value and listening to changes on a select element.
|
||||
*/
|
||||
var SelectControlValueAccessor = (function () {
|
||||
function SelectControlValueAccessor(_renderer, _elementRef, query) {
|
||||
this._renderer = _renderer;
|
||||
this._elementRef = _elementRef;
|
||||
this.onChange = function (_) { };
|
||||
this.onTouched = function () { };
|
||||
this._updateValueWhenListOfOptionsChanges(query);
|
||||
}
|
||||
SelectControlValueAccessor.prototype.writeValue = function (value) {
|
||||
this.value = value;
|
||||
shared_1.setProperty(this._renderer, this._elementRef, "value", value);
|
||||
};
|
||||
SelectControlValueAccessor.prototype.registerOnChange = function (fn) { this.onChange = fn; };
|
||||
SelectControlValueAccessor.prototype.registerOnTouched = function (fn) { this.onTouched = fn; };
|
||||
SelectControlValueAccessor.prototype._updateValueWhenListOfOptionsChanges = function (query) {
|
||||
var _this = this;
|
||||
async_1.ObservableWrapper.subscribe(query.changes, function (_) { return _this.writeValue(_this.value); });
|
||||
};
|
||||
SelectControlValueAccessor = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: 'select[ng-control],select[ng-form-control],select[ng-model]',
|
||||
host: {
|
||||
'(change)': 'onChange($event.target.value)',
|
||||
'(input)': 'onChange($event.target.value)',
|
||||
'(blur)': 'onTouched()'
|
||||
},
|
||||
bindings: [SELECT_VALUE_ACCESSOR]
|
||||
}),
|
||||
__param(2, metadata_1.Query(NgSelectOption, { descendants: true })),
|
||||
__metadata('design:paramtypes', [render_1.Renderer, linker_1.ElementRef, linker_1.QueryList])
|
||||
], SelectControlValueAccessor);
|
||||
return SelectControlValueAccessor;
|
||||
})();
|
||||
exports.SelectControlValueAccessor = SelectControlValueAccessor;
|
||||
//# sourceMappingURL=select_control_value_accessor.js.map
|
||||
@@ -0,0 +1,101 @@
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
var validators_1 = require('../validators');
|
||||
var default_value_accessor_1 = require('./default_value_accessor');
|
||||
var number_value_accessor_1 = require('./number_value_accessor');
|
||||
var checkbox_value_accessor_1 = require('./checkbox_value_accessor');
|
||||
var select_control_value_accessor_1 = require('./select_control_value_accessor');
|
||||
var normalize_validator_1 = require('./normalize_validator');
|
||||
function controlPath(name, parent) {
|
||||
var p = collection_1.ListWrapper.clone(parent.path);
|
||||
p.push(name);
|
||||
return p;
|
||||
}
|
||||
exports.controlPath = controlPath;
|
||||
function setUpControl(control, dir) {
|
||||
if (lang_1.isBlank(control))
|
||||
_throwError(dir, "Cannot find control");
|
||||
if (lang_1.isBlank(dir.valueAccessor))
|
||||
_throwError(dir, "No value accessor for");
|
||||
control.validator = validators_1.Validators.compose([control.validator, dir.validator]);
|
||||
control.asyncValidator = validators_1.Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
|
||||
dir.valueAccessor.writeValue(control.value);
|
||||
// view -> model
|
||||
dir.valueAccessor.registerOnChange(function (newValue) {
|
||||
dir.viewToModelUpdate(newValue);
|
||||
control.updateValue(newValue, { emitModelToViewChange: false });
|
||||
control.markAsDirty();
|
||||
});
|
||||
// model -> view
|
||||
control.registerOnChange(function (newValue) { return dir.valueAccessor.writeValue(newValue); });
|
||||
// touched
|
||||
dir.valueAccessor.registerOnTouched(function () { return control.markAsTouched(); });
|
||||
}
|
||||
exports.setUpControl = setUpControl;
|
||||
function setUpControlGroup(control, dir) {
|
||||
if (lang_1.isBlank(control))
|
||||
_throwError(dir, "Cannot find control");
|
||||
control.validator = validators_1.Validators.compose([control.validator, dir.validator]);
|
||||
control.asyncValidator = validators_1.Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
|
||||
}
|
||||
exports.setUpControlGroup = setUpControlGroup;
|
||||
function _throwError(dir, message) {
|
||||
var path = dir.path.join(" -> ");
|
||||
throw new exceptions_1.BaseException(message + " '" + path + "'");
|
||||
}
|
||||
function setProperty(renderer, elementRef, propName, propValue) {
|
||||
renderer.setElementProperty(elementRef, propName, propValue);
|
||||
}
|
||||
exports.setProperty = setProperty;
|
||||
function composeValidators(validators) {
|
||||
return lang_1.isPresent(validators) ? validators_1.Validators.compose(validators.map(normalize_validator_1.normalizeValidator)) : null;
|
||||
}
|
||||
exports.composeValidators = composeValidators;
|
||||
function composeAsyncValidators(validators) {
|
||||
return lang_1.isPresent(validators) ? validators_1.Validators.composeAsync(validators.map(normalize_validator_1.normalizeValidator)) : null;
|
||||
}
|
||||
exports.composeAsyncValidators = composeAsyncValidators;
|
||||
function isPropertyUpdated(changes, viewModel) {
|
||||
if (!collection_1.StringMapWrapper.contains(changes, "model"))
|
||||
return false;
|
||||
var change = changes["model"];
|
||||
if (change.isFirstChange())
|
||||
return true;
|
||||
return !lang_1.looseIdentical(viewModel, change.currentValue);
|
||||
}
|
||||
exports.isPropertyUpdated = isPropertyUpdated;
|
||||
// TODO: vsavkin remove it once https://github.com/angular/angular/issues/3011 is implemented
|
||||
function selectValueAccessor(dir, valueAccessors) {
|
||||
if (lang_1.isBlank(valueAccessors))
|
||||
return null;
|
||||
var defaultAccessor;
|
||||
var builtinAccessor;
|
||||
var customAccessor;
|
||||
valueAccessors.forEach(function (v) {
|
||||
if (v instanceof default_value_accessor_1.DefaultValueAccessor) {
|
||||
defaultAccessor = v;
|
||||
}
|
||||
else if (v instanceof checkbox_value_accessor_1.CheckboxControlValueAccessor || v instanceof number_value_accessor_1.NumberValueAccessor ||
|
||||
v instanceof select_control_value_accessor_1.SelectControlValueAccessor) {
|
||||
if (lang_1.isPresent(builtinAccessor))
|
||||
_throwError(dir, "More than one built-in value accessor matches");
|
||||
builtinAccessor = v;
|
||||
}
|
||||
else {
|
||||
if (lang_1.isPresent(customAccessor))
|
||||
_throwError(dir, "More than one custom value accessor matches");
|
||||
customAccessor = v;
|
||||
}
|
||||
});
|
||||
if (lang_1.isPresent(customAccessor))
|
||||
return customAccessor;
|
||||
if (lang_1.isPresent(builtinAccessor))
|
||||
return builtinAccessor;
|
||||
if (lang_1.isPresent(defaultAccessor))
|
||||
return defaultAccessor;
|
||||
_throwError(dir, "No valid value accessor for");
|
||||
return null;
|
||||
}
|
||||
exports.selectValueAccessor = selectValueAccessor;
|
||||
//# sourceMappingURL=shared.js.map
|
||||
@@ -0,0 +1,78 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
||||
return function (target, key) { decorator(target, key, paramIndex); }
|
||||
};
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var validators_1 = require('../validators');
|
||||
var lang_2 = require("angular2/src/facade/lang");
|
||||
var REQUIRED_VALIDATOR = lang_1.CONST_EXPR(new di_1.Provider(validators_1.NG_VALIDATORS, { useValue: validators_1.Validators.required, multi: true }));
|
||||
/**
|
||||
* A Directive that adds the `required` validator to any controls marked with the
|
||||
* `required` attribute, via the {@link NG_VALIDATORS} binding.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ```
|
||||
* <input ng-control="fullName" required>
|
||||
* ```
|
||||
*/
|
||||
var RequiredValidator = (function () {
|
||||
function RequiredValidator() {
|
||||
}
|
||||
RequiredValidator = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[required][ng-control],[required][ng-form-control],[required][ng-model]',
|
||||
providers: [REQUIRED_VALIDATOR]
|
||||
}),
|
||||
__metadata('design:paramtypes', [])
|
||||
], RequiredValidator);
|
||||
return RequiredValidator;
|
||||
})();
|
||||
exports.RequiredValidator = RequiredValidator;
|
||||
var MIN_LENGTH_VALIDATOR = lang_1.CONST_EXPR(new di_1.Provider(validators_1.NG_VALIDATORS, { useExisting: di_1.forwardRef(function () { return MinLengthValidator; }), multi: true }));
|
||||
var MinLengthValidator = (function () {
|
||||
function MinLengthValidator(minLength) {
|
||||
this._validator = validators_1.Validators.minLength(lang_2.NumberWrapper.parseInt(minLength, 10));
|
||||
}
|
||||
MinLengthValidator.prototype.validate = function (c) { return this._validator(c); };
|
||||
MinLengthValidator = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[minlength][ng-control],[minlength][ng-form-control],[minlength][ng-model]',
|
||||
providers: [MIN_LENGTH_VALIDATOR]
|
||||
}),
|
||||
__param(0, metadata_1.Attribute("minlength")),
|
||||
__metadata('design:paramtypes', [String])
|
||||
], MinLengthValidator);
|
||||
return MinLengthValidator;
|
||||
})();
|
||||
exports.MinLengthValidator = MinLengthValidator;
|
||||
var MAX_LENGTH_VALIDATOR = lang_1.CONST_EXPR(new di_1.Provider(validators_1.NG_VALIDATORS, { useExisting: di_1.forwardRef(function () { return MaxLengthValidator; }), multi: true }));
|
||||
var MaxLengthValidator = (function () {
|
||||
function MaxLengthValidator(minLength) {
|
||||
this._validator = validators_1.Validators.maxLength(lang_2.NumberWrapper.parseInt(minLength, 10));
|
||||
}
|
||||
MaxLengthValidator.prototype.validate = function (c) { return this._validator(c); };
|
||||
MaxLengthValidator = __decorate([
|
||||
metadata_1.Directive({
|
||||
selector: '[maxlength][ng-control],[maxlength][ng-form-control],[maxlength][ng-model]',
|
||||
providers: [MAX_LENGTH_VALIDATOR]
|
||||
}),
|
||||
__param(0, metadata_1.Attribute("maxlength")),
|
||||
__metadata('design:paramtypes', [String])
|
||||
], MaxLengthValidator);
|
||||
return MaxLengthValidator;
|
||||
})();
|
||||
exports.MaxLengthValidator = MaxLengthValidator;
|
||||
//# sourceMappingURL=validators.js.map
|
||||
@@ -0,0 +1,140 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var modelModule = require('./model');
|
||||
/**
|
||||
* Creates a form object from a user-specified configuration.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/ENgZo8EuIECZNensZCVr?p=preview))
|
||||
*
|
||||
* ```typescript
|
||||
* @Component({
|
||||
* selector: 'my-app',
|
||||
* viewBindings: [FORM_BINDINGS]
|
||||
* template: `
|
||||
* <form [ng-form-model]="loginForm">
|
||||
* <p>Login <input ng-control="login"></p>
|
||||
* <div ng-control-group="passwordRetry">
|
||||
* <p>Password <input type="password" ng-control="password"></p>
|
||||
* <p>Confirm password <input type="password" ng-control="passwordConfirmation"></p>
|
||||
* </div>
|
||||
* </form>
|
||||
* <h3>Form value:</h3>
|
||||
* <pre>{{value}}</pre>
|
||||
* `,
|
||||
* directives: [FORM_DIRECTIVES]
|
||||
* })
|
||||
* export class App {
|
||||
* loginForm: ControlGroup;
|
||||
*
|
||||
* constructor(builder: FormBuilder) {
|
||||
* this.loginForm = builder.group({
|
||||
* login: ["", Validators.required],
|
||||
* passwordRetry: builder.group({
|
||||
* password: ["", Validators.required],
|
||||
* passwordConfirmation: ["", Validators.required, asyncValidator]
|
||||
* })
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* get value(): string {
|
||||
* return JSON.stringify(this.loginForm.value, null, 2);
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var FormBuilder = (function () {
|
||||
function FormBuilder() {
|
||||
}
|
||||
/**
|
||||
* Construct a new {@link ControlGroup} with the given map of configuration.
|
||||
* Valid keys for the `extra` parameter map are `optionals` and `validator`.
|
||||
*
|
||||
* See the {@link ControlGroup} constructor for more details.
|
||||
*/
|
||||
FormBuilder.prototype.group = function (controlsConfig, extra) {
|
||||
if (extra === void 0) { extra = null; }
|
||||
var controls = this._reduceControls(controlsConfig);
|
||||
var optionals = lang_1.isPresent(extra) ? collection_1.StringMapWrapper.get(extra, "optionals") : null;
|
||||
var validator = lang_1.isPresent(extra) ? collection_1.StringMapWrapper.get(extra, "validator") : null;
|
||||
var asyncValidator = lang_1.isPresent(extra) ? collection_1.StringMapWrapper.get(extra, "asyncValidator") : null;
|
||||
return new modelModule.ControlGroup(controls, optionals, validator, asyncValidator);
|
||||
};
|
||||
/**
|
||||
* Construct a new {@link Control} with the given `value`,`validator`, and `asyncValidator`.
|
||||
*/
|
||||
FormBuilder.prototype.control = function (value, validator, asyncValidator) {
|
||||
if (validator === void 0) { validator = null; }
|
||||
if (asyncValidator === void 0) { asyncValidator = null; }
|
||||
return new modelModule.Control(value, validator, asyncValidator);
|
||||
};
|
||||
/**
|
||||
* Construct an array of {@link Control}s from the given `controlsConfig` array of
|
||||
* configuration, with the given optional `validator` and `asyncValidator`.
|
||||
*/
|
||||
FormBuilder.prototype.array = function (controlsConfig, validator, asyncValidator) {
|
||||
var _this = this;
|
||||
if (validator === void 0) { validator = null; }
|
||||
if (asyncValidator === void 0) { asyncValidator = null; }
|
||||
var controls = controlsConfig.map(function (c) { return _this._createControl(c); });
|
||||
return new modelModule.ControlArray(controls, validator, asyncValidator);
|
||||
};
|
||||
/** @internal */
|
||||
FormBuilder.prototype._reduceControls = function (controlsConfig) {
|
||||
var _this = this;
|
||||
var controls = {};
|
||||
collection_1.StringMapWrapper.forEach(controlsConfig, function (controlConfig, controlName) {
|
||||
controls[controlName] = _this._createControl(controlConfig);
|
||||
});
|
||||
return controls;
|
||||
};
|
||||
/** @internal */
|
||||
FormBuilder.prototype._createControl = function (controlConfig) {
|
||||
if (controlConfig instanceof modelModule.Control ||
|
||||
controlConfig instanceof modelModule.ControlGroup ||
|
||||
controlConfig instanceof modelModule.ControlArray) {
|
||||
return controlConfig;
|
||||
}
|
||||
else if (lang_1.isArray(controlConfig)) {
|
||||
var value = controlConfig[0];
|
||||
var validator = controlConfig.length > 1 ? controlConfig[1] : null;
|
||||
var asyncValidator = controlConfig.length > 2 ? controlConfig[2] : null;
|
||||
return this.control(value, validator, asyncValidator);
|
||||
}
|
||||
else {
|
||||
return this.control(controlConfig);
|
||||
}
|
||||
};
|
||||
FormBuilder = __decorate([
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], FormBuilder);
|
||||
return FormBuilder;
|
||||
})();
|
||||
exports.FormBuilder = FormBuilder;
|
||||
/**
|
||||
* Shorthand set of providers used for building Angular forms.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* bootstrap(MyApp, [FORM_PROVIDERS]);
|
||||
* ```
|
||||
*/
|
||||
exports.FORM_PROVIDERS = lang_1.CONST_EXPR([FormBuilder]);
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
exports.FORM_BINDINGS = exports.FORM_PROVIDERS;
|
||||
//# sourceMappingURL=form_builder.js.map
|
||||
@@ -0,0 +1,489 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var promise_1 = require('angular2/src/facade/promise');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
/**
|
||||
* Indicates that a Control is valid, i.e. that no errors exist in the input value.
|
||||
*/
|
||||
exports.VALID = "VALID";
|
||||
/**
|
||||
* Indicates that a Control is invalid, i.e. that an error exists in the input value.
|
||||
*/
|
||||
exports.INVALID = "INVALID";
|
||||
/**
|
||||
* Indicates that a Control is pending, i.e. that async validation is occuring and
|
||||
* errors are not yet available for the input value.
|
||||
*/
|
||||
exports.PENDING = "PENDING";
|
||||
function isControl(control) {
|
||||
return control instanceof AbstractControl;
|
||||
}
|
||||
exports.isControl = isControl;
|
||||
function _find(control, path) {
|
||||
if (lang_1.isBlank(path))
|
||||
return null;
|
||||
if (!(path instanceof Array)) {
|
||||
path = path.split("/");
|
||||
}
|
||||
if (path instanceof Array && collection_1.ListWrapper.isEmpty(path))
|
||||
return null;
|
||||
return path
|
||||
.reduce(function (v, name) {
|
||||
if (v instanceof ControlGroup) {
|
||||
return lang_1.isPresent(v.controls[name]) ? v.controls[name] : null;
|
||||
}
|
||||
else if (v instanceof ControlArray) {
|
||||
var index = name;
|
||||
return lang_1.isPresent(v.at(index)) ? v.at(index) : null;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}, control);
|
||||
}
|
||||
function toObservable(r) {
|
||||
return promise_1.PromiseWrapper.isPromise(r) ? async_1.ObservableWrapper.fromPromise(r) : r;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
var AbstractControl = (function () {
|
||||
function AbstractControl(validator, asyncValidator) {
|
||||
this.validator = validator;
|
||||
this.asyncValidator = asyncValidator;
|
||||
this._pristine = true;
|
||||
this._touched = false;
|
||||
}
|
||||
Object.defineProperty(AbstractControl.prototype, "value", {
|
||||
get: function () { return this._value; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "status", {
|
||||
get: function () { return this._status; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "valid", {
|
||||
get: function () { return this._status === exports.VALID; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "errors", {
|
||||
/**
|
||||
* Returns the errors of this control.
|
||||
*/
|
||||
get: function () { return this._errors; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "pristine", {
|
||||
get: function () { return this._pristine; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "dirty", {
|
||||
get: function () { return !this.pristine; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "touched", {
|
||||
get: function () { return this._touched; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "untouched", {
|
||||
get: function () { return !this._touched; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "valueChanges", {
|
||||
get: function () { return this._valueChanges; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "statusChanges", {
|
||||
get: function () { return this._statusChanges; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(AbstractControl.prototype, "pending", {
|
||||
get: function () { return this._status == exports.PENDING; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
AbstractControl.prototype.markAsTouched = function () { this._touched = true; };
|
||||
AbstractControl.prototype.markAsDirty = function (_a) {
|
||||
var onlySelf = (_a === void 0 ? {} : _a).onlySelf;
|
||||
onlySelf = lang_1.normalizeBool(onlySelf);
|
||||
this._pristine = false;
|
||||
if (lang_1.isPresent(this._parent) && !onlySelf) {
|
||||
this._parent.markAsDirty({ onlySelf: onlySelf });
|
||||
}
|
||||
};
|
||||
AbstractControl.prototype.markAsPending = function (_a) {
|
||||
var onlySelf = (_a === void 0 ? {} : _a).onlySelf;
|
||||
onlySelf = lang_1.normalizeBool(onlySelf);
|
||||
this._status = exports.PENDING;
|
||||
if (lang_1.isPresent(this._parent) && !onlySelf) {
|
||||
this._parent.markAsPending({ onlySelf: onlySelf });
|
||||
}
|
||||
};
|
||||
AbstractControl.prototype.setParent = function (parent) { this._parent = parent; };
|
||||
AbstractControl.prototype.updateValueAndValidity = function (_a) {
|
||||
var _b = _a === void 0 ? {} : _a, onlySelf = _b.onlySelf, emitEvent = _b.emitEvent;
|
||||
onlySelf = lang_1.normalizeBool(onlySelf);
|
||||
emitEvent = lang_1.isPresent(emitEvent) ? emitEvent : true;
|
||||
this._updateValue();
|
||||
this._errors = this._runValidator();
|
||||
this._status = this._calculateStatus();
|
||||
if (this._status == exports.VALID || this._status == exports.PENDING) {
|
||||
this._runAsyncValidator(emitEvent);
|
||||
}
|
||||
if (emitEvent) {
|
||||
async_1.ObservableWrapper.callNext(this._valueChanges, this._value);
|
||||
async_1.ObservableWrapper.callNext(this._statusChanges, this._status);
|
||||
}
|
||||
if (lang_1.isPresent(this._parent) && !onlySelf) {
|
||||
this._parent.updateValueAndValidity({ onlySelf: onlySelf, emitEvent: emitEvent });
|
||||
}
|
||||
};
|
||||
AbstractControl.prototype._runValidator = function () { return lang_1.isPresent(this.validator) ? this.validator(this) : null; };
|
||||
AbstractControl.prototype._runAsyncValidator = function (emitEvent) {
|
||||
var _this = this;
|
||||
if (lang_1.isPresent(this.asyncValidator)) {
|
||||
this._status = exports.PENDING;
|
||||
this._cancelExistingSubscription();
|
||||
var obs = toObservable(this.asyncValidator(this));
|
||||
this._asyncValidationSubscription =
|
||||
async_1.ObservableWrapper.subscribe(obs, function (res) { return _this.setErrors(res, { emitEvent: emitEvent }); });
|
||||
}
|
||||
};
|
||||
AbstractControl.prototype._cancelExistingSubscription = function () {
|
||||
if (lang_1.isPresent(this._asyncValidationSubscription)) {
|
||||
async_1.ObservableWrapper.dispose(this._asyncValidationSubscription);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Sets errors on a control.
|
||||
*
|
||||
* This is used when validations are run not automatically, but manually by the user.
|
||||
*
|
||||
* Calling `setErrors` will also update the validity of the parent control.
|
||||
*
|
||||
* ## Usage
|
||||
*
|
||||
* ```
|
||||
* var login = new Control("someLogin");
|
||||
* login.setErrors({
|
||||
* "notUnique": true
|
||||
* });
|
||||
*
|
||||
* expect(login.valid).toEqual(false);
|
||||
* expect(login.errors).toEqual({"notUnique": true});
|
||||
*
|
||||
* login.updateValue("someOtherLogin");
|
||||
*
|
||||
* expect(login.valid).toEqual(true);
|
||||
* ```
|
||||
*/
|
||||
AbstractControl.prototype.setErrors = function (errors, _a) {
|
||||
var emitEvent = (_a === void 0 ? {} : _a).emitEvent;
|
||||
emitEvent = lang_1.isPresent(emitEvent) ? emitEvent : true;
|
||||
this._errors = errors;
|
||||
this._status = this._calculateStatus();
|
||||
if (emitEvent) {
|
||||
async_1.ObservableWrapper.callNext(this._statusChanges, this._status);
|
||||
}
|
||||
if (lang_1.isPresent(this._parent)) {
|
||||
this._parent._updateControlsErrors();
|
||||
}
|
||||
};
|
||||
AbstractControl.prototype.find = function (path) { return _find(this, path); };
|
||||
AbstractControl.prototype.getError = function (errorCode, path) {
|
||||
if (path === void 0) { path = null; }
|
||||
var control = lang_1.isPresent(path) && !collection_1.ListWrapper.isEmpty(path) ? this.find(path) : this;
|
||||
if (lang_1.isPresent(control) && lang_1.isPresent(control._errors)) {
|
||||
return collection_1.StringMapWrapper.get(control._errors, errorCode);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
AbstractControl.prototype.hasError = function (errorCode, path) {
|
||||
if (path === void 0) { path = null; }
|
||||
return lang_1.isPresent(this.getError(errorCode, path));
|
||||
};
|
||||
/** @internal */
|
||||
AbstractControl.prototype._updateControlsErrors = function () {
|
||||
this._status = this._calculateStatus();
|
||||
if (lang_1.isPresent(this._parent)) {
|
||||
this._parent._updateControlsErrors();
|
||||
}
|
||||
};
|
||||
/** @internal */
|
||||
AbstractControl.prototype._initObservables = function () {
|
||||
this._valueChanges = new async_1.EventEmitter();
|
||||
this._statusChanges = new async_1.EventEmitter();
|
||||
};
|
||||
AbstractControl.prototype._calculateStatus = function () {
|
||||
if (lang_1.isPresent(this._errors))
|
||||
return exports.INVALID;
|
||||
if (this._anyControlsHaveStatus(exports.PENDING))
|
||||
return exports.PENDING;
|
||||
if (this._anyControlsHaveStatus(exports.INVALID))
|
||||
return exports.INVALID;
|
||||
return exports.VALID;
|
||||
};
|
||||
return AbstractControl;
|
||||
})();
|
||||
exports.AbstractControl = AbstractControl;
|
||||
/**
|
||||
* Defines a part of a form that cannot be divided into other controls. `Control`s have values and
|
||||
* validation state, which is determined by an optional validation function.
|
||||
*
|
||||
* `Control` is one of the three fundamental building blocks used to define forms in Angular, along
|
||||
* with {@link ControlGroup} and {@link ControlArray}.
|
||||
*
|
||||
* ##Usage
|
||||
*
|
||||
* By default, a `Control` is created for every `<input>` or other form component.
|
||||
* With {@link NgFormControl} or {@link NgFormModel} an existing {@link Control} can be
|
||||
* bound to a DOM element instead. This `Control` can be configured with a custom
|
||||
* validation function.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
|
||||
*/
|
||||
var Control = (function (_super) {
|
||||
__extends(Control, _super);
|
||||
function Control(value, validator, asyncValidator) {
|
||||
if (value === void 0) { value = null; }
|
||||
if (validator === void 0) { validator = null; }
|
||||
if (asyncValidator === void 0) { asyncValidator = null; }
|
||||
_super.call(this, validator, asyncValidator);
|
||||
this._value = value;
|
||||
this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
this._initObservables();
|
||||
}
|
||||
/**
|
||||
* Set the value of the control to `value`.
|
||||
*
|
||||
* If `onlySelf` is `true`, this change will only affect the validation of this `Control`
|
||||
* and not its parent component. If `emitEvent` is `true`, this change will cause a
|
||||
* `valueChanges` event on the `Control` to be emitted. Both of these options default to
|
||||
* `false`.
|
||||
*
|
||||
* If `emitModelToViewChange` is `true`, the view will be notified about the new value
|
||||
* via an `onChange` event. This is the default behavior if `emitModelToViewChange` is not
|
||||
* specified.
|
||||
*/
|
||||
Control.prototype.updateValue = function (value, _a) {
|
||||
var _b = _a === void 0 ? {} : _a, onlySelf = _b.onlySelf, emitEvent = _b.emitEvent, emitModelToViewChange = _b.emitModelToViewChange;
|
||||
emitModelToViewChange = lang_1.isPresent(emitModelToViewChange) ? emitModelToViewChange : true;
|
||||
this._value = value;
|
||||
if (lang_1.isPresent(this._onChange) && emitModelToViewChange)
|
||||
this._onChange(this._value);
|
||||
this.updateValueAndValidity({ onlySelf: onlySelf, emitEvent: emitEvent });
|
||||
};
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
Control.prototype._updateValue = function () { };
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
Control.prototype._anyControlsHaveStatus = function (status) { return false; };
|
||||
/**
|
||||
* Register a listener for change events.
|
||||
*/
|
||||
Control.prototype.registerOnChange = function (fn) { this._onChange = fn; };
|
||||
return Control;
|
||||
})(AbstractControl);
|
||||
exports.Control = Control;
|
||||
/**
|
||||
* Defines a part of a form, of fixed length, that can contain other controls.
|
||||
*
|
||||
* A `ControlGroup` aggregates the values and errors of each {@link Control} in the group. Thus, if
|
||||
* one of the controls in a group is invalid, the entire group is invalid. Similarly, if a control
|
||||
* changes its value, the entire group changes as well.
|
||||
*
|
||||
* `ControlGroup` is one of the three fundamental building blocks used to define forms in Angular,
|
||||
* along with {@link Control} and {@link ControlArray}. {@link ControlArray} can also contain other
|
||||
* controls, but is of variable length.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
|
||||
*/
|
||||
var ControlGroup = (function (_super) {
|
||||
__extends(ControlGroup, _super);
|
||||
function ControlGroup(controls, optionals, validator, asyncValidator) {
|
||||
if (optionals === void 0) { optionals = null; }
|
||||
if (validator === void 0) { validator = null; }
|
||||
if (asyncValidator === void 0) { asyncValidator = null; }
|
||||
_super.call(this, validator, asyncValidator);
|
||||
this.controls = controls;
|
||||
this._optionals = lang_1.isPresent(optionals) ? optionals : {};
|
||||
this._initObservables();
|
||||
this._setParentForControls();
|
||||
this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
}
|
||||
/**
|
||||
* Add a control to this group.
|
||||
*/
|
||||
ControlGroup.prototype.addControl = function (name, control) {
|
||||
this.controls[name] = control;
|
||||
control.setParent(this);
|
||||
};
|
||||
/**
|
||||
* Remove a control from this group.
|
||||
*/
|
||||
ControlGroup.prototype.removeControl = function (name) { collection_1.StringMapWrapper.delete(this.controls, name); };
|
||||
/**
|
||||
* Mark the named control as non-optional.
|
||||
*/
|
||||
ControlGroup.prototype.include = function (controlName) {
|
||||
collection_1.StringMapWrapper.set(this._optionals, controlName, true);
|
||||
this.updateValueAndValidity();
|
||||
};
|
||||
/**
|
||||
* Mark the named control as optional.
|
||||
*/
|
||||
ControlGroup.prototype.exclude = function (controlName) {
|
||||
collection_1.StringMapWrapper.set(this._optionals, controlName, false);
|
||||
this.updateValueAndValidity();
|
||||
};
|
||||
/**
|
||||
* Check whether there is a control with the given name in the group.
|
||||
*/
|
||||
ControlGroup.prototype.contains = function (controlName) {
|
||||
var c = collection_1.StringMapWrapper.contains(this.controls, controlName);
|
||||
return c && this._included(controlName);
|
||||
};
|
||||
/** @internal */
|
||||
ControlGroup.prototype._setParentForControls = function () {
|
||||
var _this = this;
|
||||
collection_1.StringMapWrapper.forEach(this.controls, function (control, name) { control.setParent(_this); });
|
||||
};
|
||||
/** @internal */
|
||||
ControlGroup.prototype._updateValue = function () { this._value = this._reduceValue(); };
|
||||
/** @internal */
|
||||
ControlGroup.prototype._anyControlsHaveStatus = function (status) {
|
||||
var _this = this;
|
||||
var res = false;
|
||||
collection_1.StringMapWrapper.forEach(this.controls, function (control, name) {
|
||||
res = res || (_this.contains(name) && control.status == status);
|
||||
});
|
||||
return res;
|
||||
};
|
||||
/** @internal */
|
||||
ControlGroup.prototype._reduceValue = function () {
|
||||
return this._reduceChildren({}, function (acc, control, name) {
|
||||
acc[name] = control.value;
|
||||
return acc;
|
||||
});
|
||||
};
|
||||
/** @internal */
|
||||
ControlGroup.prototype._reduceChildren = function (initValue, fn) {
|
||||
var _this = this;
|
||||
var res = initValue;
|
||||
collection_1.StringMapWrapper.forEach(this.controls, function (control, name) {
|
||||
if (_this._included(name)) {
|
||||
res = fn(res, control, name);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
};
|
||||
/** @internal */
|
||||
ControlGroup.prototype._included = function (controlName) {
|
||||
var isOptional = collection_1.StringMapWrapper.contains(this._optionals, controlName);
|
||||
return !isOptional || collection_1.StringMapWrapper.get(this._optionals, controlName);
|
||||
};
|
||||
return ControlGroup;
|
||||
})(AbstractControl);
|
||||
exports.ControlGroup = ControlGroup;
|
||||
/**
|
||||
* Defines a part of a form, of variable length, that can contain other controls.
|
||||
*
|
||||
* A `ControlArray` aggregates the values and errors of each {@link Control} in the group. Thus, if
|
||||
* one of the controls in a group is invalid, the entire group is invalid. Similarly, if a control
|
||||
* changes its value, the entire group changes as well.
|
||||
*
|
||||
* `ControlArray` is one of the three fundamental building blocks used to define forms in Angular,
|
||||
* along with {@link Control} and {@link ControlGroup}. {@link ControlGroup} can also contain
|
||||
* other controls, but is of fixed length.
|
||||
*
|
||||
* ##Adding or removing controls
|
||||
*
|
||||
* To change the controls in the array, use the `push`, `insert`, or `removeAt` methods
|
||||
* in `ControlArray` itself. These methods ensure the controls are properly tracked in the
|
||||
* form's hierarchy. Do not modify the array of `AbstractControl`s used to instantiate
|
||||
* the `ControlArray` directly, as that will result in strange and unexpected behavior such
|
||||
* as broken change detection.
|
||||
*
|
||||
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
|
||||
*/
|
||||
var ControlArray = (function (_super) {
|
||||
__extends(ControlArray, _super);
|
||||
function ControlArray(controls, validator, asyncValidator) {
|
||||
if (validator === void 0) { validator = null; }
|
||||
if (asyncValidator === void 0) { asyncValidator = null; }
|
||||
_super.call(this, validator, asyncValidator);
|
||||
this.controls = controls;
|
||||
this._initObservables();
|
||||
this._setParentForControls();
|
||||
this.updateValueAndValidity({ onlySelf: true, emitEvent: false });
|
||||
}
|
||||
/**
|
||||
* Get the {@link AbstractControl} at the given `index` in the array.
|
||||
*/
|
||||
ControlArray.prototype.at = function (index) { return this.controls[index]; };
|
||||
/**
|
||||
* Insert a new {@link AbstractControl} at the end of the array.
|
||||
*/
|
||||
ControlArray.prototype.push = function (control) {
|
||||
this.controls.push(control);
|
||||
control.setParent(this);
|
||||
this.updateValueAndValidity();
|
||||
};
|
||||
/**
|
||||
* Insert a new {@link AbstractControl} at the given `index` in the array.
|
||||
*/
|
||||
ControlArray.prototype.insert = function (index, control) {
|
||||
collection_1.ListWrapper.insert(this.controls, index, control);
|
||||
control.setParent(this);
|
||||
this.updateValueAndValidity();
|
||||
};
|
||||
/**
|
||||
* Remove the control at the given `index` in the array.
|
||||
*/
|
||||
ControlArray.prototype.removeAt = function (index) {
|
||||
collection_1.ListWrapper.removeAt(this.controls, index);
|
||||
this.updateValueAndValidity();
|
||||
};
|
||||
Object.defineProperty(ControlArray.prototype, "length", {
|
||||
/**
|
||||
* Length of the control array.
|
||||
*/
|
||||
get: function () { return this.controls.length; },
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
/** @internal */
|
||||
ControlArray.prototype._updateValue = function () { this._value = this.controls.map(function (control) { return control.value; }); };
|
||||
/** @internal */
|
||||
ControlArray.prototype._anyControlsHaveStatus = function (status) {
|
||||
return this.controls.some(function (c) { return c.status == status; });
|
||||
};
|
||||
/** @internal */
|
||||
ControlArray.prototype._setParentForControls = function () {
|
||||
var _this = this;
|
||||
this.controls.forEach(function (control) { control.setParent(_this); });
|
||||
};
|
||||
return ControlArray;
|
||||
})(AbstractControl);
|
||||
exports.ControlArray = ControlArray;
|
||||
//# sourceMappingURL=model.js.map
|
||||
@@ -0,0 +1,113 @@
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var promise_1 = require('angular2/src/facade/promise');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
/**
|
||||
* Providers for validators to be used for {@link Control}s in a form.
|
||||
*
|
||||
* Provide this using `multi: true` to add validators.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```typescript
|
||||
* var providers = [
|
||||
* new Provider(NG_VALIDATORS, {useValue: myValidator, multi: true})
|
||||
* ];
|
||||
* ```
|
||||
*/
|
||||
exports.NG_VALIDATORS = lang_1.CONST_EXPR(new di_1.OpaqueToken("NgValidators"));
|
||||
exports.NG_ASYNC_VALIDATORS = lang_1.CONST_EXPR(new di_1.OpaqueToken("NgAsyncValidators"));
|
||||
/**
|
||||
* Provides a set of validators used by form controls.
|
||||
*
|
||||
* A validator is a function that processes a {@link Control} or collection of
|
||||
* controls and returns a {@link StringMap} of errors. A null map means that
|
||||
* validation has passed.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* ```typescript
|
||||
* var loginControl = new Control("", Validators.required)
|
||||
* ```
|
||||
*/
|
||||
var Validators = (function () {
|
||||
function Validators() {
|
||||
}
|
||||
/**
|
||||
* Validator that requires controls to have a non-empty value.
|
||||
*/
|
||||
Validators.required = function (control) {
|
||||
return lang_1.isBlank(control.value) || control.value == "" ? { "required": true } : null;
|
||||
};
|
||||
/**
|
||||
* Validator that requires controls to have a value of a minimum length.
|
||||
*/
|
||||
Validators.minLength = function (minLength) {
|
||||
return function (control) {
|
||||
if (lang_1.isPresent(Validators.required(control)))
|
||||
return null;
|
||||
var v = control.value;
|
||||
return v.length < minLength ?
|
||||
{ "minlength": { "requiredLength": minLength, "actualLength": v.length } } :
|
||||
null;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Validator that requires controls to have a value of a maximum length.
|
||||
*/
|
||||
Validators.maxLength = function (maxLength) {
|
||||
return function (control) {
|
||||
if (lang_1.isPresent(Validators.required(control)))
|
||||
return null;
|
||||
var v = control.value;
|
||||
return v.length > maxLength ?
|
||||
{ "maxlength": { "requiredLength": maxLength, "actualLength": v.length } } :
|
||||
null;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* No-op validator.
|
||||
*/
|
||||
Validators.nullValidator = function (c) { return null; };
|
||||
/**
|
||||
* Compose multiple validators into a single function that returns the union
|
||||
* of the individual error maps.
|
||||
*/
|
||||
Validators.compose = function (validators) {
|
||||
if (lang_1.isBlank(validators))
|
||||
return null;
|
||||
var presentValidators = validators.filter(lang_1.isPresent);
|
||||
if (presentValidators.length == 0)
|
||||
return null;
|
||||
return function (control) {
|
||||
return _mergeErrors(_executeValidators(control, presentValidators));
|
||||
};
|
||||
};
|
||||
Validators.composeAsync = function (validators) {
|
||||
if (lang_1.isBlank(validators))
|
||||
return null;
|
||||
var presentValidators = validators.filter(lang_1.isPresent);
|
||||
if (presentValidators.length == 0)
|
||||
return null;
|
||||
return function (control) {
|
||||
var promises = _executeValidators(control, presentValidators).map(_convertToPromise);
|
||||
return promise_1.PromiseWrapper.all(promises).then(_mergeErrors);
|
||||
};
|
||||
};
|
||||
return Validators;
|
||||
})();
|
||||
exports.Validators = Validators;
|
||||
function _convertToPromise(obj) {
|
||||
return promise_1.PromiseWrapper.isPromise(obj) ? obj : async_1.ObservableWrapper.toPromise(obj);
|
||||
}
|
||||
function _executeValidators(control, validators) {
|
||||
return validators.map(function (v) { return v(control); });
|
||||
}
|
||||
function _mergeErrors(arrayOfErrors) {
|
||||
var res = arrayOfErrors.reduce(function (res, errors) {
|
||||
return lang_1.isPresent(errors) ? collection_1.StringMapWrapper.merge(res, errors) : res;
|
||||
}, {});
|
||||
return collection_1.StringMapWrapper.isEmpty(res) ? null : res;
|
||||
}
|
||||
//# sourceMappingURL=validators.js.map
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* This module provides a set of common Pipes.
|
||||
*/
|
||||
var async_pipe_1 = require('./pipes/async_pipe');
|
||||
var uppercase_pipe_1 = require('./pipes/uppercase_pipe');
|
||||
var lowercase_pipe_1 = require('./pipes/lowercase_pipe');
|
||||
var json_pipe_1 = require('./pipes/json_pipe');
|
||||
var slice_pipe_1 = require('./pipes/slice_pipe');
|
||||
var date_pipe_1 = require('./pipes/date_pipe');
|
||||
var number_pipe_1 = require('./pipes/number_pipe');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var async_pipe_2 = require('./pipes/async_pipe');
|
||||
exports.AsyncPipe = async_pipe_2.AsyncPipe;
|
||||
var date_pipe_2 = require('./pipes/date_pipe');
|
||||
exports.DatePipe = date_pipe_2.DatePipe;
|
||||
var json_pipe_2 = require('./pipes/json_pipe');
|
||||
exports.JsonPipe = json_pipe_2.JsonPipe;
|
||||
var slice_pipe_2 = require('./pipes/slice_pipe');
|
||||
exports.SlicePipe = slice_pipe_2.SlicePipe;
|
||||
var lowercase_pipe_2 = require('./pipes/lowercase_pipe');
|
||||
exports.LowerCasePipe = lowercase_pipe_2.LowerCasePipe;
|
||||
var number_pipe_2 = require('./pipes/number_pipe');
|
||||
exports.NumberPipe = number_pipe_2.NumberPipe;
|
||||
exports.DecimalPipe = number_pipe_2.DecimalPipe;
|
||||
exports.PercentPipe = number_pipe_2.PercentPipe;
|
||||
exports.CurrencyPipe = number_pipe_2.CurrencyPipe;
|
||||
var uppercase_pipe_2 = require('./pipes/uppercase_pipe');
|
||||
exports.UpperCasePipe = uppercase_pipe_2.UpperCasePipe;
|
||||
exports.COMMON_PIPES = lang_1.CONST_EXPR([
|
||||
async_pipe_1.AsyncPipe,
|
||||
uppercase_pipe_1.UpperCasePipe,
|
||||
lowercase_pipe_1.LowerCasePipe,
|
||||
json_pipe_1.JsonPipe,
|
||||
slice_pipe_1.SlicePipe,
|
||||
number_pipe_1.DecimalPipe,
|
||||
number_pipe_1.PercentPipe,
|
||||
number_pipe_1.CurrencyPipe,
|
||||
date_pipe_1.DatePipe
|
||||
]);
|
||||
//# sourceMappingURL=pipes.js.map
|
||||
@@ -0,0 +1,143 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var async_1 = require('angular2/src/facade/async');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var change_detection_1 = require('angular2/src/core/change_detection');
|
||||
var invalid_pipe_argument_exception_1 = require('./invalid_pipe_argument_exception');
|
||||
var ObservableStrategy = (function () {
|
||||
function ObservableStrategy() {
|
||||
}
|
||||
ObservableStrategy.prototype.createSubscription = function (async, updateLatestValue) {
|
||||
return async_1.ObservableWrapper.subscribe(async, updateLatestValue, function (e) { throw e; });
|
||||
};
|
||||
ObservableStrategy.prototype.dispose = function (subscription) { async_1.ObservableWrapper.dispose(subscription); };
|
||||
ObservableStrategy.prototype.onDestroy = function (subscription) { async_1.ObservableWrapper.dispose(subscription); };
|
||||
return ObservableStrategy;
|
||||
})();
|
||||
var PromiseStrategy = (function () {
|
||||
function PromiseStrategy() {
|
||||
}
|
||||
PromiseStrategy.prototype.createSubscription = function (async, updateLatestValue) {
|
||||
return async.then(updateLatestValue);
|
||||
};
|
||||
PromiseStrategy.prototype.dispose = function (subscription) { };
|
||||
PromiseStrategy.prototype.onDestroy = function (subscription) { };
|
||||
return PromiseStrategy;
|
||||
})();
|
||||
var _promiseStrategy = new PromiseStrategy();
|
||||
var _observableStrategy = new ObservableStrategy();
|
||||
/**
|
||||
* The `async` pipe subscribes to an Observable or Promise and returns the latest value it has
|
||||
* emitted.
|
||||
* When a new value is emitted, the `async` pipe marks the component to be checked for changes.
|
||||
*
|
||||
* ### Example
|
||||
* The example below binds the `time` Observable to the view. Every 500ms, the `time` Observable
|
||||
* updates the view with the current time.
|
||||
*
|
||||
* ```
|
||||
* import {Observable} from 'angular2/core';
|
||||
* @Component({
|
||||
* selector: "task-cmp",
|
||||
* template: "Time: {{ time | async }}"
|
||||
* })
|
||||
* class Task {
|
||||
* time = new Observable<number>(observer => {
|
||||
* setInterval(_ =>
|
||||
* observer.next(new Date().getTime()), 500);
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
var AsyncPipe = (function () {
|
||||
function AsyncPipe(_ref) {
|
||||
/** @internal */
|
||||
this._latestValue = null;
|
||||
/** @internal */
|
||||
this._latestReturnedValue = null;
|
||||
/** @internal */
|
||||
this._subscription = null;
|
||||
/** @internal */
|
||||
this._obj = null;
|
||||
this._strategy = null;
|
||||
this._ref = _ref;
|
||||
}
|
||||
AsyncPipe.prototype.onDestroy = function () {
|
||||
if (lang_1.isPresent(this._subscription)) {
|
||||
this._dispose();
|
||||
}
|
||||
};
|
||||
AsyncPipe.prototype.transform = function (obj, args) {
|
||||
if (lang_1.isBlank(this._obj)) {
|
||||
if (lang_1.isPresent(obj)) {
|
||||
this._subscribe(obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (obj !== this._obj) {
|
||||
this._dispose();
|
||||
return this.transform(obj);
|
||||
}
|
||||
if (this._latestValue === this._latestReturnedValue) {
|
||||
return this._latestReturnedValue;
|
||||
}
|
||||
else {
|
||||
this._latestReturnedValue = this._latestValue;
|
||||
return change_detection_1.WrappedValue.wrap(this._latestValue);
|
||||
}
|
||||
};
|
||||
/** @internal */
|
||||
AsyncPipe.prototype._subscribe = function (obj) {
|
||||
var _this = this;
|
||||
this._obj = obj;
|
||||
this._strategy = this._selectStrategy(obj);
|
||||
this._subscription =
|
||||
this._strategy.createSubscription(obj, function (value) { return _this._updateLatestValue(obj, value); });
|
||||
};
|
||||
/** @internal */
|
||||
AsyncPipe.prototype._selectStrategy = function (obj) {
|
||||
if (lang_1.isPromise(obj)) {
|
||||
return _promiseStrategy;
|
||||
}
|
||||
else if (async_1.ObservableWrapper.isObservable(obj)) {
|
||||
return _observableStrategy;
|
||||
}
|
||||
else {
|
||||
throw new invalid_pipe_argument_exception_1.InvalidPipeArgumentException(AsyncPipe, obj);
|
||||
}
|
||||
};
|
||||
/** @internal */
|
||||
AsyncPipe.prototype._dispose = function () {
|
||||
this._strategy.dispose(this._subscription);
|
||||
this._latestValue = null;
|
||||
this._latestReturnedValue = null;
|
||||
this._subscription = null;
|
||||
this._obj = null;
|
||||
};
|
||||
/** @internal */
|
||||
AsyncPipe.prototype._updateLatestValue = function (async, value) {
|
||||
if (async === this._obj) {
|
||||
this._latestValue = value;
|
||||
this._ref.markForCheck();
|
||||
}
|
||||
};
|
||||
AsyncPipe = __decorate([
|
||||
metadata_1.Pipe({ name: 'async', pure: false }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [change_detection_1.ChangeDetectorRef])
|
||||
], AsyncPipe);
|
||||
return AsyncPipe;
|
||||
})();
|
||||
exports.AsyncPipe = AsyncPipe;
|
||||
//# sourceMappingURL=async_pipe.js.map
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* This module provides a set of common Pipes.
|
||||
*/
|
||||
var async_pipe_1 = require('./async_pipe');
|
||||
var uppercase_pipe_1 = require('./uppercase_pipe');
|
||||
var lowercase_pipe_1 = require('./lowercase_pipe');
|
||||
var json_pipe_1 = require('./json_pipe');
|
||||
var slice_pipe_1 = require('./slice_pipe');
|
||||
var date_pipe_1 = require('./date_pipe');
|
||||
var number_pipe_1 = require('./number_pipe');
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
exports.COMMON_PIPES = lang_1.CONST_EXPR([
|
||||
async_pipe_1.AsyncPipe,
|
||||
uppercase_pipe_1.UpperCasePipe,
|
||||
lowercase_pipe_1.LowerCasePipe,
|
||||
json_pipe_1.JsonPipe,
|
||||
slice_pipe_1.SlicePipe,
|
||||
number_pipe_1.DecimalPipe,
|
||||
number_pipe_1.PercentPipe,
|
||||
number_pipe_1.CurrencyPipe,
|
||||
date_pipe_1.DatePipe
|
||||
]);
|
||||
//# sourceMappingURL=common_pipes.js.map
|
||||
@@ -0,0 +1,121 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var intl_1 = require('angular2/src/facade/intl');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var invalid_pipe_argument_exception_1 = require('./invalid_pipe_argument_exception');
|
||||
// TODO: move to a global configurable location along with other i18n components.
|
||||
var defaultLocale = 'en-US';
|
||||
/**
|
||||
* Formats a date value to a string based on the requested format.
|
||||
*
|
||||
* WARNINGS:
|
||||
* - this pipe is marked as pure hence it will not be re-evaluated when the input is mutated.
|
||||
* Instead users should treat the date as an immutable object and change the reference when the
|
||||
* pipe needs to re-run (this is to avoid reformatting the date on every change detection run
|
||||
* which would be an expensive operation).
|
||||
* - this pipe uses the Internationalization API. Therefore it is only reliable in Chrome and Opera
|
||||
* browsers.
|
||||
*
|
||||
* ## Usage
|
||||
*
|
||||
* expression | date[:format]
|
||||
*
|
||||
* where `expression` is a date object or a number (milliseconds since UTC epoch) and
|
||||
* `format` indicates which date/time components to include:
|
||||
*
|
||||
* | Component | Symbol | Short Form | Long Form | Numeric | 2-digit |
|
||||
* |-----------|:------:|--------------|-------------------|-----------|-----------|
|
||||
* | era | G | G (AD) | GGGG (Anno Domini)| - | - |
|
||||
* | year | y | - | - | y (2015) | yy (15) |
|
||||
* | month | M | MMM (Sep) | MMMM (September) | M (9) | MM (09) |
|
||||
* | day | d | - | - | d (3) | dd (03) |
|
||||
* | weekday | E | EEE (Sun) | EEEE (Sunday) | - | - |
|
||||
* | hour | j | - | - | j (13) | jj (13) |
|
||||
* | hour12 | h | - | - | h (1 PM) | hh (01 PM)|
|
||||
* | hour24 | H | - | - | H (13) | HH (13) |
|
||||
* | minute | m | - | - | m (5) | mm (05) |
|
||||
* | second | s | - | - | s (9) | ss (09) |
|
||||
* | timezone | z | - | z (Pacific Standard Time)| - | - |
|
||||
* | timezone | Z | Z (GMT-8:00) | - | - | - |
|
||||
*
|
||||
* In javascript, only the components specified will be respected (not the ordering,
|
||||
* punctuations, ...) and details of the formatting will be dependent on the locale.
|
||||
* On the other hand in Dart version, you can also include quoted text as well as some extra
|
||||
* date/time components such as quarter. For more information see:
|
||||
* https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.DateFormat.
|
||||
*
|
||||
* `format` can also be one of the following predefined formats:
|
||||
*
|
||||
* - `'medium'`: equivalent to `'yMMMdjms'` (e.g. Sep 3, 2010, 12:05:08 PM for en-US)
|
||||
* - `'short'`: equivalent to `'yMdjm'` (e.g. 9/3/2010, 12:05 PM for en-US)
|
||||
* - `'fullDate'`: equivalent to `'yMMMMEEEEd'` (e.g. Friday, September 3, 2010 for en-US)
|
||||
* - `'longDate'`: equivalent to `'yMMMMd'` (e.g. September 3, 2010)
|
||||
* - `'mediumDate'`: equivalent to `'yMMMd'` (e.g. Sep 3, 2010 for en-US)
|
||||
* - `'shortDate'`: equivalent to `'yMd'` (e.g. 9/3/2010 for en-US)
|
||||
* - `'mediumTime'`: equivalent to `'jms'` (e.g. 12:05:08 PM for en-US)
|
||||
* - `'shortTime'`: equivalent to `'jm'` (e.g. 12:05 PM for en-US)
|
||||
*
|
||||
* Timezone of the formatted text will be the local system timezone of the end-users machine.
|
||||
*
|
||||
* ### Examples
|
||||
*
|
||||
* Assuming `dateObj` is (year: 2015, month: 6, day: 15, hour: 21, minute: 43, second: 11)
|
||||
* in the _local_ time and locale is 'en-US':
|
||||
*
|
||||
* {{ dateObj | date }} // output is 'Jun 15, 2015'
|
||||
* {{ dateObj | date:'medium' }} // output is 'Jun 15, 2015, 9:43:11 PM'
|
||||
* {{ dateObj | date:'shortTime' }} // output is '9:43 PM'
|
||||
* {{ dateObj | date:'mmss' }} // output is '43:11'
|
||||
*/
|
||||
var DatePipe = (function () {
|
||||
function DatePipe() {
|
||||
}
|
||||
DatePipe.prototype.transform = function (value, args) {
|
||||
if (lang_1.isBlank(value))
|
||||
return null;
|
||||
if (!this.supports(value)) {
|
||||
throw new invalid_pipe_argument_exception_1.InvalidPipeArgumentException(DatePipe, value);
|
||||
}
|
||||
var pattern = lang_1.isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
|
||||
if (lang_1.isNumber(value)) {
|
||||
value = lang_1.DateWrapper.fromMillis(value);
|
||||
}
|
||||
if (collection_1.StringMapWrapper.contains(DatePipe._ALIASES, pattern)) {
|
||||
pattern = collection_1.StringMapWrapper.get(DatePipe._ALIASES, pattern);
|
||||
}
|
||||
return intl_1.DateFormatter.format(value, defaultLocale, pattern);
|
||||
};
|
||||
DatePipe.prototype.supports = function (obj) { return lang_1.isDate(obj) || lang_1.isNumber(obj); };
|
||||
/** @internal */
|
||||
DatePipe._ALIASES = {
|
||||
'medium': 'yMMMdjms',
|
||||
'short': 'yMdjm',
|
||||
'fullDate': 'yMMMMEEEEd',
|
||||
'longDate': 'yMMMMd',
|
||||
'mediumDate': 'yMMMd',
|
||||
'shortDate': 'yMd',
|
||||
'mediumTime': 'jms',
|
||||
'shortTime': 'jm'
|
||||
};
|
||||
DatePipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'date', pure: true }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], DatePipe);
|
||||
return DatePipe;
|
||||
})();
|
||||
exports.DatePipe = DatePipe;
|
||||
//# sourceMappingURL=date_pipe.js.map
|
||||
@@ -0,0 +1,15 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
var InvalidPipeArgumentException = (function (_super) {
|
||||
__extends(InvalidPipeArgumentException, _super);
|
||||
function InvalidPipeArgumentException(type, value) {
|
||||
_super.call(this, "Invalid argument '" + value + "' for pipe '" + type + "'");
|
||||
}
|
||||
return InvalidPipeArgumentException;
|
||||
})(exceptions_1.BaseException);
|
||||
exports.InvalidPipeArgumentException = InvalidPipeArgumentException;
|
||||
//# sourceMappingURL=invalid_pipe_argument_exception.js.map
|
||||
@@ -0,0 +1,52 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
/**
|
||||
* Implements json transforms to any object.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* In this example we transform the user object to json.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "user-cmp",
|
||||
* template: "User: {{ user | json }}"
|
||||
* })
|
||||
* class Username {
|
||||
* user:Object
|
||||
* constructor() {
|
||||
* this.user = { name: "PatrickJS" };
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
var JsonPipe = (function () {
|
||||
function JsonPipe() {
|
||||
}
|
||||
JsonPipe.prototype.transform = function (value, args) {
|
||||
if (args === void 0) { args = null; }
|
||||
return lang_1.Json.stringify(value);
|
||||
};
|
||||
JsonPipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'json', pure: false }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], JsonPipe);
|
||||
return JsonPipe;
|
||||
})();
|
||||
exports.JsonPipe = JsonPipe;
|
||||
//# sourceMappingURL=json_pipe.js.map
|
||||
@@ -0,0 +1,55 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var invalid_pipe_argument_exception_1 = require('./invalid_pipe_argument_exception');
|
||||
/**
|
||||
* Implements lowercase transforms to text.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* In this example we transform the user text lowercase.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "username-cmp",
|
||||
* template: "Username: {{ user | lowercase }}"
|
||||
* })
|
||||
* class Username {
|
||||
* user:string;
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
var LowerCasePipe = (function () {
|
||||
function LowerCasePipe() {
|
||||
}
|
||||
LowerCasePipe.prototype.transform = function (value, args) {
|
||||
if (args === void 0) { args = null; }
|
||||
if (lang_1.isBlank(value))
|
||||
return value;
|
||||
if (!lang_1.isString(value)) {
|
||||
throw new invalid_pipe_argument_exception_1.InvalidPipeArgumentException(LowerCasePipe, value);
|
||||
}
|
||||
return value.toLowerCase();
|
||||
};
|
||||
LowerCasePipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'lowercase' }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], LowerCasePipe);
|
||||
return LowerCasePipe;
|
||||
})();
|
||||
exports.LowerCasePipe = LowerCasePipe;
|
||||
//# sourceMappingURL=lowercase_pipe.js.map
|
||||
@@ -0,0 +1,182 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
var intl_1 = require('angular2/src/facade/intl');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var invalid_pipe_argument_exception_1 = require('./invalid_pipe_argument_exception');
|
||||
var defaultLocale = 'en-US';
|
||||
var _re = lang_1.RegExpWrapper.create('^(\\d+)?\\.((\\d+)(\\-(\\d+))?)?$');
|
||||
var NumberPipe = (function () {
|
||||
function NumberPipe() {
|
||||
}
|
||||
/** @internal */
|
||||
NumberPipe._format = function (value, style, digits, currency, currencyAsSymbol) {
|
||||
if (currency === void 0) { currency = null; }
|
||||
if (currencyAsSymbol === void 0) { currencyAsSymbol = false; }
|
||||
if (lang_1.isBlank(value))
|
||||
return null;
|
||||
if (!lang_1.isNumber(value)) {
|
||||
throw new invalid_pipe_argument_exception_1.InvalidPipeArgumentException(NumberPipe, value);
|
||||
}
|
||||
var minInt = 1, minFraction = 0, maxFraction = 3;
|
||||
if (lang_1.isPresent(digits)) {
|
||||
var parts = lang_1.RegExpWrapper.firstMatch(_re, digits);
|
||||
if (lang_1.isBlank(parts)) {
|
||||
throw new exceptions_1.BaseException(digits + " is not a valid digit info for number pipes");
|
||||
}
|
||||
if (lang_1.isPresent(parts[1])) {
|
||||
minInt = lang_1.NumberWrapper.parseIntAutoRadix(parts[1]);
|
||||
}
|
||||
if (lang_1.isPresent(parts[3])) {
|
||||
minFraction = lang_1.NumberWrapper.parseIntAutoRadix(parts[3]);
|
||||
}
|
||||
if (lang_1.isPresent(parts[5])) {
|
||||
maxFraction = lang_1.NumberWrapper.parseIntAutoRadix(parts[5]);
|
||||
}
|
||||
}
|
||||
return intl_1.NumberFormatter.format(value, defaultLocale, style, {
|
||||
minimumIntegerDigits: minInt,
|
||||
minimumFractionDigits: minFraction,
|
||||
maximumFractionDigits: maxFraction,
|
||||
currency: currency,
|
||||
currencyAsSymbol: currencyAsSymbol
|
||||
});
|
||||
};
|
||||
NumberPipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], NumberPipe);
|
||||
return NumberPipe;
|
||||
})();
|
||||
exports.NumberPipe = NumberPipe;
|
||||
/**
|
||||
* WARNING: this pipe uses the Internationalization API.
|
||||
* Therefore it is only reliable in Chrome and Opera browsers.
|
||||
*
|
||||
* Formats a number as local text. i.e. group sizing and separator and other locale-specific
|
||||
* configurations are based on the active locale.
|
||||
*
|
||||
*##Usage
|
||||
*
|
||||
* expression | number[:digitInfo]
|
||||
*
|
||||
* where `expression` is a number and `digitInfo` has the following format:
|
||||
*
|
||||
* {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}
|
||||
*
|
||||
* - minIntegerDigits is the minimum number of integer digits to use. Defaults to 1.
|
||||
* - minFractionDigits is the minimum number of digits after fraction. Defaults to 0.
|
||||
* - maxFractionDigits is the maximum number of digits after fraction. Defaults to 3.
|
||||
*
|
||||
* For more information on the acceptable range for each of these numbers and other
|
||||
* details see your native internationalization library.
|
||||
*
|
||||
* ### Examples
|
||||
*
|
||||
* {{ 123 | number }} // output is 123
|
||||
* {{ 123.1 | number: '.2-3' }} // output is 123.10
|
||||
* {{ 1 | number: '2.2' }} // output is 01.00
|
||||
*/
|
||||
var DecimalPipe = (function (_super) {
|
||||
__extends(DecimalPipe, _super);
|
||||
function DecimalPipe() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
DecimalPipe.prototype.transform = function (value, args) {
|
||||
var digits = collection_1.ListWrapper.first(args);
|
||||
return NumberPipe._format(value, intl_1.NumberFormatStyle.Decimal, digits);
|
||||
};
|
||||
DecimalPipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'number' }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], DecimalPipe);
|
||||
return DecimalPipe;
|
||||
})(NumberPipe);
|
||||
exports.DecimalPipe = DecimalPipe;
|
||||
/**
|
||||
* WARNING: this pipe uses the Internationalization API.
|
||||
* Therefore it is only reliable in Chrome and Opera browsers.
|
||||
*
|
||||
* Formats a number as local percent.
|
||||
*
|
||||
*##Usage
|
||||
*
|
||||
* expression | percent[:digitInfo]
|
||||
*
|
||||
* For more information about `digitInfo` see {@link DecimalPipe}
|
||||
*/
|
||||
var PercentPipe = (function (_super) {
|
||||
__extends(PercentPipe, _super);
|
||||
function PercentPipe() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
PercentPipe.prototype.transform = function (value, args) {
|
||||
var digits = collection_1.ListWrapper.first(args);
|
||||
return NumberPipe._format(value, intl_1.NumberFormatStyle.Percent, digits);
|
||||
};
|
||||
PercentPipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'percent' }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], PercentPipe);
|
||||
return PercentPipe;
|
||||
})(NumberPipe);
|
||||
exports.PercentPipe = PercentPipe;
|
||||
/**
|
||||
* WARNING: this pipe uses the Internationalization API.
|
||||
* Therefore it is only reliable in Chrome and Opera browsers.
|
||||
*
|
||||
* Formats a number as local currency.
|
||||
*
|
||||
*##Usage
|
||||
*
|
||||
* expression | currency[:currencyCode[:symbolDisplay[:digitInfo]]]
|
||||
*
|
||||
* where `currencyCode` is the ISO 4217 currency code, such as "USD" for the US dollar and
|
||||
* "EUR" for the euro. `symbolDisplay` is a boolean indicating whether to use the currency
|
||||
* symbol (e.g. $) or the currency code (e.g. USD) in the output. The default for this value
|
||||
* is `false`.
|
||||
* For more information about `digitInfo` see {@link DecimalPipe}
|
||||
*/
|
||||
var CurrencyPipe = (function (_super) {
|
||||
__extends(CurrencyPipe, _super);
|
||||
function CurrencyPipe() {
|
||||
_super.apply(this, arguments);
|
||||
}
|
||||
CurrencyPipe.prototype.transform = function (value, args) {
|
||||
var currencyCode = lang_1.isPresent(args) && args.length > 0 ? args[0] : 'USD';
|
||||
var symbolDisplay = lang_1.isPresent(args) && args.length > 1 ? args[1] : false;
|
||||
var digits = lang_1.isPresent(args) && args.length > 2 ? args[2] : null;
|
||||
return NumberPipe._format(value, intl_1.NumberFormatStyle.Currency, digits, currencyCode, symbolDisplay);
|
||||
};
|
||||
CurrencyPipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'currency' }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], CurrencyPipe);
|
||||
return CurrencyPipe;
|
||||
})(NumberPipe);
|
||||
exports.CurrencyPipe = CurrencyPipe;
|
||||
//# sourceMappingURL=number_pipe.js.map
|
||||
@@ -0,0 +1,105 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var exceptions_1 = require('angular2/src/facade/exceptions');
|
||||
var collection_1 = require('angular2/src/facade/collection');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var invalid_pipe_argument_exception_1 = require('./invalid_pipe_argument_exception');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
/**
|
||||
* Creates a new List or String containing only a subset (slice) of the
|
||||
* elements.
|
||||
*
|
||||
* The starting index of the subset to return is specified by the `start` parameter.
|
||||
*
|
||||
* The ending index of the subset to return is specified by the optional `end` parameter.
|
||||
*
|
||||
*##Usage
|
||||
*
|
||||
* expression | slice:start[:end]
|
||||
*
|
||||
* All behavior is based on the expected behavior of the JavaScript API
|
||||
* Array.prototype.slice() and String.prototype.slice()
|
||||
*
|
||||
* Where the input expression is a [List] or [String], and `start` is:
|
||||
*
|
||||
* - **a positive integer**: return the item at _start_ index and all items after
|
||||
* in the list or string expression.
|
||||
* - **a negative integer**: return the item at _start_ index from the end and all items after
|
||||
* in the list or string expression.
|
||||
* - **`|start|` greater than the size of the expression**: return an empty list or string.
|
||||
* - **`|start|` negative greater than the size of the expression**: return entire list or
|
||||
* string expression.
|
||||
*
|
||||
* and where `end` is:
|
||||
*
|
||||
* - **omitted**: return all items until the end of the input
|
||||
* - **a positive integer**: return all items before _end_ index of the list or string
|
||||
* expression.
|
||||
* - **a negative integer**: return all items before _end_ index from the end of the list
|
||||
* or string expression.
|
||||
*
|
||||
* When operating on a [List], the returned list is always a copy even when all
|
||||
* the elements are being returned.
|
||||
*
|
||||
* ### Examples
|
||||
*
|
||||
* ## List Example
|
||||
*
|
||||
* Assuming `var collection = ['a', 'b', 'c', 'd']`, this `ng-for` directive:
|
||||
*
|
||||
* <li *ng-for="var i of collection | slice:1:3">{{i}}</li>
|
||||
*
|
||||
* produces the following:
|
||||
*
|
||||
* <li>b</li>
|
||||
* <li>c</li>
|
||||
*
|
||||
* ## String Examples
|
||||
*
|
||||
* {{ 'abcdefghij' | slice:0:4 }} // output is 'abcd'
|
||||
* {{ 'abcdefghij' | slice:4:0 }} // output is ''
|
||||
* {{ 'abcdefghij' | slice:-4 }} // output is 'ghij'
|
||||
* {{ 'abcdefghij' | slice:-4,-2 }} // output is 'gh'
|
||||
* {{ 'abcdefghij' | slice: -100 }} // output is 'abcdefghij'
|
||||
* {{ 'abcdefghij' | slice: 100 }} // output is ''
|
||||
*/
|
||||
var SlicePipe = (function () {
|
||||
function SlicePipe() {
|
||||
}
|
||||
SlicePipe.prototype.transform = function (value, args) {
|
||||
if (args === void 0) { args = null; }
|
||||
if (lang_1.isBlank(args) || args.length == 0) {
|
||||
throw new exceptions_1.BaseException('Slice pipe requires one argument');
|
||||
}
|
||||
if (!this.supports(value)) {
|
||||
throw new invalid_pipe_argument_exception_1.InvalidPipeArgumentException(SlicePipe, value);
|
||||
}
|
||||
if (lang_1.isBlank(value))
|
||||
return value;
|
||||
var start = args[0];
|
||||
var end = args.length > 1 ? args[1] : null;
|
||||
if (lang_1.isString(value)) {
|
||||
return lang_1.StringWrapper.slice(value, start, end);
|
||||
}
|
||||
return collection_1.ListWrapper.slice(value, start, end);
|
||||
};
|
||||
SlicePipe.prototype.supports = function (obj) { return lang_1.isString(obj) || lang_1.isArray(obj); };
|
||||
SlicePipe = __decorate([
|
||||
metadata_1.Pipe({ name: 'slice', pure: false }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], SlicePipe);
|
||||
return SlicePipe;
|
||||
})();
|
||||
exports.SlicePipe = SlicePipe;
|
||||
//# sourceMappingURL=slice_pipe.js.map
|
||||
@@ -0,0 +1,55 @@
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var lang_1 = require('angular2/src/facade/lang');
|
||||
var metadata_1 = require('angular2/src/core/metadata');
|
||||
var di_1 = require('angular2/src/core/di');
|
||||
var invalid_pipe_argument_exception_1 = require('./invalid_pipe_argument_exception');
|
||||
/**
|
||||
* Implements uppercase transforms to text.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* In this example we transform the user text uppercase.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "username-cmp",
|
||||
* template: "Username: {{ user | uppercase }}"
|
||||
* })
|
||||
* class Username {
|
||||
* user:string;
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
var UpperCasePipe = (function () {
|
||||
function UpperCasePipe() {
|
||||
}
|
||||
UpperCasePipe.prototype.transform = function (value, args) {
|
||||
if (args === void 0) { args = null; }
|
||||
if (lang_1.isBlank(value))
|
||||
return value;
|
||||
if (!lang_1.isString(value)) {
|
||||
throw new invalid_pipe_argument_exception_1.InvalidPipeArgumentException(UpperCasePipe, value);
|
||||
}
|
||||
return value.toUpperCase();
|
||||
};
|
||||
UpperCasePipe = __decorate([
|
||||
lang_1.CONST(),
|
||||
metadata_1.Pipe({ name: 'uppercase' }),
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], UpperCasePipe);
|
||||
return UpperCasePipe;
|
||||
})();
|
||||
exports.UpperCasePipe = UpperCasePipe;
|
||||
//# sourceMappingURL=uppercase_pipe.js.map
|
||||
@@ -0,0 +1,40 @@
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
|
||||
switch (arguments.length) {
|
||||
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
|
||||
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
|
||||
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
|
||||
}
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
var app_root_url_1 = require("angular2/src/compiler/app_root_url");
|
||||
var dom_adapter_1 = require("angular2/src/core/dom/dom_adapter");
|
||||
var di_1 = require("angular2/src/core/di");
|
||||
/**
|
||||
* Extension of {@link AppRootUrl} that uses a DOM anchor tag to set the root url to
|
||||
* the current page's url.
|
||||
*/
|
||||
var AnchorBasedAppRootUrl = (function (_super) {
|
||||
__extends(AnchorBasedAppRootUrl, _super);
|
||||
function AnchorBasedAppRootUrl() {
|
||||
_super.call(this, "");
|
||||
// compute the root url to pass to AppRootUrl
|
||||
var a = dom_adapter_1.DOM.createElement('a');
|
||||
dom_adapter_1.DOM.resolveAndSetHref(a, './', null);
|
||||
this.value = dom_adapter_1.DOM.getHref(a);
|
||||
}
|
||||
AnchorBasedAppRootUrl = __decorate([
|
||||
di_1.Injectable(),
|
||||
__metadata('design:paramtypes', [])
|
||||
], AnchorBasedAppRootUrl);
|
||||
return AnchorBasedAppRootUrl;
|
||||
})(app_root_url_1.AppRootUrl);
|
||||
exports.AnchorBasedAppRootUrl = AnchorBasedAppRootUrl;
|
||||
//# sourceMappingURL=anchor_based_app_root_url.js.map
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user