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

@ -63,9 +63,9 @@ Here is a trivial example of a tooltip decorator. The directive will log a toolt
``` ```
@Directive({ @Directive({
selector: '[tooltip]', | CSS Selector which triggers the decorator selector: '[tooltip]', | CSS Selector which triggers the decorator
properties: { | List which properties need to be bound properties: [ | List which properties need to be bound
text: 'tooltip' | - DOM element tooltip property should be 'text: tooltip' | - DOM element tooltip property should be
}, | mapped to the directive text property. ], | mapped to the directive text property.
hostListeners: { | List which events need to be mapped. hostListeners: { | List which events need to be mapped.
mouseover: 'show' | - Invoke the show() method every time mouseover: 'show' | - Invoke the show() method every time
} | the mouseover event is fired. } | the mouseover event is fired.
@ -108,10 +108,10 @@ Example of a component:
``` ```
@Component({ | Component annotation @Component({ | Component annotation
selector: 'pane', | CSS selector on <pane> element selector: 'pane', | CSS selector on <pane> element
properties: { | List which property need to be bound properties: [ | List which property need to be bound
'title': 'title', | - title mapped to component title 'title', | - title mapped to component title
'open': 'open' | - open attribute mapped to component's open property 'open' | - open attribute mapped to component's open property
}, | ], |
}) | }) |
@View({ | View annotation @View({ | View annotation
templateUrl: 'pane.html' | - URL of template HTML templateUrl: 'pane.html' | - URL of template HTML
@ -173,9 +173,9 @@ Directives that use a ViewContainer can control instantiation of child views whi
``` ```
@Directive({ @Directive({
selector: '[if]', selector: '[if]',
properties: { properties: [
'condition': 'if' 'condition: if'
} ]
}) })
export class If { export class If {
viewContainer: ViewContainerRef; viewContainer: ViewContainerRef;

View File

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

View File

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

View File

@ -300,7 +300,7 @@ export class DirectiveBinding extends ResolvedBinding {
isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null, isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null,
hostActions: isPresent(ann.hostActions) ? MapWrapper.createFromStringMap(ann.hostActions) : hostActions: isPresent(ann.hostActions) ? MapWrapper.createFromStringMap(ann.hostActions) :
null, null,
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null, properties: ann.properties,
readAttributes: DirectiveBinding._readAttributes(deps), readAttributes: DirectiveBinding._readAttributes(deps),
callOnDestroy: hasLifecycleHook(onDestroy, rb.key.token, ann), 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 {isPresent} from 'angular2/src/facade/lang';
import {DOM} from 'angular2/src/dom/dom_adapter'; 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 { export class CSSClass {
_domEl; _domEl;
constructor(ngEl: ElementRef) { this._domEl = ngEl.domElement; } constructor(ngEl: ElementRef) { this._domEl = ngEl.domElement; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -89,8 +89,8 @@ import {
var directiveBinderBuilder = elementBinder.bindDirective(directiveIndex); var directiveBinderBuilder = elementBinder.bindDirective(directiveIndex);
current.compileChildren = current.compileChildren && directive.compileChildren; current.compileChildren = current.compileChildren && directive.compileChildren;
if (isPresent(directive.properties)) { if (isPresent(directive.properties)) {
MapWrapper.forEach(directive.properties, (bindConfig, dirProperty) => { ListWrapper.forEach(directive.properties, (bindConfig) => {
this._bindDirectiveProperty(dirProperty, bindConfig, current, directiveBinderBuilder); this._bindDirectiveProperty(bindConfig, current, directiveBinderBuilder);
}); });
} }
if (isPresent(directive.hostListeners)) { if (isPresent(directive.hostListeners)) {
@ -121,10 +121,27 @@ import {
}); });
} }
_bindDirectiveProperty(dirProperty: string, bindConfig: string, compileElement: CompileElement, _bindDirectiveProperty(bindConfig: string, compileElement: CompileElement,
directiveBinderBuilder: DirectiveBuilder) { directiveBinderBuilder: DirectiveBuilder) {
var pipes = this._splitBindConfig(bindConfig); // Name of the property on the directive
var elProp = ListWrapper.removeAt(pipes, 0); 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 = var bindingAst =
MapWrapper.get(compileElement.bindElement().propertyBindings, dashCaseToCamelCase(elProp)); 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')), hostProperties:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostProperties')),
hostActions:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostActions')), hostActions:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostActions')),
hostAttributes:<Map<string, string>>_cloneIfPresent(MapWrapper.get(map, 'hostAttributes')), 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')), readAttributes:<List<string>>_cloneIfPresent(MapWrapper.get(map, 'readAttributes')),
type:<number>MapWrapper.get(map, 'type') type:<number>MapWrapper.get(map, 'type')
}); });

View File

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

View File

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

View File

@ -219,7 +219,7 @@ export function main() {
it('should set directive.bind', inject([AsyncTestCompleter], (async) => { it('should set directive.bind', inject([AsyncTestCompleter], (async) => {
captureDirective(DirectiveWithBind) captureDirective(DirectiveWithBind)
.then((renderDir) => { .then((renderDir) => {
expect(renderDir.properties).toEqual(MapWrapper.createFromStringMap({'a': 'b'})); expect(renderDir.properties).toEqual(['a: b']);
async.done(); async.done();
}); });
})); }));
@ -478,7 +478,7 @@ class DirectiveWithEvents {
class DirectiveWithProperties { class DirectiveWithProperties {
} }
@Directive({properties: {'a': 'b'}}) @Directive({properties: ['a: b']})
class DirectiveWithBind { class DirectiveWithBind {
} }

View File

@ -191,7 +191,7 @@ class NoPropertyAccess {
selector: 'on-change', selector: 'on-change',
// TODO: needed because of https://github.com/angular/angular/issues/2120 // TODO: needed because of https://github.com/angular/angular/issues/2120
lifecycle: const [onChange], lifecycle: const [onChange],
properties: const { 'prop': 'prop' } properties: const ['prop']
) )
@View(template: '') @View(template: '')
class OnChangeComponent implements OnChange { class OnChangeComponent implements OnChange {

View File

@ -1173,14 +1173,14 @@ class DynamicViewport {
} }
} }
@Directive({selector: '[my-dir]', properties: {'dirProp': 'elprop'}}) @Directive({selector: '[my-dir]', properties: ['dirProp: elprop']})
@Injectable() @Injectable()
class MyDir { class MyDir {
dirProp: string; dirProp: string;
constructor() { this.dirProp = ''; } constructor() { this.dirProp = ''; }
} }
@Component({selector: 'push-cmp', properties: {'prop': 'prop'}, changeDetection: ON_PUSH}) @Component({selector: 'push-cmp', properties: ['prop'], changeDetection: ON_PUSH})
@View({template: '{{field}}'}) @View({template: '{{field}}'})
@Injectable() @Injectable()
class PushCmp { class PushCmp {
@ -1195,7 +1195,7 @@ class PushCmp {
} }
} }
@Component({selector: 'push-cmp-with-ref', properties: {'prop': 'prop'}, changeDetection: ON_PUSH}) @Component({selector: 'push-cmp-with-ref', properties: ['prop'], changeDetection: ON_PUSH})
@View({template: '{{field}}'}) @View({template: '{{field}}'})
@Injectable() @Injectable()
class PushCmpWithRef { class PushCmpWithRef {
@ -1230,7 +1230,7 @@ class MyComp {
} }
} }
@Component({selector: 'component-with-pipes', properties: {"prop": "prop | double"}}) @Component({selector: 'component-with-pipes', properties: ["prop: prop | double"]})
@View({template: ''}) @View({template: ''})
@Injectable() @Injectable()
class ComponentWithPipes { class ComponentWithPipes {
@ -1412,7 +1412,7 @@ class DirectiveListeningDomEventNoPrevent {
onEvent(event) { return true; } onEvent(event) { return true; }
} }
@Directive({selector: '[id]', properties: {'id': 'id'}}) @Directive({selector: '[id]', properties: ['id']})
@Injectable() @Injectable()
class IdDir { class IdDir {
id: string; id: string;
@ -1459,7 +1459,7 @@ class ToolbarPart {
} }
} }
@Directive({selector: '[toolbar-vc]', properties: {'toolbarVc': 'toolbarVc'}}) @Directive({selector: '[toolbar-vc]', properties: ['toolbarVc']})
@Injectable() @Injectable()
class ToolbarViewContainer { class ToolbarViewContainer {
vc: ViewContainerRef; vc: ViewContainerRef;
@ -1487,7 +1487,7 @@ class ToolbarComponent {
} }
} }
@Directive({selector: '[two-way]', properties: {value: 'control'}, events: ['control']}) @Directive({selector: '[two-way]', properties: ['value: control'], events: ['control']})
@Injectable() @Injectable()
class DirectiveWithTwoWayBinding { class DirectiveWithTwoWayBinding {
control: EventEmitter; control: EventEmitter;

View File

@ -87,7 +87,7 @@ export function main() {
}); });
} }
@Directive({selector: '[text]', properties: {'text': 'text'}}) @Directive({selector: '[text]', properties: ['text']})
@Injectable() @Injectable()
class TextDirective { class TextDirective {
text: string; text: string;

View File

@ -48,11 +48,8 @@ export function main() {
} }
@Directive({ @Directive(
selector: "[lifecycle]", {selector: "[lifecycle]", properties: ['field'], lifecycle: [onChange, onCheck, onInit]})
properties: {'field': 'field'},
lifecycle: [onChange, onCheck, onInit]
})
class LifecycleDir { class LifecycleDir {
field; field;
log: List<string>; log: List<string>;

View File

@ -239,8 +239,7 @@ var decoratorWithMultipleAttrs = new DirectiveMetadata({
var someDirectiveWithProps = new DirectiveMetadata({ var someDirectiveWithProps = new DirectiveMetadata({
selector: '[some-decor-props]', selector: '[some-decor-props]',
properties: properties: ['dirProp: elProp', 'doubleProp: elProp | double'],
MapWrapper.createFromStringMap({'dirProp': 'elProp', 'doubleProp': 'elProp | double'}),
readAttributes: ['some-attr'] readAttributes: ['some-attr']
}); });

View File

@ -12,7 +12,7 @@ export function main() {
hostProperties: MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]), hostProperties: MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']]),
hostActions: MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]), hostActions: MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]),
id: 'someComponent', id: 'someComponent',
properties: MapWrapper.createFromPairs([['propKey', 'propVal']]), properties: ['propKey: propVal'],
readAttributes: ['read1', 'read2'], readAttributes: ['read1', 'read2'],
selector: 'some-comp', selector: 'some-comp',
type: DirectiveMetadata.COMPONENT_TYPE type: DirectiveMetadata.COMPONENT_TYPE
@ -26,8 +26,7 @@ export function main() {
expect(MapWrapper.get(map, 'hostActions')) expect(MapWrapper.get(map, 'hostActions'))
.toEqual(MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])); .toEqual(MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
expect(MapWrapper.get(map, 'id')).toEqual('someComponent'); expect(MapWrapper.get(map, 'id')).toEqual('someComponent');
expect(MapWrapper.get(map, 'properties')) expect(MapWrapper.get(map, 'properties')).toEqual(['propKey: propVal']);
.toEqual(MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(MapWrapper.get(map, 'readAttributes')).toEqual(['read1', 'read2']); expect(MapWrapper.get(map, 'readAttributes')).toEqual(['read1', 'read2']);
expect(MapWrapper.get(map, 'selector')).toEqual('some-comp'); expect(MapWrapper.get(map, 'selector')).toEqual('some-comp');
expect(MapWrapper.get(map, 'type')).toEqual(DirectiveMetadata.COMPONENT_TYPE); expect(MapWrapper.get(map, 'type')).toEqual(DirectiveMetadata.COMPONENT_TYPE);
@ -40,7 +39,7 @@ export function main() {
['hostProperties', MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']])], ['hostProperties', MapWrapper.createFromPairs([['hostPropKey', 'hostPropVal']])],
['hostActions', MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])], ['hostActions', MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])],
['id', 'testId'], ['id', 'testId'],
['properties', MapWrapper.createFromPairs([['propKey', 'propVal']])], ['properties', ['propKey: propVal']],
['readAttributes', ['readTest1', 'readTest2']], ['readAttributes', ['readTest1', 'readTest2']],
['selector', 'testSelector'], ['selector', 'testSelector'],
['type', DirectiveMetadata.DIRECTIVE_TYPE] ['type', DirectiveMetadata.DIRECTIVE_TYPE]
@ -53,7 +52,7 @@ export function main() {
expect(meta.hostActions) expect(meta.hostActions)
.toEqual(MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']])); .toEqual(MapWrapper.createFromPairs([['hostActionKey', 'hostActionVal']]));
expect(meta.id).toEqual('testId'); expect(meta.id).toEqual('testId');
expect(meta.properties).toEqual(MapWrapper.createFromPairs([['propKey', 'propVal']])); expect(meta.properties).toEqual(['propKey: propVal']);
expect(meta.readAttributes).toEqual(['readTest1', 'readTest2']); expect(meta.readAttributes).toEqual(['readTest1', 'readTest2']);
expect(meta.selector).toEqual('testSelector'); expect(meta.selector).toEqual('testSelector');
expect(meta.type).toEqual(DirectiveMetadata.DIRECTIVE_TYPE); expect(meta.type).toEqual(DirectiveMetadata.DIRECTIVE_TYPE);

View File

@ -43,7 +43,7 @@ class Logger {
add(thing: string) { ListWrapper.push(this.log, thing); } add(thing: string) { ListWrapper.push(this.log, thing); }
} }
@Directive({selector: '[message]', properties: {'message': 'message'}}) @Directive({selector: '[message]', properties: ['message']})
@Injectable() @Injectable()
class MessageDir { class MessageDir {
logger: Logger; logger: Logger;

View File

@ -13,7 +13,7 @@ void initReflector(reflector) {
'parameters': const [], 'parameters': const [],
'annotations': const [ 'annotations': const [
const Directive( const Directive(
selector: '[tool-tip]', properties: const {'text': 'tool-tip'}) selector: '[tool-tip]', properties: const ['text: tool-tip'])
] ]
}); });
} }

View File

@ -13,7 +13,7 @@ void initReflector(reflector) {
'parameters': const [], 'parameters': const [],
'annotations': const [ 'annotations': const [
const Directive( const Directive(
selector: '[tool-tip]', properties: const {'text': 'tool-tip'}) selector: '[tool-tip]', properties: const ['text: tool-tip'])
] ]
}) })
..registerSetters({'text': (o, v) => o.text = v}); ..registerSetters({'text': (o, v) => o.text = v});

View File

@ -14,13 +14,13 @@ void initReflector(reflector) {
'annotations': const [ 'annotations': const [
const Component( const Component(
componentServices: const [SaladComponent], componentServices: const [SaladComponent],
properties: const {'menu': 'menu'}) properties: const ['menu'])
] ]
}) })
..registerType(SaladComponent, { ..registerType(SaladComponent, {
'factory': () => new SaladComponent(), 'factory': () => new SaladComponent(),
'parameters': const [], 'parameters': const [],
'annotations': const [const Component(properties: const {'menu': 'menu'})] 'annotations': const [const Component(properties: const ['menu'])]
}) })
..registerSetters({'menu': (o, v) => o.menu = v}); ..registerSetters({'menu': (o, v) => o.menu = v});
} }

View File

@ -14,12 +14,12 @@ void initReflector(reflector) {
'annotations': const [ 'annotations': const [
const Component( const Component(
componentServices: const [SaladComponent], componentServices: const [SaladComponent],
properties: const {'menu': 'menu'}) properties: const ['menu'])
] ]
}) })
..registerType(SaladComponent, { ..registerType(SaladComponent, {
'factory': () => new SaladComponent(), 'factory': () => new SaladComponent(),
'parameters': const [], 'parameters': const [],
'annotations': const [const Component(properties: const {'menu': 'menu'})] 'annotations': const [const Component(properties: const ['menu'])]
}); });
} }

View File

@ -13,7 +13,7 @@ void initReflector(reflector) {
'factory': () => new HelloCmp(), 'factory': () => new HelloCmp(),
'parameters': const [const []], 'parameters': const [const []],
'annotations': const [ 'annotations': const [
const Component(properties: const {'key1': 'val1', 'key2': 'val2'}) const Component(properties: const ['key1: val1', 'key2: val2'])
] ]
}); });
} }

View File

@ -11,7 +11,7 @@ export class MdButton {
@Component({ @Component({
selector: '[md-button][href]', selector: '[md-button][href]',
properties: {'disabled': 'disabled'}, properties: ['disabled'],
hostListeners: {'click': 'onClick($event)'}, hostListeners: {'click': 'onClick($event)'},
hostProperties: {'tabIndex': 'tabIndex'}, hostProperties: {'tabIndex': 'tabIndex'},
lifecycle: [onChange] lifecycle: [onChange]

View File

@ -6,7 +6,7 @@ import {NumberWrapper} from 'angular2/src/facade/lang';
@Component({ @Component({
selector: 'md-checkbox', selector: 'md-checkbox',
properties: {'checked': 'checked', 'disabled': 'disabled'}, properties: ['checked', 'disabled'],
hostListeners: {'keydown': 'onKeydown($event)'}, hostListeners: {'keydown': 'onKeydown($event)'},
hostProperties: { hostProperties: {
'tabindex': 'tabindex', 'tabindex': 'tabindex',

View File

@ -19,7 +19,7 @@ import {Math} from 'angular2/src/facade/math';
@Component({ @Component({
selector: 'md-grid-list', selector: 'md-grid-list',
properties: {'cols': 'cols', 'rowHeight': 'row-height', 'gutterSize': 'gutter-size'}, properties: ['cols', 'rowHeight', 'gutterSize'],
lifecycle: [onAllChangesDone] lifecycle: [onAllChangesDone]
}) })
@View({templateUrl: 'angular2_material/src/components/grid_list/grid_list.html'}) @View({templateUrl: 'angular2_material/src/components/grid_list/grid_list.html'})
@ -217,7 +217,7 @@ export class MdGridList {
@Component({ @Component({
selector: 'md-grid-tile', selector: 'md-grid-tile',
properties: {'rowspan': 'rowspan', 'colspan': 'colspan'}, properties: ['rowspan', 'colspan'],
hostProperties: { hostProperties: {
'styleHeight': 'style.height', 'styleHeight': 'style.height',
'styleWidth': 'style.width', 'styleWidth': 'style.width',

View File

@ -6,7 +6,7 @@ import {Math} from 'angular2/src/facade/math';
@Component({ @Component({
selector: 'md-progress-linear', selector: 'md-progress-linear',
lifecycle: [onChange], lifecycle: [onChange],
properties: {'value': 'value', 'bufferValue': 'buffer-value'}, properties: ['value', 'bufferValue'],
hostProperties: { hostProperties: {
'role': 'attr.role', 'role': 'attr.role',
'ariaValuemin': 'attr.aria-valuemin', 'ariaValuemin': 'attr.aria-valuemin',

View File

@ -26,7 +26,7 @@ var _uniqueIdCounter: number = 0;
selector: 'md-radio-group', selector: 'md-radio-group',
lifecycle: [onChange], lifecycle: [onChange],
events: ['change'], events: ['change'],
properties: {'disabled': 'disabled', 'value': 'value'}, properties: ['disabled', 'value'],
hostListeners: { hostListeners: {
// TODO(jelbourn): Remove ^ when event retargeting is fixed. // TODO(jelbourn): Remove ^ when event retargeting is fixed.
'^keydown': 'onKeydown($event)' '^keydown': 'onKeydown($event)'
@ -186,8 +186,7 @@ export class MdRadioGroup {
@Component({ @Component({
selector: 'md-radio-button', selector: 'md-radio-button',
lifecycle: [onChange], lifecycle: [onChange],
properties: properties: ['id', 'name', 'value', 'checked', 'disabled'],
{'id': 'id', 'name': 'name', 'value': 'value', 'checked': 'checked', 'disabled': 'disabled'},
hostListeners: {'keydown': 'onKeydown($event)'}, hostListeners: {'keydown': 'onKeydown($event)'},
hostProperties: { hostProperties: {
'id': 'id', 'id': 'id',

View File

@ -8,7 +8,7 @@ import {NumberWrapper} from 'angular2/src/facade/lang';
@Component({ @Component({
selector: 'md-switch', selector: 'md-switch',
properties: {'checked': 'checked', 'disabled': 'disabled'}, properties: ['checked', 'disabled'],
hostListeners: {'keydown': 'onKeydown($event)'}, hostListeners: {'keydown': 'onKeydown($event)'},
hostProperties: hostProperties:
{'checked': 'attr.aria-checked', 'disabled_': 'attr.aria-disabled', 'role': 'attr.role'} {'checked': 'attr.aria-checked', 'disabled_': 'attr.aria-disabled', 'role': 'attr.role'}

View File

@ -81,17 +81,17 @@ export function main() {
@Directive({ @Directive({
selector: '[dir0]', selector: '[dir0]',
properties: { properties: [
'prop': 'attr0' 'prop: attr0'
} ]
}) })
class Dir0 {} class Dir0 {}
@Directive({ @Directive({
selector: '[dir1]', selector: '[dir1]',
properties: { properties: [
'prop': 'attr1' 'prop: attr1'
} ]
}) })
class Dir1 { class Dir1 {
constructor(dir0:Dir0) {} constructor(dir0:Dir0) {}
@ -99,9 +99,9 @@ class Dir1 {
@Directive({ @Directive({
selector: '[dir2]', selector: '[dir2]',
properties: { properties: [
'prop': 'attr2' 'prop: attr2'
} ]
}) })
class Dir2 { class Dir2 {
constructor(dir1:Dir1) {} constructor(dir1:Dir1) {}
@ -109,9 +109,9 @@ class Dir2 {
@Directive({ @Directive({
selector: '[dir3]', selector: '[dir3]',
properties: { properties: [
'prop': 'attr3' 'prop: attr3'
} ]
}) })
class Dir3 { class Dir3 {
constructor(dir2:Dir2) {} constructor(dir2:Dir2) {}
@ -119,9 +119,9 @@ class Dir3 {
@Directive({ @Directive({
selector: '[dir4]', selector: '[dir4]',
properties: { properties: [
'prop': 'attr4' 'prop: attr4'
} ]
}) })
class Dir4 { class Dir4 {
constructor(dir3:Dir3) {} constructor(dir3:Dir3) {}

View File

@ -233,10 +233,10 @@ class AppComponent {
@Component({ @Component({
selector: 'largetable', selector: 'largetable',
properties: { properties: [
'data': 'data', 'data',
'benchmarkType': 'benchmarktype' 'benchmarkType'
} ]
}) })
@View({ @View({
directives: [NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault], directives: [NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault],

View File

@ -22,10 +22,10 @@ export class HasStyle {
@Component({ @Component({
selector: 'company-name', selector: 'company-name',
properties: { properties: [
'width': 'cell-width', 'width: cell-width',
'company': 'company' 'company'
} ]
}) })
@View({ @View({
directives: [], directives: [],
@ -37,10 +37,10 @@ export class CompanyNameComponent extends HasStyle {
@Component({ @Component({
selector: 'opportunity-name', selector: 'opportunity-name',
properties: { properties: [
'width': 'cell-width', 'width: cell-width',
'opportunity': 'opportunity' 'opportunity'
} ]
}) })
@View({ @View({
directives: [], directives: [],
@ -52,10 +52,10 @@ export class OpportunityNameComponent extends HasStyle {
@Component({ @Component({
selector: 'offering-name', selector: 'offering-name',
properties: { properties: [
'width': 'cell-width', 'width: cell-width',
'offering': 'offering' 'offering'
} ]
}) })
@View({ @View({
directives: [], directives: [],
@ -74,10 +74,10 @@ export class Stage {
@Component({ @Component({
selector: 'stage-buttons', selector: 'stage-buttons',
properties: { properties: [
'width': 'cell-width', 'width: cell-width',
'offering': 'offering' 'offering'
} ]
}) })
@View({ @View({
directives: [NgFor], directives: [NgFor],
@ -133,10 +133,10 @@ export class StageButtonsComponent extends HasStyle {
@Component({ @Component({
selector: 'account-cell', selector: 'account-cell',
properties: { properties: [
'width': 'cell-width', 'width: cell-width',
'account': 'account' 'account'
} ]
}) })
@View({ @View({
directives: [], directives: [],
@ -153,10 +153,10 @@ export class AccountCellComponent extends HasStyle {
@Component({ @Component({
selector: 'formatted-cell', selector: 'formatted-cell',
properties: { properties: [
'width': 'cell-width', 'width: cell-width',
'value': 'value' 'value'
} ]
}) })
@View({ @View({
directives: [], directives: [],

View File

@ -15,9 +15,9 @@ import {Offering, ITEM_HEIGHT, COMPANY_NAME_WIDTH, OPPORTUNITY_NAME_WIDTH,
@Component({ @Component({
selector: 'scroll-item', selector: 'scroll-item',
properties: { properties: [
'offering': 'offering' 'offering'
} ]
}) })
@View({ @View({
directives: [ directives: [

View File

@ -242,7 +242,7 @@ class AppComponent {
@Component({ @Component({
selector: 'tree', selector: 'tree',
properties: {'data': 'data'} properties: ['data']
}) })
@View({ @View({
directives: [TreeComponent, NgIf], directives: [TreeComponent, NgIf],

View File

@ -16,7 +16,7 @@ import {print} from 'angular2/src/facade/lang';
// <survey-header [header]="header"></survey-header> // <survey-header [header]="header"></survey-header>
// //
// This component is self-contained and can be tested in isolation. // This component is self-contained and can be tested in isolation.
@Component({selector: 'survey-header', properties: {"header": "header"}}) @Component({selector: 'survey-header', properties: ['header']})
@View({ @View({
template: ` template: `
<div [control-group]="header"> <div [control-group]="header">
@ -62,11 +62,7 @@ class HeaderFields {
// //
// SurveyQuestion uses EventEmitter to fire the delete action. // SurveyQuestion uses EventEmitter to fire the delete action.
// This component is self-contained and can be tested in isolation. // This component is self-contained and can be tested in isolation.
@Component({ @Component({selector: 'survey-question', events: ['destroy'], properties: ['question', 'index']})
selector: 'survey-question',
events: ['destroy'],
properties: {"question": "question", "index": "index"}
})
@View({ @View({
template: ` template: `
<h2>Question #{{index}}</h2> <h2>Question #{{index}}</h2>

View File

@ -62,7 +62,7 @@ class DemoApp {
@Component({ @Component({
selector: 'simple-dialog', selector: 'simple-dialog',
properties: {'numCoconuts': 'numCoconuts'} properties: ['numCoconuts']
}) })
@View({ @View({
template: ` template: `