@@ -46,22 +46,20 @@ function _find(control: AbstractControl, path: Array<string | number>| string) {
4646/**
4747 *
4848 */
49- export class AbstractControl {
49+ export abstract class AbstractControl {
5050 /** @internal */
5151 _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+
6253 /** @internal */
6354 _valueChanges : EventEmitter ;
6455
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+
6563 constructor ( public validator : Function ) { }
6664
6765 get value ( ) : any { return this . _value ; }
@@ -70,8 +68,16 @@ export class AbstractControl {
7068
7169 get valid ( ) : boolean { return this . _status === VALID ; }
7270
71+ /**
72+ * Returns the errors of this control.
73+ */
7374 get errors ( ) : { [ key : string ] : any } { return this . _errors ; }
7475
76+ /**
77+ * Returns the errors of the child controls.
78+ */
79+ get controlsErrors ( ) : any { return this . _controlsErrors ; }
80+
7581 get pristine ( ) : boolean { return this . _pristine ; }
7682
7783 get dirty ( ) : boolean { return ! this . pristine ; }
@@ -105,17 +111,6 @@ export class AbstractControl {
105111
106112 setParent ( parent : ControlGroup | ControlArray ) : void { this . _parent = parent ; }
107113
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-
119114 updateValueAndValidity ( { onlySelf, emitEvent} : { onlySelf ?: boolean , emitEvent ?: boolean } = { } ) :
120115 void {
121116 onlySelf = normalizeBool ( onlySelf ) ;
@@ -124,7 +119,8 @@ export class AbstractControl {
124119 this . _updateValue ( ) ;
125120
126121 this . _errors = this . validator ( this ) ;
127- this . _status = isPresent ( this . _errors ) ? INVALID : VALID ;
122+ this . _controlsErrors = this . _calculateControlsErrors ( ) ;
123+ this . _status = this . _calculateStatus ( ) ;
128124
129125 if ( emitEvent ) {
130126 ObservableWrapper . callNext ( this . _valueChanges , this . _value ) ;
@@ -135,6 +131,38 @@ export class AbstractControl {
135131 }
136132 }
137133
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+
138166 find ( path : Array < string | number > | string ) : AbstractControl { return _find ( this , path ) ; }
139167
140168 getError ( errorCode : string , path : string [ ] = null ) : any {
@@ -151,7 +179,23 @@ export class AbstractControl {
151179 }
152180
153181 /** @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 ;
155199}
156200
157201/**
@@ -177,7 +221,7 @@ export class Control extends AbstractControl {
177221 constructor ( value : any = null , validator : Function = Validators . nullValidator ) {
178222 super ( validator ) ;
179223 this . _value = value ;
180- this . updateValidity ( { onlySelf : true } ) ;
224+ this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
181225 this . _valueChanges = new EventEmitter ( ) ;
182226 }
183227
@@ -203,6 +247,16 @@ export class Control extends AbstractControl {
203247 this . updateValueAndValidity ( { onlySelf : onlySelf , emitEvent : emitEvent } ) ;
204248 }
205249
250+ /**
251+ * @internal
252+ */
253+ _updateValue ( ) { }
254+
255+ /**
256+ * @internal
257+ */
258+ _calculateControlsErrors ( ) { return null ; }
259+
206260 /**
207261 * Register a listener for change events.
208262 */
@@ -226,14 +280,14 @@ export class ControlGroup extends AbstractControl {
226280 private _optionals : { [ key : string ] : boolean } ;
227281
228282 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 ) {
230285 super ( validator ) ;
231286 this . _optionals = isPresent ( optionals ) ? optionals : { } ;
232287 this . _valueChanges = new EventEmitter ( ) ;
233288
234289 this . _setParentForControls ( ) ;
235- this . _value = this . _reduceValue ( ) ;
236- this . updateValidity ( { onlySelf : true } ) ;
290+ this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
237291 }
238292
239293 addControl ( name : string , control : AbstractControl ) : void {
@@ -266,6 +320,9 @@ export class ControlGroup extends AbstractControl {
266320 /** @internal */
267321 _updateValue ( ) { this . _value = this . _reduceValue ( ) ; }
268322
323+ /** @internal */
324+ _calculateControlsErrors ( ) { return Validators . group ( this ) ; }
325+
269326 /** @internal */
270327 _reduceValue ( ) {
271328 return this . _reduceChildren ( { } , ( acc , control , name ) => {
@@ -314,14 +371,13 @@ export class ControlGroup extends AbstractControl {
314371 * ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
315372 */
316373export class ControlArray extends AbstractControl {
317- constructor ( public controls : AbstractControl [ ] , validator : Function = Validators . array ) {
374+ constructor ( public controls : AbstractControl [ ] , validator : Function = Validators . nullValidator ) {
318375 super ( validator ) ;
319376
320377 this . _valueChanges = new EventEmitter ( ) ;
321378
322379 this . _setParentForControls ( ) ;
323- this . _updateValue ( ) ;
324- this . updateValidity ( { onlySelf : true } ) ;
380+ this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
325381 }
326382
327383 /**
@@ -363,6 +419,9 @@ export class ControlArray extends AbstractControl {
363419 /** @internal */
364420 _updateValue ( ) : void { this . _value = this . controls . map ( ( control ) => control . value ) ; }
365421
422+ /** @internal */
423+ _calculateControlsErrors ( ) { return Validators . array ( this ) ; }
424+
366425 /** @internal */
367426 _setParentForControls ( ) : void {
368427 this . controls . forEach ( ( control ) => { control . setParent ( this ) ; } ) ;
0 commit comments