From 514529b5d921d9df27ca5dffa41bc6961c366fd1 Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 19 Mar 2015 13:12:16 -0700 Subject: [PATCH] refactor(formed): changed forms to use event and property setters instead of NgElement --- modules/angular2/core.js | 1 + modules/angular2/src/forms/directives.js | 101 ++++++++---------- .../angular2/test/forms/integration_spec.js | 59 +++++++--- 3 files changed, 90 insertions(+), 71 deletions(-) diff --git a/modules/angular2/core.js b/modules/angular2/core.js index db2da0c6f8..639df4aa46 100644 --- a/modules/angular2/core.js +++ b/modules/angular2/core.js @@ -2,6 +2,7 @@ export * from './src/core/annotations/visibility'; export * from './src/core/compiler/interfaces'; export * from './src/core/annotations/template'; export * from './src/core/application'; +export * from './src/core/annotations/di'; export * from './src/core/compiler/compiler'; diff --git a/modules/angular2/src/forms/directives.js b/modules/angular2/src/forms/directives.js index e3d848d33e..c937f57b97 100644 --- a/modules/angular2/src/forms/directives.js +++ b/modules/angular2/src/forms/directives.js @@ -1,4 +1,4 @@ -import {Template, Component, Decorator, NgElement, Ancestor, onChange} from 'angular2/angular2'; +import {Template, Component, Decorator, Ancestor, onChange, PropertySetter} from 'angular2/angular2'; import {Optional} from 'angular2/di'; import {DOM} from 'angular2/src/dom/dom_adapter'; import {isBlank, isPresent, isString, CONST} from 'angular2/src/facade/lang'; @@ -6,53 +6,50 @@ import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {ControlGroup, Control} from './model'; import {Validators} from './validators'; -@CONST() export class ControlValueAccessor { - readValue(el){} - writeValue(el, value):void {} + writeValue(value):void{} + set onChange(fn){} } -@CONST() -class DefaultControlValueAccessor extends ControlValueAccessor { - constructor() { - super(); +@Decorator({ + selector: '[control]', + events: { + 'change' : 'onChange($event.target.value)' + } +}) +export class DefaultControlDecorator extends ControlValueAccessor { + _setValueProperty:Function; + onChange:Function; + + constructor(@PropertySetter('value') setValueProperty:Function) { + this._setValueProperty = setValueProperty; + this.onChange = (_) => {}; } - readValue(el) { - return DOM.getValue(el); - } - - writeValue(el, value):void { - DOM.setValue(el,value); + writeValue(value) { + this._setValueProperty(value); } } -@CONST() -class CheckboxControlValueAccessor extends ControlValueAccessor { - constructor() { - super(); +@Decorator({ + selector: 'input[type=checkbox]', //should be input[type=checkbox][control] + events: { + 'change' : 'onChange($event.target.checked)' + } +}) +export class CheckboxControlDecorator extends ControlValueAccessor { + _setCheckedProperty:Function; + onChange:Function; + + constructor(cd:ControlDirective, @PropertySetter('checked') setCheckedProperty:Function) { + this._setCheckedProperty = setCheckedProperty; + this.onChange = (_) => {}; + //TODO: vsavkin ControlDirective should inject CheckboxControlDirective + cd.valueAccessor = this; } - readValue(el):boolean { - return DOM.getChecked(el); - } - - writeValue(el, value:boolean):void { - DOM.setChecked(el, value); - } -} - -var controlValueAccessors = { - "checkbox" : new CheckboxControlValueAccessor(), - "text" : new DefaultControlValueAccessor() -}; - -function controlValueAccessorFor(controlType:string):ControlValueAccessor { - var accessor = StringMapWrapper.get(controlValueAccessors, controlType); - if (isPresent(accessor)) { - return accessor; - } else { - return StringMapWrapper.get(controlValueAccessors, "text"); + writeValue(value) { + this._setCheckedProperty(value); } } @@ -60,25 +57,21 @@ function controlValueAccessorFor(controlType:string):ControlValueAccessor { lifecycle: [onChange], selector: '[control]', bind: { - 'controlName' : 'control', - 'type' : 'type' + 'controlName' : 'control' } }) export class ControlDirective { _groupDirective:ControlGroupDirective; - _el:NgElement; controlName:string; - type:string; valueAccessor:ControlValueAccessor; validator:Function; - constructor(@Ancestor() groupDirective:ControlGroupDirective, el:NgElement) { + constructor(@Ancestor() groupDirective:ControlGroupDirective, valueAccessor:DefaultControlDecorator) { this._groupDirective = groupDirective; - this._el = el; this.controlName = null; - this.type = null; + this.valueAccessor = valueAccessor; this.validator = Validators.nullValidator; } @@ -94,20 +87,20 @@ export class ControlDirective { var c = this._control(); c.validator = Validators.compose([c.validator, this.validator]); - if (isBlank(this.valueAccessor)) { - this.valueAccessor = controlValueAccessorFor(this.type); - } - this._updateDomValue(); - DOM.on(this._el.domElement, "change", (_) => this._updateControlValue()); + this._setUpUpdateControlValue(); } _updateDomValue() { - this.valueAccessor.writeValue(this._el.domElement, this._control().value); + this.valueAccessor.writeValue(this._control().value); } - _updateControlValue() { - this._control().updateValue(this.valueAccessor.readValue(this._el.domElement)); + _setUpUpdateControlValue() { + this.valueAccessor.onChange = (newValue) => this._control().updateValue(newValue); + } + + _updateControlValue(newValue) { + this._control().updateValue(newValue); } _control() { @@ -165,5 +158,5 @@ export class ControlGroupDirective { } export var FormDirectives = [ - ControlGroupDirective, ControlDirective + ControlGroupDirective, ControlDirective, CheckboxControlDecorator, DefaultControlDecorator ]; diff --git a/modules/angular2/test/forms/integration_spec.js b/modules/angular2/test/forms/integration_spec.js index 826525e033..b040830fb5 100644 --- a/modules/angular2/test/forms/integration_spec.js +++ b/modules/angular2/test/forms/integration_spec.js @@ -24,14 +24,17 @@ import {ComponentUrlMapper} from 'angular2/src/core/compiler/component_url_mappe import {UrlResolver} from 'angular2/src/core/compiler/url_resolver'; import {StyleUrlResolver} from 'angular2/src/core/compiler/style_url_resolver'; import {CssProcessor} from 'angular2/src/core/compiler/css_processor'; +import {EventManager, DomEventsPlugin} from 'angular2/src/core/events/event_manager'; +import {VmTurnZone} from 'angular2/src/core/zone/vm_turn_zone'; import {MockTemplateResolver} from 'angular2/src/mock/template_resolver_mock'; import {Injector} from 'angular2/di'; -import {Component, Decorator, Template} from 'angular2/angular2'; +import {Component, Decorator, Template, PropertySetter} from 'angular2/angular2'; import {ControlGroupDirective, ControlDirective, Control, ControlGroup, OptionalControl, - ControlValueAccessor, RequiredValidatorDirective, Validators} from 'angular2/forms'; + ControlValueAccessor, RequiredValidatorDirective, CheckboxControlDecorator, + DefaultControlDecorator, Validators} from 'angular2/forms'; export function main() { function detectChanges(view) { @@ -56,11 +59,13 @@ export function main() { tplResolver.setTemplate(componentType, new Template({ inline: template, - directives: [ControlGroupDirective, ControlDirective, WrappedValue, RequiredValidatorDirective] + directives: [ControlGroupDirective, ControlDirective, WrappedValue, RequiredValidatorDirective, + CheckboxControlDecorator, DefaultControlDecorator] })); compiler.compile(componentType).then((pv) => { - var view = pv.instantiate(null, null); + var eventManager = new EventManager([new DomEventsPlugin()], new FakeVmTurnZone()); + var view = pv.instantiate(null, eventManager); view.hydrate(new Injector([]), null, null, context, null); detectChanges(view); callback(view); @@ -346,21 +351,41 @@ class MyComp { } } -class WrappedValueAccessor extends ControlValueAccessor { - readValue(el){ - return el.value.substring(1, el.value.length - 1); - } - - writeValue(el, value):void { - el.value = `!${value}!`; - } -} @Decorator({ - selector:'[wrapped-value]' + selector:'[wrapped-value]', + events: { + 'change' : 'handleOnChange($event.target.value)' + } }) -class WrappedValue { - constructor(cd:ControlDirective) { - cd.valueAccessor = new WrappedValueAccessor(); +class WrappedValue extends ControlValueAccessor { + _setProperty:Function; + onChange:Function; + + constructor(cd:ControlDirective, @PropertySetter('value') setProperty:Function) { + this._setProperty = setProperty; + cd.valueAccessor = this; + } + + writeValue(value) { + this._setProperty(`!${value}!`); + } + + handleOnChange(value) { + this.onChange(value.substring(1, value.length - 1)); } } + +class FakeVmTurnZone extends VmTurnZone { + constructor() { + super({enableLongStackTrace: false}); + } + + run(fn) { + fn(); + } + + runOutsideAngular(fn) { + fn(); + } +} \ No newline at end of file