Skip to content

Commit 30c3e5a

Browse files
committed
fix(forms): changed forms to create only one value accessor instead of always creating DefaultValueAccessor
1 parent 2ff3873 commit 30c3e5a

File tree

3 files changed

+102
-46
lines changed

3 files changed

+102
-46
lines changed

modules/angular2/src/forms/directives.ts

Lines changed: 83 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,6 @@ function _lookupControl(groupDirective: ControlGroupDirective, controlOrName: an
3232
return control;
3333
}
3434

35-
36-
/**
37-
* The default accessor for writing a value and listening to changes that is used by a {@link
38-
* Control} directive.
39-
*
40-
* This is the default strategy that Angular uses when no other accessor is applied.
41-
*
42-
* # Example
43-
* ```
44-
* <input type="text" [control]="loginControl">
45-
* ```
46-
*
47-
* @exportedAs angular2/forms
48-
*/
49-
@Directive({
50-
selector: '[control]',
51-
hostListeners:
52-
{'change': 'onChange($event.target.value)', 'input': 'onChange($event.target.value)'},
53-
hostProperties: {'value': 'value'}
54-
})
55-
export class DefaultValueAccessor {
56-
value;
57-
onChange: Function;
58-
59-
constructor() { this.onChange = (_) => {}; }
60-
61-
writeValue(value) { this.value = value }
62-
}
63-
6435
/**
6536
* Binds a control group to a DOM element.
6637
*
@@ -171,11 +142,9 @@ export class ControlDirective {
171142

172143
validator: Function;
173144

174-
constructor(@Optional() @Ancestor() groupDirective: ControlGroupDirective,
175-
valueAccessor: DefaultValueAccessor) {
145+
constructor(@Optional() @Ancestor() groupDirective: ControlGroupDirective) {
176146
this._groupDirective = groupDirective;
177147
this._controlOrName = null;
178-
this.valueAccessor = valueAccessor;
179148
this.validator = Validators.nullValidator;
180149
}
181150

@@ -189,6 +158,10 @@ export class ControlDirective {
189158
var c = this._control();
190159
c.validator = Validators.compose([c.validator, this.validator]);
191160

161+
if (isBlank(this.valueAccessor)) {
162+
throw new BaseException(`Cannot find value accessor for control "${controlOrName}"`);
163+
}
164+
192165
this._updateDomValue();
193166
this._setUpUpdateControlValue();
194167
}
@@ -202,6 +175,75 @@ export class ControlDirective {
202175
_control() { return _lookupControl(this._groupDirective, this._controlOrName); }
203176
}
204177

178+
/**
179+
* The default accessor for writing a value and listening to changes that is used by a {@link
180+
* Control} directive.
181+
*
182+
* This is the default strategy that Angular uses when no other accessor is applied.
183+
*
184+
* # Example
185+
* ```
186+
* <input type="text" [control]="loginControl">
187+
* ```
188+
*
189+
* @exportedAs angular2/forms
190+
*/
191+
@Directive({
192+
selector: 'input:not([type=checkbox])[control],textarea[control]',
193+
hostListeners:
194+
{'change': 'onChange($event.target.value)', 'input': 'onChange($event.target.value)'},
195+
hostProperties: {'value': 'value'}
196+
})
197+
export class DefaultValueAccessor {
198+
value = null;
199+
onChange: Function;
200+
201+
constructor(cd: ControlDirective, private _elementRef: ElementRef, private _renderer: Renderer) {
202+
this.onChange = (_) => {};
203+
cd.valueAccessor = this;
204+
}
205+
206+
writeValue(value) {
207+
this._renderer.setElementProperty(this._elementRef.parentView.render,
208+
this._elementRef.boundElementIndex, 'value', value)
209+
}
210+
}
211+
212+
/**
213+
* The accessor for writing a value and listening to changes that is used by a {@link
214+
* Control} directive.
215+
*
216+
* This is the default strategy that Angular uses when no other accessor is applied.
217+
*
218+
* # Example
219+
* ```
220+
* <input type="text" [control]="loginControl">
221+
* ```
222+
*
223+
* @exportedAs angular2/forms
224+
*/
225+
@Directive({
226+
selector: 'select[control]',
227+
hostListeners:
228+
{'change': 'onChange($event.target.value)', 'input': 'onChange($event.target.value)'},
229+
hostProperties: {'value': 'value'}
230+
})
231+
export class SelectControlValueAccessor {
232+
value = null;
233+
onChange: Function;
234+
235+
constructor(cd: ControlDirective, private _elementRef: ElementRef, private _renderer: Renderer) {
236+
this.onChange = (_) => {};
237+
this.value = '';
238+
cd.valueAccessor = this;
239+
}
240+
241+
writeValue(value) {
242+
this._renderer.setElementProperty(this._elementRef.parentView.render,
243+
this._elementRef.boundElementIndex, 'value', value)
244+
}
245+
}
246+
205247
/**
206248
* The accessor for writing a value and listening to changes on a checkbox input element.
207249
*
@@ -219,17 +261,12 @@ export class ControlDirective {
219261
hostProperties: {'checked': 'checked'}
220262
})
221263
export class CheckboxControlValueAccessor {
222-
_elementRef: ElementRef;
223-
_renderer: Renderer;
224-
225264
checked: boolean;
226265
onChange: Function;
227266

228-
constructor(cd: ControlDirective, elementRef: ElementRef, renderer: Renderer) {
267+
constructor(cd: ControlDirective, private _elementRef: ElementRef, private _renderer: Renderer) {
229268
this.onChange = (_) => {};
230-
this._elementRef = elementRef;
231-
this._renderer = renderer;
232-
cd.valueAccessor = this; // ControlDirective should inject CheckboxControlDirective
269+
cd.valueAccessor = this;
233270
}
234271

235272
writeValue(value) {
@@ -246,5 +283,10 @@ export class CheckboxControlValueAccessor {
246283
*
247284
* @exportedAs angular2/forms
248285
*/
249-
export const formDirectives: List<Type> = CONST_EXPR(
250-
[ControlGroupDirective, ControlDirective, CheckboxControlValueAccessor, DefaultValueAccessor]);
286+
export const formDirectives: List<Type> = CONST_EXPR([
287+
ControlGroupDirective,
288+
ControlDirective,
289+
CheckboxControlValueAccessor,
290+
DefaultValueAccessor,
291+
SelectControlValueAccessor
292+
]);

modules/angular2/test/forms/directives_spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function main() {
66
describe("Form Directives", () => {
77
describe("Control", () => {
88
it("should throw when the group is not found and the control is not set", () => {
9-
var c = new ControlDirective(null, null);
9+
var c = new ControlDirective(null);
1010
expect(() => {
1111
c.controlOrName = 'login';
1212
}).toThrowError(new RegExp('No control group found for "login"'));
@@ -16,7 +16,7 @@ export function main() {
1616
var emptyGroup = new ControlGroupDirective(null);
1717
emptyGroup.controlOrName = new ControlGroup({});
1818

19-
var c = new ControlDirective(emptyGroup, null);
19+
var c = new ControlDirective(emptyGroup);
2020
expect(() => {
2121
c.controlOrName = 'login';
2222
}).toThrowError(new RegExp('Cannot find control "login"'));

modules/angular2/test/forms/integration_spec.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ import {View} from 'angular2/src/core/annotations_impl/view';
2121

2222
import {TestBed} from 'angular2/src/test_lib/test_bed';
2323

24-
import {ControlGroupDirective, ControlDirective, Control, ControlGroup, RequiredValidatorDirective, CheckboxControlValueAccessor,
25-
DefaultValueAccessor, Validators} from 'angular2/forms';
24+
import {ControlGroupDirective, ControlDirective, Control, ControlGroup, RequiredValidatorDirective, CheckboxControlValueAccessor, DefaultValueAccessor, SelectControlValueAccessor, Validators} from 'angular2/forms';
2625

2726
export function main() {
2827
describe("integration tests", () => {
@@ -266,6 +265,19 @@ export function main() {
266265
async.done();
267266
});
268267
}));
268+
269+
it("should throw when cannot find a value accessor", inject([TestBed, AsyncTestCompleter], (tb, async) => {
270+
var ctx = new MyComp(new ControlGroup({"name": new Control("aa")}));
271+
272+
var t = `<div [control-group]="form">
273+
<div control="name">
274+
</div>`;
275+
276+
tb.createView(MyComp, {context: ctx, html: t}).then((view) => {
277+
expect(() => view.detectChanges()).toThrowError(new RegExp("Cannot find value accessor"))
278+
async.done();
279+
});
280+
}));
269281
});
270282

271283
describe("validations", () => {
@@ -377,7 +389,9 @@ export function main() {
377389
WrappedValue,
378390
RequiredValidatorDirective,
379391
DefaultValueAccessor,
380-
CheckboxControlValueAccessor]})
392+
CheckboxControlValueAccessor,
393+
SelectControlValueAccessor
394+
]})
381395
class MyComp {
382396
form:any;
383397
name:string;

0 commit comments

Comments
 (0)