2015-02-06 13:19:47 -08:00
|
|
|
import {ABSTRACT, CONST, normalizeBlank, isPresent} from 'angular2/src/facade/lang';
|
|
|
|
import {ListWrapper, List} from 'angular2/src/facade/collection';
|
2015-03-16 14:44:14 -07:00
|
|
|
import {Injectable} from 'angular2/di';
|
2014-11-21 21:19:23 -08:00
|
|
|
|
2015-03-14 00:00:42 +00:00
|
|
|
// type StringMap = {[idx: string]: string};
|
|
|
|
|
2015-03-13 21:54:19 +00:00
|
|
|
/**
|
2015-03-17 23:29:27 +00:00
|
|
|
* Directives allow you to attach behavior to elements in the DOM.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Directive is an abstract concept, instead use concrete directives: [Component], [DynamicComponent], [Decorator]
|
2015-03-19 16:56:45 +00:00
|
|
|
* or [Viewport].
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* A directive consists of a single directive annotation and a controller class. When the directive's [selector] matches
|
|
|
|
* elements in the DOM, the following steps occur:
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* 1. For each directive, the [ElementInjector] attempts to resolve the directive's constructor arguments.
|
2015-03-20 21:11:58 +00:00
|
|
|
* 2. Angular instantiates directives for each matched element using [ElementInjector] in a depth-first order,
|
|
|
|
* as declared in the HTML.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ## Understanding How Injection Works
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* There are three stages of injection resolution.
|
2015-03-20 21:11:58 +00:00
|
|
|
* - *Pre-existing Injectors*:
|
|
|
|
* - The terminal [Injector] cannot resolve dependencies. It either throws an error or, if the dependency was
|
2015-03-19 16:56:45 +00:00
|
|
|
* specified as `@Optional`, returns `null`.
|
|
|
|
* - The primordial injector resolves browser singleton resources, such as: cookies, title, location, and others.
|
2015-03-20 21:11:58 +00:00
|
|
|
* - *Component Injectors*: Each `@Component` has its own [Injector], and they follow the same parent-child hierachy
|
2015-03-19 16:56:45 +00:00
|
|
|
* as the components in the DOM.
|
2015-03-20 21:11:58 +00:00
|
|
|
* - *Element Injectors*: Each component has a Shadow DOM. Within the Shadow DOM each element has an [ElementInjector]
|
2015-03-19 16:56:45 +00:00
|
|
|
* which follow the same parent-child hiercachy as the DOM elements themselves.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* When a template is instantiated, it also must instantiate the corresponding directives in a depth-first order. The
|
|
|
|
* current [ElementInjector] resolves the constructor dependencies for each directive.
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* Angular then resolves dependencies as follows, according to the order in which they appear in the [View]:
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* 1. Dependencies on the current element
|
|
|
|
* 2. Dependencies on element injectors and their parents until it encounters a Shadow DOM boundary
|
|
|
|
* 3. Dependencies on component injectors and their parents until it encounters the root component
|
|
|
|
* 4. Dependencies on pre-existing injectors
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The [ElementInjector] can inject other directives, element-specific special objects, or it can delegate to the parent
|
2015-03-19 16:56:45 +00:00
|
|
|
* injector.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* To inject other directives, declare the constructor parameter as:
|
2015-03-20 21:11:58 +00:00
|
|
|
* - `directive:DirectiveType`: a directive on the current element only
|
|
|
|
* - `@Ancestor() directive:DirectiveType`: any directive that matches the type between the current element and the
|
|
|
|
* Shadow DOM root. Current Element is not included in the resolution, therefor even if it could resolve it, it will
|
|
|
|
* be ignored.
|
|
|
|
* - `@Parent() directive:DirectiveType`: any directive that matches the type on a direct parent element only.
|
|
|
|
* - `@Children query:Query<DirectiveType>`: A live collection of direct child directives [TO BE IMPLEMENTED].
|
|
|
|
* - `@Descendants query:Query<DirectiveType>`: A live collection of any child directives [TO BE IMPLEMENTED].
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* To inject element-specific special objects, declare the constructor parameter as:
|
2015-03-20 21:11:58 +00:00
|
|
|
* - `element: NgElement` to obtain a DOM element (DEPRECATED: replacment coming)
|
|
|
|
* - `viewContainer: ViewContainer` to control child template instantiation, for [Viewport] directives only
|
|
|
|
* - `bindingPropagation: BindingPropagation` to control change detection in a more granular way.
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ## Example
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* The following example demonstrates how dependency injection resolves constructor arguments in practice.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Assume this HTML template:
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* <div dependency="1">
|
|
|
|
* <div dependency="2">
|
|
|
|
* <div dependency="3" my-directive>
|
|
|
|
* <div dependency="4">
|
|
|
|
* <div dependency="5"></div>
|
2015-03-17 23:29:27 +00:00
|
|
|
* </div>
|
2015-03-19 16:56:45 +00:00
|
|
|
* <div dependency="6"></div>
|
2015-03-17 23:29:27 +00:00
|
|
|
* </div>
|
|
|
|
* </div>
|
|
|
|
* </div>
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* With the following `dependency` decorator and `SomeService` injectable class.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Injectable()
|
|
|
|
* class SomeService {
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* @Decorator({
|
2015-03-19 16:56:45 +00:00
|
|
|
* selector: '[dependency]',
|
2015-03-17 23:29:27 +00:00
|
|
|
* bind: {
|
2015-03-19 16:56:45 +00:00
|
|
|
* 'id':'dependency'
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* })
|
2015-03-19 16:56:45 +00:00
|
|
|
* class Dependency {
|
2015-03-17 23:29:27 +00:00
|
|
|
* id:string;
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* Let's step through the different ways in which `MyDirective` could be declared...
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
* ### No injection
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Here the constructor is declared with no arguments, therefore nothing is injected into `MyDirective`.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
2015-03-17 23:29:27 +00:00
|
|
|
* constructor() {
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with no dependencies.
|
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ### Component-level injection
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* Directives can inject any injectable instance from the closest component injector or any of its parents.
|
2015-03-19 16:56:45 +00:00
|
|
|
*
|
|
|
|
* Here, the constructor declares a parameter, `someService`, and injects the `SomeService` type from the parent
|
|
|
|
* component's injector.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
|
|
|
* constructor(someService: SomeService) {
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with a dependency on `SomeService`.
|
|
|
|
*
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ### Injecting a directive from the current element
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* Directives can inject other directives declared on the current element.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
|
|
|
* constructor(dependency: Dependency) {
|
2015-03-20 13:05:18 -05:00
|
|
|
* expect(dependency.id).toEqual(3);
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with `Dependency` declared at the same element, in this case `dependency="3"`.
|
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ### Injecting a directive from a direct parent element
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Directives can inject other directives declared on a direct parent element. By definition, a directive with a
|
2015-03-19 16:56:45 +00:00
|
|
|
* `@Parent` annotation does not attempt to resolve dependencies for the current element, even if this would satisfy
|
2015-03-20 21:11:58 +00:00
|
|
|
* the dependency.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
|
|
|
* constructor(@Parent() dependency: Dependency) {
|
|
|
|
* expect(dependency.id).toEqual(2);
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with `Dependency` declared at the parent element, in this case `dependency="2"`.
|
|
|
|
*
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ### Injecting a directive from any ancestor elements
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Directives can inject other directives declared on any ancestor element (in the current Shadow DOM), i.e. on the
|
|
|
|
* parent element and its parents. By definition, a directive with an `@Ancestor` annotation does not attempt to
|
|
|
|
* resolve dependencies for the current element, even if this would satisfy the dependency.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
|
|
|
* constructor(@Ancestor() dependency: Dependency) {
|
|
|
|
* expect(dependency.id).toEqual(2);
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Unlike the `@Parent` which only checks the parent, `@Ancestor` checks the parent, as well as its
|
|
|
|
* parents recursively. If `dependency="2"` didn't exist on the direct parent, this injection would have returned
|
|
|
|
* `dependency="1"`.
|
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* ### Injecting a live collection of direct child directives [PENDING IMPLEMENTATION]
|
|
|
|
*
|
|
|
|
* A directive can also query for other child directives. Since parent directives are instantiated before child
|
|
|
|
* directives, a directive can't simply inject the list of child directives. Instead, the directive asynchronously
|
|
|
|
* injects a [Query], which updates as children are added, removed, or moved by any [ViewPort] directive such as a
|
|
|
|
* `for`, an `if`, or a `switch`.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
2015-03-20 21:11:58 +00:00
|
|
|
* constructor(@Children() dependencies:Query<Maker>) {
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with a [Query] which contains `Dependency` 4 and 6. Here, `Dependency` 5 would
|
|
|
|
* not be included, because it is not a direct child.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* ### Injecting a live collection of direct descendant directives [PENDING IMPLEMENTATION]
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Similar to `@Children` above, but also includes the children of the child elements.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
2015-03-20 21:11:58 +00:00
|
|
|
* constructor(@Children() dependencies:Query<Maker>) {
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with a Query which would contain `Dependency` 4, 5 and 6.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ### Optional injection
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* The normal behavior of directives is to return an error when a specified dependency cannot be resolved. If you
|
|
|
|
* would like to inject `null` on unresolved dependency instead, you can annotate that dependency with `@Optional()`.
|
|
|
|
* This explicitly permits the author of a template to treat some of the surrounding directives as optional.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Decorator({ selector: '[my-directive]' })
|
|
|
|
* class MyDirective {
|
2015-03-20 21:11:58 +00:00
|
|
|
* constructor(@Optional() dependency:Dependency) {
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* This directive would be instantiated with a `Dependency` directive found on the current element. If none can be
|
|
|
|
* found, the injector supplies `null` instead of throwing an error.
|
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
* @publicModule angular2/annotations
|
2015-03-13 21:54:19 +00:00
|
|
|
*/
|
2014-11-21 21:19:23 -08:00
|
|
|
@ABSTRACT()
|
2015-03-16 14:44:14 -07:00
|
|
|
export class Directive extends Injectable {
|
2015-03-14 00:00:42 +00:00
|
|
|
/**
|
2015-03-17 19:22:13 +00:00
|
|
|
* The CSS selector that triggers the instantiation of a directive.
|
|
|
|
*
|
|
|
|
* Angular only allows directives to trigger on CSS selectors that do not cross element boundaries.
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* `selector` may be declared as one of the following:
|
|
|
|
*
|
|
|
|
* - `element-name`: select by element name.
|
|
|
|
* - `.class`: select by class name.
|
|
|
|
* - `[attribute]`: select by attribute name.
|
|
|
|
* - `[attribute=value]`: select by attribute name and value.
|
|
|
|
* - `:not(sub_selector)`: select only if the element does not match the `sub_selector`.
|
2015-03-19 17:01:42 +01:00
|
|
|
* - `selector1, selector2`: select if either `selector1` or `selector2` matches.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* ## Example
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* Suppose we have a directive with an `input[type=text]` selector.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* And the following HTML:
|
|
|
|
*
|
2015-03-17 19:22:13 +00:00
|
|
|
* ```html
|
|
|
|
* <form>
|
|
|
|
* <input type="text">
|
|
|
|
* <input type="radio">
|
|
|
|
* <form>
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* The directive would only be instantiated on the `<input type="text">` element.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
*/
|
|
|
|
selector:string;
|
2015-03-17 19:22:13 +00:00
|
|
|
|
2015-03-14 00:00:42 +00:00
|
|
|
/**
|
|
|
|
* Enumerates the set of properties that accept data binding for a directive.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* The `bind` property defines a set of `directiveProperty` to `bindingProperty` key-value pairs:
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* - `directiveProperty` specifies the component property where the value is written.
|
2015-03-17 19:22:13 +00:00
|
|
|
* - `bindingProperty` specifies the DOM property where the value is read from.
|
|
|
|
*
|
|
|
|
* You can include [Pipes] when specifying a `bindingProperty` to allow for data transformation and structural
|
2015-03-20 21:11:58 +00:00
|
|
|
* change detection of the value. These pipes will be evaluated in the context of this component.
|
|
|
|
*
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* ## Syntax
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Directive({
|
|
|
|
* bind: {
|
|
|
|
* 'directiveProperty1': 'bindingProperty1',
|
|
|
|
* 'directiveProperty2': 'bindingProperty2 | pipe1 | ...',
|
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* ## Basic Property Binding
|
|
|
|
*
|
|
|
|
* We can easily build a simple `Tooltip` directive that exposes a `tooltip` property, which can be used in templates
|
|
|
|
* with standard Angular syntax. For example:
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* selector: '[tooltip]',
|
|
|
|
* bind: {
|
2015-03-20 21:11:58 +00:00
|
|
|
* 'text': 'tooltip'
|
2015-03-17 19:22:13 +00:00
|
|
|
* }
|
|
|
|
* })
|
|
|
|
* class Tooltip {
|
2015-03-20 21:11:58 +00:00
|
|
|
* set text(text) {
|
2015-03-17 19:22:13 +00:00
|
|
|
* // This will get called every time the 'tooltip' binding changes with the new value.
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* We can then bind to the `tooltip' property as either an expression (`someExpression`) or as a string literal, as
|
|
|
|
* shown in the HTML template below:
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```html
|
2015-03-20 21:11:58 +00:00
|
|
|
* <div [tooltip]="someExpression">...</div>
|
|
|
|
* <div tooltip="Some Text">...</div>
|
2015-03-17 19:22:13 +00:00
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Whenever the `someExpression` expression changes, the `bind` declaration instructs Angular to update the
|
2015-03-14 00:00:42 +00:00
|
|
|
* `Tooltip`'s `tooltipText` property.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
2015-03-24 23:27:07 +00:00
|
|
|
* ## Bindings With Pipes
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* You can also use pipes when writing binding definitions for a directive.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* For example, we could write a binding that updates the directive on structural changes, rather than on reference
|
|
|
|
* changes, as normally occurs in change detection. (See: [Pipe] and [keyValueDiff] documentaition for more details.)
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* selector: '[class-set]',
|
|
|
|
* bind: {
|
|
|
|
* 'classChanges': 'classSet | keyValDiff'
|
|
|
|
* }
|
|
|
|
* })
|
|
|
|
* class ClassSet {
|
|
|
|
* set classChanges(changes:KeyValueChanges) {
|
|
|
|
* // This will get called every time the `class-set` expressions changes its structure.
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* The template that this directive is used in may also contain its own pipes. For example:
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```html
|
2015-03-20 21:11:58 +00:00
|
|
|
* <div [class-set]="someExpression | somePipe">
|
2015-03-17 19:22:13 +00:00
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* In this case, the two pipes compose as if they were inlined: `someExpression | somePipe | keyValDiff`.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
*/
|
|
|
|
bind:any; // StringMap
|
2015-03-17 19:22:13 +00:00
|
|
|
|
2015-03-14 00:00:42 +00:00
|
|
|
/**
|
2015-03-20 21:11:58 +00:00
|
|
|
* Specifies which DOM events a directive listens to.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-16 22:46:05 +01:00
|
|
|
* The `events` property defines a set of `event` to `method` key-value pairs:
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* - `event1`: the DOM event that the directive listens to.
|
|
|
|
* - `statement`: the statment to execute when the event occurs.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* When writing a directive event binding, you can also refer to the following local variables:
|
|
|
|
* - `$event`: Current event object which triggerd the event.
|
|
|
|
* - `$target`: The source of the event. This will be either a DOM element or an Angular directive.
|
|
|
|
* [TO BE IMPLEMENTED]
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* ## Syntax
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Directive({
|
|
|
|
* events: {
|
2015-03-20 21:11:58 +00:00
|
|
|
* 'event1': 'onMethod1(arguments)',
|
2015-03-17 19:22:13 +00:00
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* ## Basic Event Binding:
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Suppose you want to write a directive that triggers on `change` events in the DOM. You would define the event
|
|
|
|
* binding as follows:
|
|
|
|
*
|
2015-03-17 19:22:13 +00:00
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* selector: 'input',
|
2015-03-16 22:46:05 +01:00
|
|
|
* events: {
|
2015-03-20 21:11:58 +00:00
|
|
|
* 'change': 'onChange($event)'
|
2015-03-17 19:22:13 +00:00
|
|
|
* }
|
|
|
|
* })
|
|
|
|
* class InputDecorator {
|
|
|
|
* onChange(event:Event) {
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Here `InputDecorator` is invoked whenever the DOM element fires the 'change' event.
|
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
*/
|
|
|
|
events:any; // StringMap
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Specifies a set of lifecycle events in which the directive participates.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-30 10:03:51 +02:00
|
|
|
* See: [onChange], [onDestroy], [onAllChangesDone] for details.
|
2015-03-14 00:00:42 +00:00
|
|
|
*/
|
2015-03-17 23:29:27 +00:00
|
|
|
lifecycle:List; //List<LifecycleEvent>
|
2015-03-17 19:22:13 +00:00
|
|
|
|
2014-11-21 21:19:23 -08:00
|
|
|
@CONST()
|
|
|
|
constructor({
|
|
|
|
selector,
|
|
|
|
bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle
|
2014-11-21 21:19:23 -08:00
|
|
|
}:{
|
|
|
|
selector:string,
|
|
|
|
bind:any,
|
2015-03-06 15:44:59 +01:00
|
|
|
events: any,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle:List
|
2014-11-21 21:19:23 -08:00
|
|
|
}={})
|
|
|
|
{
|
2015-03-16 14:44:14 -07:00
|
|
|
super();
|
2014-11-21 21:19:23 -08:00
|
|
|
this.selector = selector;
|
|
|
|
this.bind = bind;
|
2015-03-06 15:44:59 +01:00
|
|
|
this.events = events;
|
2015-01-13 16:17:43 -08:00
|
|
|
this.lifecycle = lifecycle;
|
2014-11-21 21:19:23 -08:00
|
|
|
}
|
2015-02-06 13:19:47 -08:00
|
|
|
|
2015-03-17 23:29:27 +00:00
|
|
|
/**
|
|
|
|
* Returns true if a directive participates in a given [LifecycleEvent].
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-30 10:03:51 +02:00
|
|
|
* See: [onChange], [onDestroy], [onAllChangesDone] for details.
|
2015-03-17 23:29:27 +00:00
|
|
|
*/
|
2015-02-06 13:19:47 -08:00
|
|
|
hasLifecycleHook(hook:string):boolean {
|
|
|
|
return isPresent(this.lifecycle) ? ListWrapper.contains(this.lifecycle, hook) : false;
|
|
|
|
}
|
2014-11-21 21:19:23 -08:00
|
|
|
}
|
|
|
|
|
2015-03-17 19:22:13 +00:00
|
|
|
/**
|
2015-03-30 17:19:27 -07:00
|
|
|
* Declare reusable UI building blocks for an application.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-30 17:19:27 -07:00
|
|
|
* Each angular component requires a single `@Component` and at least one `@Template` annotation. The @Component
|
|
|
|
* annotation specifies when a component is instantiated, and which properties and events it binds to.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* When a component is instantiated, Angular
|
|
|
|
* - creates a shadow DOM for the component.
|
|
|
|
* - loads the selected template into the shadow DOM.
|
|
|
|
* - creates a child [Injector] which is configured with the [Component.services].
|
|
|
|
*
|
2015-03-30 17:19:27 -07:00
|
|
|
* All template expressions and statements are then evaluated against the component instance.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* For details on the `@Template` annotation, see [Template].
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ## Example
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Component({
|
|
|
|
* selector: 'greet'
|
|
|
|
* })
|
|
|
|
* @Template({
|
|
|
|
* inline: 'Hello {{name}}!'
|
|
|
|
* })
|
|
|
|
* class Greet {
|
|
|
|
* name: string;
|
|
|
|
*
|
|
|
|
* constructor() {
|
|
|
|
* this.name = 'World';
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* @publicModule angular2/annotations
|
2015-03-17 19:22:13 +00:00
|
|
|
*/
|
2014-11-21 21:19:23 -08:00
|
|
|
export class Component extends Directive {
|
2015-03-17 23:29:27 +00:00
|
|
|
/**
|
2015-03-20 21:11:58 +00:00
|
|
|
* Defines the set of injectable objects that are visible to a Component and its children.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* The [services] defined in the Component annotation allow you to configure a set of bindings for the component's
|
|
|
|
* injector.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* When a component is instantiated, Angular creates a new child Injector, which is configured with the bindings in
|
|
|
|
* the Component [services] annotation. The injectable objects then become available for injection to the component
|
|
|
|
* itself and any of the directives in the component's template, i.e. they are not available to the directives which
|
|
|
|
* are children in the component's light DOM.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The syntax for configuring the [services] injectable is identical to [Injector] injectable configuration. See
|
|
|
|
* [Injector] for additional detail.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* ## Simple Example
|
|
|
|
*
|
|
|
|
* Here is an example of a class that can be injected:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* class Greeter {
|
|
|
|
* greet(name:string) {
|
|
|
|
* return 'Hello ' + name + '!';
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* @Component({
|
|
|
|
* selector: 'greet',
|
|
|
|
* services: [
|
|
|
|
* Greeter
|
|
|
|
* ]
|
|
|
|
* })
|
|
|
|
* @Template({
|
|
|
|
* inline: `{{greeter.greet('world')}}!`,
|
|
|
|
* directives: Child
|
|
|
|
* })
|
|
|
|
* class HelloWorld {
|
|
|
|
* greeter:Greeter;
|
|
|
|
*
|
|
|
|
* constructor(greeter:Greeter) {
|
|
|
|
* this.greeter = greeter;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-17 23:29:27 +00:00
|
|
|
*/
|
|
|
|
services:List;
|
2014-11-21 21:19:23 -08:00
|
|
|
|
2015-01-13 16:17:43 -08:00
|
|
|
@CONST()
|
2014-11-21 21:19:23 -08:00
|
|
|
constructor({
|
|
|
|
selector,
|
|
|
|
bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events,
|
2015-03-11 16:48:57 -07:00
|
|
|
services,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle
|
2014-11-21 21:19:23 -08:00
|
|
|
}:{
|
2015-01-13 16:17:43 -08:00
|
|
|
selector:String,
|
2014-11-21 21:19:23 -08:00
|
|
|
bind:Object,
|
2015-03-06 15:44:59 +01:00
|
|
|
events:Object,
|
2015-03-11 16:48:57 -07:00
|
|
|
services:List,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle:List
|
|
|
|
}={})
|
2014-11-21 21:19:23 -08:00
|
|
|
{
|
|
|
|
super({
|
|
|
|
selector: selector,
|
|
|
|
bind: bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events: events,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle: lifecycle
|
|
|
|
});
|
2014-11-21 21:19:23 -08:00
|
|
|
|
2015-03-11 16:48:57 -07:00
|
|
|
this.services = services;
|
2014-11-21 21:19:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-19 16:56:45 +00:00
|
|
|
/**
|
2015-03-19 14:31:41 +01:00
|
|
|
* Directive used for dynamically loading components.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* Regular angular components are statically resolved. DynamicComponent allows to you resolve a component at runtime
|
|
|
|
* instead by providing a placeholder into which a regular angular component can be dynamically loaded. Once loaded,
|
|
|
|
* the dynamically-loaded component becomes permanent and cannot be changed.
|
|
|
|
*
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* ## Example
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* Here we have `DynamicComp` which acts as the placeholder for `HelloCmp`. At runtime, the dynamic component
|
|
|
|
* `DynamicComp` requests loading of the `HelloCmp` component.
|
|
|
|
*
|
|
|
|
* There is nothing special about `HelloCmp`, which is a regular angular component. It can also be used in other static
|
|
|
|
* locations.
|
|
|
|
*
|
|
|
|
* ```
|
2015-03-19 16:56:45 +00:00
|
|
|
* @DynamicComponent({
|
|
|
|
* selector: 'dynamic-comp'
|
|
|
|
* })
|
|
|
|
* class DynamicComp {
|
2015-03-20 21:11:58 +00:00
|
|
|
* helloCmp:HelloCmp;
|
2015-03-19 16:56:45 +00:00
|
|
|
* constructor(loader:PrivateComponentLoader, location:PrivateComponentLocation) {
|
2015-03-20 21:11:58 +00:00
|
|
|
* loader.load(HelloCmp, location).then((helloCmp) => {
|
|
|
|
* this.helloCmp = helloCmp;
|
|
|
|
* });
|
2015-03-19 16:56:45 +00:00
|
|
|
* }
|
|
|
|
* }
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* @Component({
|
|
|
|
* selector: 'hello-cmp'
|
|
|
|
* })
|
|
|
|
* @Template({
|
|
|
|
* inline: "{{greeting}}"
|
|
|
|
* })
|
|
|
|
* class HelloCmp {
|
|
|
|
* greeting:string;
|
|
|
|
* constructor() {
|
|
|
|
* this.greeting = "hello";
|
|
|
|
* }
|
|
|
|
* }
|
2015-03-20 21:11:58 +00:00
|
|
|
* ```
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
2015-03-19 16:56:45 +00:00
|
|
|
* @publicModule angular2/annotations
|
|
|
|
*/
|
|
|
|
export class DynamicComponent extends Directive {
|
2015-03-20 21:11:58 +00:00
|
|
|
/**
|
|
|
|
* Same as [Component.services].
|
|
|
|
*/
|
|
|
|
// TODO(vsankin): Please extract into AbstractComponent
|
2015-03-19 16:56:45 +00:00
|
|
|
services:any; //List;
|
|
|
|
|
|
|
|
@CONST()
|
|
|
|
constructor({
|
|
|
|
selector,
|
|
|
|
bind,
|
|
|
|
events,
|
|
|
|
services,
|
|
|
|
lifecycle
|
|
|
|
}:{
|
|
|
|
selector:string,
|
|
|
|
bind:Object,
|
|
|
|
events:Object,
|
|
|
|
services:List,
|
|
|
|
lifecycle:List
|
|
|
|
}={}) {
|
|
|
|
super({
|
|
|
|
selector: selector,
|
|
|
|
bind: bind,
|
|
|
|
events: events,
|
|
|
|
lifecycle: lifecycle
|
|
|
|
});
|
|
|
|
|
|
|
|
this.services = services;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-13 11:33:57 -07:00
|
|
|
/**
|
2015-03-20 21:11:58 +00:00
|
|
|
* Directive that attaches behavior to DOM elements.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* A decorator directive attaches behavior to a DOM element in a composable manner.
|
2015-03-20 21:11:58 +00:00
|
|
|
* (see: http://en.wikipedia.org/wiki/Composition_over_inheritance)
|
2015-03-19 14:31:41 +01:00
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
* Decorators:
|
|
|
|
* - are simplest form of [Directive]s.
|
2015-03-20 21:11:58 +00:00
|
|
|
* - are best used as a composition pattern ()
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* Decorators differ from [Component]s in that they:
|
|
|
|
* - can have multiple decorators per element
|
2015-03-17 23:29:27 +00:00
|
|
|
* - do not create their own evaluation context
|
|
|
|
* - do not have template (and therefor do not create Shadow DOM)
|
|
|
|
*
|
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* ## Example
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Here we use a decorator directive to simply define basic tool-tip behavior.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* selector: '[tooltip]',
|
|
|
|
* bind: {
|
|
|
|
* 'text': 'tooltip'
|
|
|
|
* },
|
2015-03-22 15:38:41 +01:00
|
|
|
* events: {
|
2015-03-20 21:11:58 +00:00
|
|
|
* 'onmouseenter': 'onMouseEnter()',
|
|
|
|
* 'onmouseleave': 'onMouseLeave()'
|
2015-03-17 23:29:27 +00:00
|
|
|
* }
|
|
|
|
* })
|
|
|
|
* class Tooltip{
|
|
|
|
* text:string;
|
|
|
|
* overlay:Overlay; // NOT YET IMPLEMENTED
|
|
|
|
* overlayManager:OverlayManager; // NOT YET IMPLEMENTED
|
|
|
|
*
|
|
|
|
* constructor(overlayManager:OverlayManager) {
|
|
|
|
* this.overlay = overlay;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* onMouseEnter() {
|
|
|
|
* // exact signature to be determined
|
|
|
|
* this.overlay = this.overlayManager.open(text, ...);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* onMouseLeave() {
|
|
|
|
* this.overlay.close();
|
|
|
|
* this.overlay = null;
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-19 14:31:41 +01:00
|
|
|
* In our HTML template, we can then add this behavior to a `<div>` or any other element with the `tooltip` selector,
|
2015-03-20 21:11:58 +00:00
|
|
|
* like so:
|
2015-03-19 14:31:41 +01:00
|
|
|
*
|
2015-03-20 21:11:58 +00:00
|
|
|
* ```
|
|
|
|
* <div tooltip="some text here"></div>
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
* @publicModule angular2/annotations
|
2015-03-13 11:33:57 -07:00
|
|
|
*/
|
2014-11-21 21:19:23 -08:00
|
|
|
export class Decorator extends Directive {
|
2015-03-20 21:11:58 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* If set to true the compiler does not compile the children of this directive.
|
|
|
|
*/
|
|
|
|
//TODO(vsavkin): This would better fall under the Macro directive concept.
|
2015-01-07 17:32:46 +01:00
|
|
|
compileChildren: boolean;
|
2015-03-20 21:11:58 +00:00
|
|
|
|
2014-11-21 21:19:23 -08:00
|
|
|
@CONST()
|
|
|
|
constructor({
|
|
|
|
selector,
|
|
|
|
bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle,
|
|
|
|
compileChildren = true,
|
2014-11-21 21:19:23 -08:00
|
|
|
}:{
|
|
|
|
selector:string,
|
|
|
|
bind:any,
|
2015-03-06 15:44:59 +01:00
|
|
|
events:any,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle:List,
|
2015-01-07 18:20:29 +01:00
|
|
|
compileChildren:boolean
|
2014-11-21 21:19:23 -08:00
|
|
|
}={})
|
|
|
|
{
|
|
|
|
super({
|
|
|
|
selector: selector,
|
|
|
|
bind: bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events: events,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle: lifecycle
|
2014-11-21 21:19:23 -08:00
|
|
|
});
|
2015-03-24 11:01:26 -04:00
|
|
|
this.compileChildren = compileChildren;
|
2014-11-21 21:19:23 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-17 19:22:13 +00:00
|
|
|
/**
|
2015-03-19 14:31:41 +01:00
|
|
|
* Directive that controls the instantiation, destruction, and positioning of inline template elements.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* A viewport directive uses a [ViewContainer] to instantiate, insert, move, and destroy views at runtime.
|
|
|
|
* The [ViewContainer] is created as a result of `<template>` element, and represents a location in the current view
|
|
|
|
* where these actions are performed.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Views are always created as children of the current [View], and as siblings of the `<template>` element. Thus a
|
|
|
|
* directive in a child view cannot inject the viewport directive that created it.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Since viewport directives are common in Angular, and using the full `<template>` element syntax is wordy, Angular
|
|
|
|
* also supports a shorthand notation: `<li *foo="bar">` and `<li template="foo: bar">` are equivalent.
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Thus,
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <ul>
|
2015-03-19 14:31:41 +01:00
|
|
|
* <li *foo="bar" title="text"></li>
|
|
|
|
* </ul>
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* Expands in use to:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <ul>
|
|
|
|
* <template [foo]="bar">
|
|
|
|
* <li title="text"></li>
|
|
|
|
* </template>
|
2015-03-17 23:29:27 +00:00
|
|
|
* </ul>
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Notice that although the shorthand places `*foo="bar"` within the `<li>` element, the binding for the `Viewport`
|
|
|
|
* controller is correctly instantiated on the `<template>` element rather than the `<li>` element.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* ## Example
|
|
|
|
*
|
|
|
|
* Let's suppose we want to implement the `unless` behavior, to conditionally include a template.
|
|
|
|
*
|
|
|
|
* Here is a simple viewport directive that triggers on an `unless` selector:
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Viewport({
|
|
|
|
* selector: '[unless]',
|
|
|
|
* bind: {
|
|
|
|
* 'condition': 'unless'
|
|
|
|
* }
|
|
|
|
* })
|
2015-03-19 14:31:41 +01:00
|
|
|
* export class Unless {
|
2015-03-17 23:29:27 +00:00
|
|
|
* viewContainer: ViewContainer;
|
|
|
|
* prevCondition: boolean;
|
|
|
|
*
|
|
|
|
* constructor(viewContainer: ViewContainer) {
|
|
|
|
* this.viewContainer = viewContainer;
|
|
|
|
* this.prevCondition = null;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* set condition(newCondition) {
|
|
|
|
* if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) {
|
|
|
|
* this.prevCondition = true;
|
|
|
|
* this.viewContainer.clear();
|
|
|
|
* } else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) {
|
|
|
|
* this.prevCondition = false;
|
|
|
|
* this.viewContainer.create();
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* We can then use this `unless` selector in a template:
|
2015-03-20 21:11:58 +00:00
|
|
|
* ```
|
|
|
|
* <ul>
|
2015-03-19 14:31:41 +01:00
|
|
|
* <li *unless="expr"></li>
|
2015-03-20 21:11:58 +00:00
|
|
|
* </ul>
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Once the viewport instantiates the child view, the shorthand notation for the template expands and the result is:
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* <ul>
|
|
|
|
* <template [unless]="exp">
|
|
|
|
* <li></li>
|
|
|
|
* </template>
|
|
|
|
* <li></li>
|
|
|
|
* </ul>
|
|
|
|
* ```
|
|
|
|
*
|
2015-03-19 14:31:41 +01:00
|
|
|
* Note also that although the `<li></li>` template still exists inside the `<template></template>`, the instantiated
|
|
|
|
* view occurs on the second `<li></li>` which is a sibling to the `<template>` element.
|
2015-03-20 21:11:58 +00:00
|
|
|
*
|
2015-03-17 23:29:27 +00:00
|
|
|
*
|
|
|
|
* @publicModule angular2/annotations
|
2015-03-17 19:22:13 +00:00
|
|
|
*/
|
2015-02-12 11:54:22 +01:00
|
|
|
export class Viewport extends Directive {
|
2014-11-21 21:19:23 -08:00
|
|
|
@CONST()
|
|
|
|
constructor({
|
|
|
|
selector,
|
|
|
|
bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle
|
2014-11-21 21:19:23 -08:00
|
|
|
}:{
|
|
|
|
selector:string,
|
|
|
|
bind:any,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle:List
|
2014-11-21 21:19:23 -08:00
|
|
|
}={})
|
|
|
|
{
|
|
|
|
super({
|
|
|
|
selector: selector,
|
|
|
|
bind: bind,
|
2015-03-06 15:44:59 +01:00
|
|
|
events: events,
|
2015-01-13 16:17:43 -08:00
|
|
|
lifecycle: lifecycle
|
2014-11-21 21:19:23 -08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2015-01-13 16:17:43 -08:00
|
|
|
|
2015-03-14 00:00:42 +00:00
|
|
|
//TODO(misko): turn into LifecycleEvent class once we switch to TypeScript;
|
|
|
|
|
|
|
|
/**
|
2015-03-19 14:31:41 +01:00
|
|
|
* Notify a directive whenever a [View] that contains it is destroyed.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* ## Example
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* ...,
|
2015-03-30 10:03:51 +02:00
|
|
|
* lifecycle: [onDestroy]
|
2015-03-17 19:22:13 +00:00
|
|
|
* })
|
2015-03-26 17:50:18 -07:00
|
|
|
* class ClassSet {
|
2015-03-17 19:22:13 +00:00
|
|
|
* onDestroy() {
|
|
|
|
* // invoked to notify directive of the containing view destruction.
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-17 23:29:27 +00:00
|
|
|
* @publicModule angular2/annotations
|
2015-03-14 00:00:42 +00:00
|
|
|
*/
|
2015-02-06 13:19:47 -08:00
|
|
|
export const onDestroy = "onDestroy";
|
2015-03-14 00:00:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-03-19 14:31:41 +01:00
|
|
|
* Notify a directive when any of its bindings have changed.
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
2015-03-26 17:50:18 -07:00
|
|
|
* This method is called right after the directive's bindings have been checked,
|
|
|
|
* and before any of its children's bindings have been checked.
|
|
|
|
*
|
|
|
|
* It is invoked only if at least one of the directive's bindings has changed.
|
|
|
|
*
|
2015-03-14 00:00:42 +00:00
|
|
|
* ## Example:
|
2015-03-17 19:22:13 +00:00
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* selector: '[class-set]',
|
|
|
|
* bind: {
|
|
|
|
* 'propA': 'propA'
|
|
|
|
* 'propB': 'propB'
|
2015-03-30 10:03:51 +02:00
|
|
|
* },
|
|
|
|
* lifecycle: [onChange]
|
2015-03-17 19:22:13 +00:00
|
|
|
* })
|
|
|
|
* class ClassSet {
|
|
|
|
* propA;
|
|
|
|
* propB;
|
|
|
|
* onChange(changes:{[idx: string, PropertyUpdate]}) {
|
|
|
|
* // This will get called after any of the properties have been updated.
|
|
|
|
* if (changes['propA']) {
|
|
|
|
* // if propA was updated
|
|
|
|
* }
|
|
|
|
* if (changes['propA']) {
|
|
|
|
* // if propB was updated
|
2015-03-14 00:00:42 +00:00
|
|
|
* }
|
2015-03-17 19:22:13 +00:00
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
2015-03-17 23:29:27 +00:00
|
|
|
* @publicModule angular2/annotations
|
2015-03-14 00:00:42 +00:00
|
|
|
*/
|
2015-02-06 13:19:47 -08:00
|
|
|
export const onChange = "onChange";
|
2015-03-26 14:36:25 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notify a directive when the bindings of all its children have been changed.
|
|
|
|
*
|
|
|
|
* ## Example:
|
|
|
|
*
|
|
|
|
* ```
|
|
|
|
* @Decorator({
|
|
|
|
* selector: '[class-set]',
|
2015-03-30 10:03:51 +02:00
|
|
|
* lifecycle: [onAllChangesDone]
|
2015-03-26 14:36:25 -07:00
|
|
|
* })
|
|
|
|
* class ClassSet {
|
|
|
|
*
|
|
|
|
* onAllChangesDone() {
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
* @publicModule angular2/annotations
|
|
|
|
*/
|
|
|
|
export const onAllChangesDone = "onAllChangesDone";
|