@@ -46,22 +46,20 @@ function _find(control: AbstractControl, path: Array<string | number>| string) {
46
46
/**
47
47
*
48
48
*/
49
- export class AbstractControl {
49
+ export abstract class AbstractControl {
50
50
/** @internal */
51
51
_value : any ;
52
- /** @internal */
53
- _status : string ;
54
- /** @internal */
55
- _errors : { [ key : string ] : any } ;
56
- /** @internal */
57
- _pristine : boolean = true ;
58
- /** @internal */
59
- _touched : boolean = false ;
60
- /** @internal */
61
- _parent : ControlGroup | ControlArray ;
52
+
62
53
/** @internal */
63
54
_valueChanges : EventEmitter ;
64
55
56
+ private _status : string ;
57
+ private _errors : { [ key : string ] : any } ;
58
+ private _controlsErrors : any ;
59
+ private _pristine : boolean = true ;
60
+ private _touched : boolean = false ;
61
+ private _parent : ControlGroup | ControlArray ;
62
+
65
63
constructor ( public validator : Function ) { }
66
64
67
65
get value ( ) : any { return this . _value ; }
@@ -70,8 +68,16 @@ export class AbstractControl {
70
68
71
69
get valid ( ) : boolean { return this . _status === VALID ; }
72
70
71
+ /**
72
+ * Returns the errors of this control.
73
+ */
73
74
get errors ( ) : { [ key : string ] : any } { return this . _errors ; }
74
75
76
+ /**
77
+ * Returns the errors of the child controls.
78
+ */
79
+ get controlsErrors ( ) : any { return this . _controlsErrors ; }
80
+
75
81
get pristine ( ) : boolean { return this . _pristine ; }
76
82
77
83
get dirty ( ) : boolean { return ! this . pristine ; }
@@ -105,17 +111,6 @@ export class AbstractControl {
105
111
106
112
setParent ( parent : ControlGroup | ControlArray ) : void { this . _parent = parent ; }
107
113
108
- updateValidity ( { onlySelf} : { onlySelf ?: boolean } = { } ) : void {
109
- onlySelf = normalizeBool ( onlySelf ) ;
110
-
111
- this . _errors = this . validator ( this ) ;
112
- this . _status = isPresent ( this . _errors ) ? INVALID : VALID ;
113
-
114
- if ( isPresent ( this . _parent ) && ! onlySelf ) {
115
- this . _parent . updateValidity ( { onlySelf : onlySelf } ) ;
116
- }
117
- }
118
-
119
114
updateValueAndValidity ( { onlySelf, emitEvent} : { onlySelf ?: boolean , emitEvent ?: boolean } = { } ) :
120
115
void {
121
116
onlySelf = normalizeBool ( onlySelf ) ;
@@ -124,7 +119,8 @@ export class AbstractControl {
124
119
this . _updateValue ( ) ;
125
120
126
121
this . _errors = this . validator ( this ) ;
127
- this . _status = isPresent ( this . _errors ) ? INVALID : VALID ;
122
+ this . _controlsErrors = this . _calculateControlsErrors ( ) ;
123
+ this . _status = this . _calculateStatus ( ) ;
128
124
129
125
if ( emitEvent ) {
130
126
ObservableWrapper . callNext ( this . _valueChanges , this . _value ) ;
@@ -135,6 +131,38 @@ export class AbstractControl {
135
131
}
136
132
}
137
133
134
+ /**
135
+ * Sets errors on a control.
136
+ *
137
+ * This is used when validations are run not automatically, but manually by the user.
138
+ *
139
+ * Calling `setErrors` will also update the validity of the parent control.
140
+ *
141
+ * ## Usage
142
+ *
143
+ * ```
144
+ * var login = new Control("someLogin");
145
+ * login.setErrors({
146
+ * "notUnique": true
147
+ * });
148
+ *
149
+ * expect(login.valid).toEqual(false);
150
+ * expect(login.errors).toEqual({"notUnique": true});
151
+ *
152
+ * login.updateValue("someOtherLogin");
153
+ *
154
+ * expect(login.valid).toEqual(true);
155
+ * ```
156
+ */
157
+ setErrors ( errors : { [ key : string ] : any } ) : void {
158
+ this . _errors = errors ;
159
+ this . _status = this . _calculateStatus ( ) ;
160
+
161
+ if ( isPresent ( this . _parent ) ) {
162
+ this . _parent . _updateControlsErrors ( ) ;
163
+ }
164
+ }
165
+
138
166
find ( path : Array < string | number > | string ) : AbstractControl { return _find ( this , path ) ; }
139
167
140
168
getError ( errorCode : string , path : string [ ] = null ) : any {
@@ -151,7 +179,23 @@ export class AbstractControl {
151
179
}
152
180
153
181
/** @internal */
154
- _updateValue ( ) : void { }
182
+ _updateControlsErrors ( ) : void {
183
+ this . _controlsErrors = this . _calculateControlsErrors ( ) ;
184
+ this . _status = this . _calculateStatus ( ) ;
185
+
186
+ if ( isPresent ( this . _parent ) ) {
187
+ this . _parent . _updateControlsErrors ( ) ;
188
+ }
189
+ }
190
+
191
+ private _calculateStatus ( ) : string {
192
+ return isPresent ( this . _errors ) || isPresent ( this . _controlsErrors ) ? INVALID : VALID ;
193
+ }
194
+
195
+ /** @internal */
196
+ abstract _updateValue ( ) : void ;
197
+ /** @internal */
198
+ abstract _calculateControlsErrors ( ) : any ;
155
199
}
156
200
157
201
/**
@@ -177,7 +221,7 @@ export class Control extends AbstractControl {
177
221
constructor ( value : any = null , validator : Function = Validators . nullValidator ) {
178
222
super ( validator ) ;
179
223
this . _value = value ;
180
- this . updateValidity ( { onlySelf : true } ) ;
224
+ this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
181
225
this . _valueChanges = new EventEmitter ( ) ;
182
226
}
183
227
@@ -203,6 +247,16 @@ export class Control extends AbstractControl {
203
247
this . updateValueAndValidity ( { onlySelf : onlySelf , emitEvent : emitEvent } ) ;
204
248
}
205
249
250
+ /**
251
+ * @internal
252
+ */
253
+ _updateValue ( ) { }
254
+
255
+ /**
256
+ * @internal
257
+ */
258
+ _calculateControlsErrors ( ) { return null ; }
259
+
206
260
/**
207
261
* Register a listener for change events.
208
262
*/
@@ -226,14 +280,14 @@ export class ControlGroup extends AbstractControl {
226
280
private _optionals : { [ key : string ] : boolean } ;
227
281
228
282
constructor ( public controls : { [ key : string ] : AbstractControl } ,
229
- optionals : { [ key : string ] : boolean } = null , validator : Function = Validators . group ) {
283
+ optionals : { [ key : string ] : boolean } = null ,
284
+ validator : Function = Validators . nullValidator ) {
230
285
super ( validator ) ;
231
286
this . _optionals = isPresent ( optionals ) ? optionals : { } ;
232
287
this . _valueChanges = new EventEmitter ( ) ;
233
288
234
289
this . _setParentForControls ( ) ;
235
- this . _value = this . _reduceValue ( ) ;
236
- this . updateValidity ( { onlySelf : true } ) ;
290
+ this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
237
291
}
238
292
239
293
addControl ( name : string , control : AbstractControl ) : void {
@@ -266,6 +320,9 @@ export class ControlGroup extends AbstractControl {
266
320
/** @internal */
267
321
_updateValue ( ) { this . _value = this . _reduceValue ( ) ; }
268
322
323
+ /** @internal */
324
+ _calculateControlsErrors ( ) { return Validators . group ( this ) ; }
325
+
269
326
/** @internal */
270
327
_reduceValue ( ) {
271
328
return this . _reduceChildren ( { } , ( acc , control , name ) => {
@@ -314,14 +371,13 @@ export class ControlGroup extends AbstractControl {
314
371
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
315
372
*/
316
373
export class ControlArray extends AbstractControl {
317
- constructor ( public controls : AbstractControl [ ] , validator : Function = Validators . array ) {
374
+ constructor ( public controls : AbstractControl [ ] , validator : Function = Validators . nullValidator ) {
318
375
super ( validator ) ;
319
376
320
377
this . _valueChanges = new EventEmitter ( ) ;
321
378
322
379
this . _setParentForControls ( ) ;
323
- this . _updateValue ( ) ;
324
- this . updateValidity ( { onlySelf : true } ) ;
380
+ this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
325
381
}
326
382
327
383
/**
@@ -363,6 +419,9 @@ export class ControlArray extends AbstractControl {
363
419
/** @internal */
364
420
_updateValue ( ) : void { this . _value = this . controls . map ( ( control ) => control . value ) ; }
365
421
422
+ /** @internal */
423
+ _calculateControlsErrors ( ) { return Validators . array ( this ) ; }
424
+
366
425
/** @internal */
367
426
_setParentForControls ( ) : void {
368
427
this . controls . forEach ( ( control ) => { control . setParent ( this ) ; } ) ;
0 commit comments