feat(Directive): convert properties to an array

fixes #2013

BREAKING CHANGE:

Before

    @Directive(properties: {
      'sameName': 'sameName',
      'directiveProp': 'elProp | pipe'
    })

After

    @Directive(properties: [
      'sameName',
      'directiveProp: elProp | pipe'
    ])
This commit is contained in:
Victor Berchet
2015-05-26 15:54:10 +02:00
parent 0387221da8
commit d7df853bde
40 changed files with 182 additions and 179 deletions

View File

@ -103,9 +103,9 @@ import {DEFAULT} from 'angular2/change_detection';
*
* @Directive({
* selector: '[dependency]',
* properties: {
* 'id':'dependency'
* }
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
@ -275,9 +275,9 @@ import {DEFAULT} from 'angular2/change_detection';
* ```
* @Directive({
* selector: '[tooltip]',
* properties: {
* 'text': 'tooltip'
* },
* properties: [
* 'text: tooltip'
* ],
* hostListeners: {
* 'onmouseenter': 'onMouseEnter()',
* 'onmouseleave': 'onMouseLeave()'
@ -361,9 +361,7 @@ import {DEFAULT} from 'angular2/change_detection';
* ```
* @Directive({
* selector: '[unless]',
* properties: {
* 'unless': 'unless'
* }
* properties: ['unless']
* })
* export class Unless {
* viewContainer: ViewContainerRef;
@ -453,25 +451,28 @@ export class Directive extends Injectable {
* Enumerates the set of properties that accept data binding for a directive.
*
* The `properties` property defines a set of `directiveProperty` to `bindingProperty`
* key-value pairs:
* configuration:
*
* - `directiveProperty` specifies the component property where the value is written.
* - `bindingProperty` specifies the DOM property where the value is read from.
*
* You can include a {@link Pipe} when specifying a `bindingProperty` to allow for data
* transformation and structural
* change detection of the value. These pipes will be evaluated in the context of this component.
*
* transformation and structural change detection of the value. These pipes will be evaluated in
* the context of this component.
*
* ## Syntax
*
* There is no need to specify both `directiveProperty` and `bindingProperty` when they both have
* the same value.
*
* ```
* @Directive({
* properties: {
* 'directiveProperty1': 'bindingProperty1',
* 'directiveProperty2': 'bindingProperty2 | pipe1 | ...',
* properties: [
* 'propertyName', // shorthand notation for 'propertyName: propertyName'
* 'directiveProperty1: bindingProperty1',
* 'directiveProperty2: bindingProperty2 | pipe1 | ...',
* ...
* }
* ]
* }
* ```
*
@ -479,26 +480,24 @@ export class Directive extends Injectable {
* ## 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:
* be used in templates with standard Angular syntax. For example:
*
* ```
* @Directive({
* selector: '[tooltip]',
* properties: {
* 'text': 'tooltip'
* }
* properties: [
* 'text: tooltip'
* ]
* })
* class Tooltip {
* set text(text) {
* // This will get called every time the 'tooltip' binding changes with the new value.
* set text(value: string) {
* // This will get called every time with the new value when the 'tooltip' property changes
* }
* }
* ```
*
* 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:
* string literal, as shown in the HTML template below:
*
* ```html
* <div [tooltip]="someExpression">...</div>
@ -508,27 +507,24 @@ export class Directive extends Injectable {
* Whenever the `someExpression` expression changes, the `properties` declaration instructs
* Angular to update the `Tooltip`'s `text` property.
*
*
*
* ## Bindings With Pipes
*
* You can also use pipes when writing binding definitions for a directive.
*
* 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.
* than on reference changes, as normally occurs in change detection.
*
* See {@link Pipe} and {@link keyValDiff} documentation for more details.
*
* ```
* @Directive({
* selector: '[class-set]',
* properties: {
* 'classChanges': 'classSet | keyValDiff'
* }
* properties: [
* 'classChanges: classSet | keyValDiff'
* ]
* })
* class ClassSet {
* set classChanges(changes:KeyValueChanges) {
* set classChanges(changes: KeyValueChanges) {
* // This will get called every time the `class-set` expressions changes its structure.
* }
* }
@ -544,7 +540,7 @@ export class Directive extends Injectable {
* keyValDiff`.
*
*/
properties: StringMap<string, string>;
properties: List<string>;
/**
* Enumerates the set of emitted events.
@ -756,7 +752,7 @@ export class Directive extends Injectable {
hostActions, lifecycle, hostInjector, compileChildren = true,
}: {
selector?: string,
properties?: any,
properties?: List<string>,
events?: List<string>,
hostListeners?: StringMap<string, string>,
hostProperties?: StringMap<string, string>,
@ -981,7 +977,7 @@ export class Component extends Directive {
hostActions, appInjector, lifecycle, hostInjector, viewInjector,
changeDetection = DEFAULT, compileChildren = true}: {
selector?: string,
properties?: Object,
properties?: List<string>,
events?: List<string>,
hostListeners?: Map<string, string>,
hostProperties?: any,
@ -1053,10 +1049,10 @@ export const onDestroy = CONST_EXPR(new LifecycleEvent("onDestroy"));
* ```
* @Directive({
* selector: '[class-set]',
* properties: {
* 'propA': 'propA'
* 'propB': 'propB'
* },
* properties: [
* 'propA',
* 'propB'
* ],
* lifecycle: [onChange]
* })
* class ClassSet {

View File

@ -21,9 +21,9 @@ export class Visibility extends DependencyAnnotation {
* ```
* @Directive({
* selector: '[dependency]',
* properties: {
* 'id':'dependency'
* }
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
@ -66,9 +66,9 @@ export var self = new Self();
* ```
* @Directive({
* selector: '[dependency]',
* properties: {
* 'id':'dependency'
* }
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
@ -118,9 +118,9 @@ export class Parent extends Visibility {
* ```
* @Directive({
* selector: '[dependency]',
* properties: {
* 'id':'dependency'
* }
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
@ -178,9 +178,9 @@ export class Ancestor extends Visibility {
* ```
* @Directive({
* selector: '[dependency]',
* properties: {
* 'id':'dependency'
* }
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;

View File

@ -300,7 +300,7 @@ export class DirectiveBinding extends ResolvedBinding {
isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null,
hostActions: isPresent(ann.hostActions) ? MapWrapper.createFromStringMap(ann.hostActions) :
null,
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null,
properties: ann.properties,
readAttributes: DirectiveBinding._readAttributes(deps),
callOnDestroy: hasLifecycleHook(onDestroy, rb.key.token, ann),

View File

@ -4,7 +4,7 @@ import {ElementRef} from 'angular2/core';
import {isPresent} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter';
@Directive({selector: '[class]', properties: {'iterableChanges': 'class | keyValDiff'}})
@Directive({selector: '[class]', properties: ['iterableChanges: class | keyValDiff']})
export class CSSClass {
_domEl;
constructor(ngEl: ElementRef) { this._domEl = ngEl.domElement; }

View File

@ -36,7 +36,7 @@ import {ListWrapper} from 'angular2/src/facade/collection';
* @exportedAs angular2/directives
*/
@Directive(
{selector: '[ng-for][ng-for-of]', properties: {'iterableChanges': 'ngForOf | iterableDiff'}})
{selector: '[ng-for][ng-for-of]', properties: ['iterableChanges: ngForOf | iterableDiff']})
export class NgFor {
viewContainer: ViewContainerRef;
protoViewRef: ProtoViewRef;

View File

@ -27,7 +27,7 @@ import {isBlank} from 'angular2/src/facade/lang';
*
* @exportedAs angular2/directives
*/
@Directive({selector: '[ng-if]', properties: {'ngIf': 'ngIf'}})
@Directive({selector: '[ng-if]', properties: ['ngIf']})
export class NgIf {
viewContainer: ViewContainerRef;
protoViewRef: ProtoViewRef;

View File

@ -44,7 +44,7 @@ export class SwitchView {
*
* @exportedAs angular2/directives
*/
@Directive({selector: '[ng-switch]', properties: {'ngSwitch': 'ngSwitch'}})
@Directive({selector: '[ng-switch]', properties: ['ngSwitch']})
export class NgSwitch {
_switchValue: any;
_useDefault: boolean;
@ -153,7 +153,7 @@ export class NgSwitch {
*
* @exportedAs angular2/directives
*/
@Directive({selector: '[ng-switch-when]', properties: {'ngSwitchWhen': 'ngSwitchWhen'}})
@Directive({selector: '[ng-switch-when]', properties: ['ngSwitchWhen']})
export class NgSwitchWhen {
_value: any;
_switch: NgSwitch;

View File

@ -73,7 +73,7 @@ function _lookupControl(groupDirective: ControlGroupDirective, controlOrName: an
*
* @exportedAs angular2/forms
*/
@Directive({selector: '[control-group]', properties: {'controlOrName': 'control-group'}})
@Directive({selector: '[control-group]', properties: ['controlOrName: control-group']})
export class ControlGroupDirective {
_groupDirective: ControlGroupDirective;
_directives: List<ControlDirective>;
@ -133,7 +133,7 @@ export class ControlGroupDirective {
*
* @exportedAs angular2/forms
*/
@Directive({selector: '[control]', properties: {'controlOrName': 'control'}})
@Directive({selector: '[control]', properties: ['controlOrName: control']})
export class ControlDirective {
_groupDirective: ControlGroupDirective;

View File

@ -133,7 +133,7 @@ export class DirectiveMetadata {
hostProperties: Map<string, string>;
hostAttributes: Map<string, string>;
hostActions: Map<string, string>;
properties: Map<string, string>;
properties: List<string>;
readAttributes: List<string>;
type: number;
callOnDestroy: boolean;
@ -153,7 +153,7 @@ export class DirectiveMetadata {
hostProperties?: Map<string, string>,
hostAttributes?: Map<string, string>,
hostActions?: Map<string, string>,
properties?: Map<string, string>,
properties?: List<string>,
readAttributes?: List<string>,
type?: number,
callOnDestroy?: boolean,

View File

@ -89,8 +89,8 @@ import {
var directiveBinderBuilder = elementBinder.bindDirective(directiveIndex);
current.compileChildren = current.compileChildren && directive.compileChildren;
if (isPresent(directive.properties)) {
MapWrapper.forEach(directive.properties, (bindConfig, dirProperty) => {
this._bindDirectiveProperty(dirProperty, bindConfig, current, directiveBinderBuilder);
ListWrapper.forEach(directive.properties, (bindConfig) => {
this._bindDirectiveProperty(bindConfig, current, directiveBinderBuilder);
});
}
if (isPresent(directive.hostListeners)) {
@ -121,10 +121,27 @@ import {
});
}
_bindDirectiveProperty(dirProperty: string, bindConfig: string, compileElement: CompileElement,
_bindDirectiveProperty(bindConfig: string, compileElement: CompileElement,
directiveBinderBuilder: DirectiveBuilder) {
var pipes = this._splitBindConfig(bindConfig);
var elProp = ListWrapper.removeAt(pipes, 0);
// Name of the property on the directive
let dirProperty: string;
// Name of the property on the element
let elProp: string;
let pipes: List<string>;
let assignIndex: number = bindConfig.indexOf(':');
if (assignIndex > -1) {
// canonical syntax: `dirProp: elProp | pipe0 | ... | pipeN`
dirProperty = StringWrapper.substring(bindConfig, 0, assignIndex).trim();
pipes = this._splitBindConfig(StringWrapper.substring(bindConfig, assignIndex + 1));
elProp = ListWrapper.removeAt(pipes, 0);
} else {
// shorthand syntax when the name of the property on the directive and on the element is the
// same, ie `property`
dirProperty = bindConfig;
elProp = bindConfig;
pipes = [];
}
var bindingAst =
MapWrapper.get(compileElement.bindElement().propertyBindings, dashCaseToCamelCase(elProp));

View File

@ -36,7 +36,7 @@ export function directiveMetadataFromMap(map: Map<string, any>): DirectiveMetada
hostProperties:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostProperties')),
hostActions:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostActions')),
hostAttributes:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostAttributes')),
properties:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'properties')),
properties:<List<string>>_cloneIfPresent(MapWrapper.get(map, 'properties')),
readAttributes:<List<string>>_cloneIfPresent(MapWrapper.get(map, 'readAttributes')),
type:<number>MapWrapper.get(map, 'type')
});

View File

@ -31,10 +31,10 @@ import {Location} from './location';
*/
@Directive({
selector: '[router-link]',
properties: {
'route': 'routerLink',
'params': 'routerParams'
},
properties: [
'route: routerLink',
'params: routerParams'
],
lifecycle: [onAllChangesDone]
})
export class RouterLink {

View File

@ -56,7 +56,7 @@ class _DirectiveMetadataVisitor extends Object
meta = new DirectiveMetadata(
type: type,
compileChildren: true,
properties: {},
properties: [],
hostListeners: {},
hostProperties: {},
hostAttributes: {},