From 47c1a0f3814c888509f2e653d57b33727046103d Mon Sep 17 00:00:00 2001 From: vsavkin Date: Thu, 19 Mar 2015 14:01:11 -0700 Subject: [PATCH] feat(forms): added value accessor for input=text --- modules/angular2/src/forms/directives.js | 32 ++- .../angular2/test/forms/integration_spec.js | 223 ++++++++++-------- 2 files changed, 144 insertions(+), 111 deletions(-) diff --git a/modules/angular2/src/forms/directives.js b/modules/angular2/src/forms/directives.js index c937f57b97..f0f7aba1e4 100644 --- a/modules/angular2/src/forms/directives.js +++ b/modules/angular2/src/forms/directives.js @@ -1,27 +1,28 @@ 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'; import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; import {ControlGroup, Control} from './model'; import {Validators} from './validators'; -export class ControlValueAccessor { - writeValue(value):void{} - set onChange(fn){} -} +//export interface ControlValueAccessor { +// writeValue(value):void{} +// set onChange(fn){} +//} @Decorator({ selector: '[control]', events: { - 'change' : 'onChange($event.target.value)' + 'change' : 'onChange($event.target.value)', + 'input' : 'onChange($event.target.value)' } }) -export class DefaultControlDecorator extends ControlValueAccessor { +export class DefaultValueAccessor { _setValueProperty:Function; onChange:Function; constructor(@PropertySetter('value') setValueProperty:Function) { + super(); this._setValueProperty = setValueProperty; this.onChange = (_) => {}; } @@ -33,19 +34,20 @@ export class DefaultControlDecorator extends ControlValueAccessor { @Decorator({ selector: 'input[type=checkbox]', //should be input[type=checkbox][control] + // change the selector once https://github.com/angular/angular/issues/1025 is fixed events: { 'change' : 'onChange($event.target.checked)' } }) -export class CheckboxControlDecorator extends ControlValueAccessor { +export class CheckboxControlValueAccessor { _setCheckedProperty:Function; onChange:Function; constructor(cd:ControlDirective, @PropertySetter('checked') setCheckedProperty:Function) { + super(); this._setCheckedProperty = setCheckedProperty; this.onChange = (_) => {}; - //TODO: vsavkin ControlDirective should inject CheckboxControlDirective - cd.valueAccessor = this; + cd.valueAccessor = this; //ControlDirective should inject CheckboxControlDirective } writeValue(value) { @@ -64,11 +66,11 @@ export class ControlDirective { _groupDirective:ControlGroupDirective; controlName:string; - valueAccessor:ControlValueAccessor; + valueAccessor:any; //ControlValueAccessor validator:Function; - constructor(@Ancestor() groupDirective:ControlGroupDirective, valueAccessor:DefaultControlDecorator) { + constructor(@Ancestor() groupDirective:ControlGroupDirective, valueAccessor:DefaultValueAccessor) { this._groupDirective = groupDirective; this.controlName = null; this.valueAccessor = valueAccessor; @@ -99,10 +101,6 @@ export class ControlDirective { this.valueAccessor.onChange = (newValue) => this._control().updateValue(newValue); } - _updateControlValue(newValue) { - this._control().updateValue(newValue); - } - _control() { return this._groupDirective.findControl(this.controlName); } @@ -158,5 +156,5 @@ export class ControlGroupDirective { } export var FormDirectives = [ - ControlGroupDirective, ControlDirective, CheckboxControlDecorator, DefaultControlDecorator + ControlGroupDirective, ControlDirective, CheckboxControlValueAccessor, DefaultValueAccessor ]; diff --git a/modules/angular2/test/forms/integration_spec.js b/modules/angular2/test/forms/integration_spec.js index b040830fb5..f078b0c883 100644 --- a/modules/angular2/test/forms/integration_spec.js +++ b/modules/angular2/test/forms/integration_spec.js @@ -33,8 +33,8 @@ import {Injector} from 'angular2/di'; import {Component, Decorator, Template, PropertySetter} from 'angular2/angular2'; import {ControlGroupDirective, ControlDirective, Control, ControlGroup, OptionalControl, - ControlValueAccessor, RequiredValidatorDirective, CheckboxControlDecorator, - DefaultControlDecorator, Validators} from 'angular2/forms'; + ControlValueAccessor, RequiredValidatorDirective, CheckboxControlValueAccessor, + DefaultValueAccessor, Validators} from 'angular2/forms'; export function main() { function detectChanges(view) { @@ -60,7 +60,7 @@ export function main() { tplResolver.setTemplate(componentType, new Template({ inline: template, directives: [ControlGroupDirective, ControlDirective, WrappedValue, RequiredValidatorDirective, - CheckboxControlDecorator, DefaultControlDecorator] + CheckboxControlValueAccessor, DefaultValueAccessor] })); compiler.compile(componentType).then((pv) => { @@ -72,24 +72,24 @@ export function main() { }); } - describe("integration tests", () => { - it("should initialize DOM elements with the given form object", inject([AsyncTestCompleter], (async) => { - var ctx = new MyComp(new ControlGroup({ - "login": new Control("loginValue") - })); + if (DOM.supportsDOMEvents()) { + describe("integration tests", () => { + it("should initialize DOM elements with the given form object", inject([AsyncTestCompleter], (async) => { + var ctx = new MyComp(new ControlGroup({ + "login": new Control("loginValue") + })); - var t = `
+ var t = `
`; - compile(MyComp, t, ctx, (view) => { - var input = queryView(view, "input") - expect(input.value).toEqual("loginValue"); - async.done(); - }); - })); + compile(MyComp, t, ctx, (view) => { + var input = queryView(view, "input") + expect(input.value).toEqual("loginValue"); + async.done(); + }); + })); - if (DOM.supportsDOMEvents()) { it("should update the control group values on DOM change", inject([AsyncTestCompleter], (async) => { var form = new ControlGroup({ "login": new Control("oldValue") @@ -110,55 +110,110 @@ export function main() { async.done(); }); })); - } - it("should update DOM elements when rebinding the control group", inject([AsyncTestCompleter], (async) => { - var form = new ControlGroup({ - "login": new Control("oldValue") - }); - var ctx = new MyComp(form); + it("should update DOM elements when rebinding the control group", inject([AsyncTestCompleter], (async) => { + var form = new ControlGroup({ + "login": new Control("oldValue") + }); + var ctx = new MyComp(form); - var t = `
+ var t = `
`; - compile(MyComp, t, ctx, (view) => { - ctx.form = new ControlGroup({ - "login": new Control("newValue") + compile(MyComp, t, ctx, (view) => { + ctx.form = new ControlGroup({ + "login": new Control("newValue") + }); + detectChanges(view); + + var input = queryView(view, "input") + expect(input.value).toEqual("newValue"); + async.done(); }); - detectChanges(view); + })); - var input = queryView(view, "input") - expect(input.value).toEqual("newValue"); - async.done(); - }); - })); + it("should update DOM element when rebinding the control name", inject([AsyncTestCompleter], (async) => { + var ctx = new MyComp(new ControlGroup({ + "one": new Control("one"), + "two": new Control("two") + }), "one"); - it("should update DOM element when rebinding the control name", inject([AsyncTestCompleter], (async) => { - var ctx = new MyComp(new ControlGroup({ - "one": new Control("one"), - "two": new Control("two") - }), "one"); - - var t = `
+ var t = `
`; - compile(MyComp, t, ctx, (view) => { - var input = queryView(view, "input") - expect(input.value).toEqual("one"); + compile(MyComp, t, ctx, (view) => { + var input = queryView(view, "input") + expect(input.value).toEqual("one"); - ctx.name = "two"; - detectChanges(view); + ctx.name = "two"; + detectChanges(view); - expect(input.value).toEqual("two"); - async.done(); - }); - })); + expect(input.value).toEqual("two"); + async.done(); + }); + })); - if (DOM.supportsDOMEvents()) { describe("different control types", () => { - it("should support type=checkbox", inject([AsyncTestCompleter], (async) => { + it("should support ", inject([AsyncTestCompleter], (async) => { + var ctx = new MyComp(new ControlGroup({"text": new Control("old")})); + + var t = `
+ +
`; + + compile(MyComp, t, ctx, (view) => { + var input = queryView(view, "input") + expect(input.value).toEqual("old"); + + input.value = "new"; + dispatchEvent(input, "input"); + + expect(ctx.form.value).toEqual({"text": "new"}); + async.done(); + }); + })); + + it("should support without type", inject([AsyncTestCompleter], (async) => { + var ctx = new MyComp(new ControlGroup({"text": new Control("old")})); + + var t = `
+ +
`; + + compile(MyComp, t, ctx, (view) => { + var input = queryView(view, "input") + expect(input.value).toEqual("old"); + + input.value = "new"; + dispatchEvent(input, "input"); + + expect(ctx.form.value).toEqual({"text": "new"}); + async.done(); + }); + })); + + it("should support +
`; + + compile(MyComp, t, ctx, (view) => { + var textarea = queryView(view, "textarea") + expect(textarea.value).toEqual("old"); + + textarea.value = "new"; + dispatchEvent(textarea, "input"); + + expect(ctx.form.value).toEqual({"text": 'new'}); + async.done(); + }); + })); + + it("should support ", inject([AsyncTestCompleter], (async) => { var ctx = new MyComp(new ControlGroup({"checkbox": new Control(true)})); var t = `
@@ -172,31 +227,12 @@ export function main() { input.checked = false; dispatchEvent(input, "change"); - expect(ctx.form.value).toEqual({"checkbox" : false}); + expect(ctx.form.value).toEqual({"checkbox": false}); async.done(); }); })); - it("should support textarea", inject([AsyncTestCompleter], (async) => { - var ctx = new MyComp(new ControlGroup({"text": new Control('old')})); - - var t = `
- -
`; - - compile(MyComp, t, ctx, (view) => { - var textarea = queryView(view, "textarea") - expect(textarea.value).toEqual("old"); - - textarea.value = "new"; - dispatchEvent(textarea, "change"); - - expect(ctx.form.value).toEqual({"text" : 'new'}); - async.done(); - }); - })); - - it("should support select", inject([AsyncTestCompleter], (async) => { + it("should support
`; - compile(MyComp, t, ctx, (view) => { - var input = queryView(view, "input") - expect(input.value).toEqual("value"); - async.done(); - }); - })); + compile(MyComp, t, ctx, (view) => { + var input = queryView(view, "input") + expect(input.value).toEqual("value"); + async.done(); + }); + })); - if (DOM.supportsDOMEvents()) { it("should update the control group values on DOM change", inject([AsyncTestCompleter], (async) => { var form = new ControlGroup({ "nested": new ControlGroup({ @@ -329,13 +363,13 @@ export function main() { input.value = "updatedValue"; dispatchEvent(input, "change"); - expect(form.value).toEqual({"nested" : {"login" : "updatedValue"}}); + expect(form.value).toEqual({"nested": {"login": "updatedValue"}}); async.done(); }); })); - } + }); }); - }); + } } @Component({ @@ -358,11 +392,12 @@ class MyComp { 'change' : 'handleOnChange($event.target.value)' } }) -class WrappedValue extends ControlValueAccessor { +class WrappedValue { _setProperty:Function; onChange:Function; constructor(cd:ControlDirective, @PropertySetter('value') setProperty:Function) { + super(); this._setProperty = setProperty; cd.valueAccessor = this; }