@@ -153,6 +153,7 @@ export class AbstractControl {
153153 * a `blur` event on it.
154154 */
155155 this . touched = false ;
156+ this . submitted = false ;
156157 /**
157158 * A control is `pristine` if the user has not yet changed
158159 * the value in the UI.
@@ -300,13 +301,13 @@ export class AbstractControl {
300301 updateValueAndValidity ( options = { } ) {
301302 this . setInitialStatus ( ) ;
302303 this . _updateValue ( ) ;
303- const shouldValidate = this . enabled && ( this . updateOn === "change " || options . validate ) ;
304+ const shouldValidate = this . enabled && ( this . updateOn !== "submit " || this . submitted ) ;
304305 if ( shouldValidate ) {
305306 this . _cancelExistingSubscription ( ) ;
306307 this . errors = this . _runValidator ( ) ;
307308 this . status = this . _calculateStatus ( ) ;
308309 if ( this . status === VALID || this . status === PENDING ) {
309- this . _runAsyncValidator ( options . emitEvent ) ;
310+ this . _runAsyncValidator ( true ) ;
310311 }
311312 }
312313 if ( options . emitEvent !== false ) {
@@ -332,6 +333,39 @@ export class AbstractControl {
332333 this . _parent . markAsTouched ( opts ) ;
333334 }
334335 }
336+ /**
337+ * Marks the control as `submitted`.
338+ *
339+ * If the control has any children, it will also mark all children as `submitted`
340+ * @param {{emitEvent: Boolean} } opts
341+ * @return {void }
342+ */
343+ markAsSubmitted ( opts = { } ) {
344+ this . submitted = true ;
345+
346+ this . _forEachChild ( ( control ) => { control . markAsSubmitted ( ) ; } ) ;
347+
348+ if ( opts . emitEvent !== false ) {
349+ this . stateChanges . next ( ) ;
350+ }
351+ }
352+ /**
353+ * Marks the control as `unsubmitted`.
354+ *
355+ * If the control has any children, it will also mark all children as `unsubmitted`.
356+ *
357+ * @param {{emitEvent: Boolean} } opts
358+ * @return {void }
359+ */
360+ markAsUnsubmitted ( opts = { } ) {
361+ this . submitted = false ;
362+
363+ this . _forEachChild ( ( control ) => { control . markAsUnsubmitted ( { onlySelf : true } ) ; } ) ;
364+
365+ if ( opts . emitEvent !== false ) {
366+ this . stateChanges . next ( ) ;
367+ }
368+ }
335369 /**
336370 * Marks the control as `pristine`.
337371 *
@@ -645,14 +679,17 @@ export class FormControl extends AbstractControl {
645679 if ( this . updateOn === "blur" ) {
646680 if ( ! this . dirty ) { this . markAsDirty ( ) ; }
647681 if ( ! this . touched ) { this . markAsTouched ( ) ; }
648- this . setValue ( this . _pendingValue , { validate : true } ) ;
682+ this . setValue ( this . _pendingValue ) ;
649683 } else if ( this . updateOn === "submit" ) {
650684 this . _pendingTouched = true ;
651685 this . _pendingDirty = true ;
652686 } else {
687+ const emitChangeToView = ! this . touched ;
653688 if ( ! this . dirty ) { this . markAsDirty ( ) ; }
654689 if ( ! this . touched ) { this . markAsTouched ( ) ; }
655- this . stateChanges . next ( ) ;
690+ if ( emitChangeToView ) {
691+ this . stateChanges . next ( ) ;
692+ }
656693 }
657694 } ;
658695 /**
@@ -728,7 +765,8 @@ export class FormControl extends AbstractControl {
728765 if ( this . _pendingDirty ) this . markAsDirty ( ) ;
729766 if ( this . _pendingTouched ) this . markAsTouched ( ) ;
730767 if ( this . _pendingChange ) {
731- this . setValue ( this . _pendingValue , { validate : true } ) ;
768+ this . setValue ( this . _pendingValue ) ;
769+ this . _pendingChange = false ;
732770 return true ;
733771 }
734772 }
@@ -740,16 +778,15 @@ export class FormGroup extends AbstractControl {
740778 super ( coerceToValidator ( validatorOrOpts ) ,
741779 coerceToAsyncValidator ( asyncValidator , validatorOrOpts ) ) ;
742780 this . controls = controls ;
743- this . submitted = false ;
744781 this . validatorOrOpts = validatorOrOpts ;
745782 this . _initObservables ( ) ;
746783 this . _setUpdateStrategy ( validatorOrOpts ) ;
747784 this . _setUpControls ( ) ;
748785 this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
749786 this . handleSubmit = ( e ) => {
750- e . preventDefault ( ) ;
751- this . submitted = true ;
752- if ( ! this . _syncPendingControls ( ) ) { this . updateValueAndValidity ( { validate : true } ) }
787+ if ( e ) { e . preventDefault ( ) ; }
788+ if ( ! this . submitted ) { this . markAsSubmitted ( { emitEvent : false } ) ; }
789+ if ( ! this . _syncPendingControls ( ) ) { this . updateValueAndValidity ( ) } ;
753790 }
754791 }
755792 /**
@@ -851,6 +888,7 @@ export class FormGroup extends AbstractControl {
851888 control . reset ( value [ name ] , { onlySelf : true , emitEvent : options . emitEvent } ) ;
852889 } ) ;
853890 this . updateValueAndValidity ( options ) ;
891+ this . markAsUnsubmitted ( ) ;
854892 this . _updatePristine ( options ) ;
855893 this . _updateTouched ( options ) ;
856894 }
@@ -982,7 +1020,7 @@ export class FormGroup extends AbstractControl {
9821020 let subtreeUpdated = this . _reduceChildren ( false , ( updated , child ) => {
9831021 return child . _syncPendingControls ( ) ? true : updated ;
9841022 } ) ;
985- if ( subtreeUpdated ) this . updateValueAndValidity ( { onlySelf : true } ) ;
1023+ if ( subtreeUpdated ) this . updateValueAndValidity ( ) ;
9861024 return subtreeUpdated ;
9871025 }
9881026}
@@ -992,16 +1030,15 @@ export class FormArray extends AbstractControl {
9921030 coerceToValidator ( validatorOrOpts ) ,
9931031 coerceToAsyncValidator ( asyncValidator , validatorOrOpts ) ) ;
9941032 this . controls = controls ;
995- this . submitted = false ;
9961033 this . validatorOrOpts = validatorOrOpts ;
9971034 this . _initObservables ( ) ;
9981035 this . _setUpdateStrategy ( validatorOrOpts ) ;
9991036 this . _setUpControls ( ) ;
10001037 this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
10011038 this . handleSubmit = ( e ) => {
1002- e . preventDefault ( ) ;
1003- this . submitted = true ;
1004- if ( ! this . _syncPendingControls ( ) ) { this . updateValueAndValidity ( { validate : true } ) }
1039+ if ( e ) { e . preventDefault ( ) ; }
1040+ if ( ! this . submitted ) { this . markAsSubmitted ( { emitEvent : false } ) ; }
1041+ if ( ! this . _syncPendingControls ( ) ) { this . updateValueAndValidity ( ) } ;
10051042 }
10061043 }
10071044 /**
@@ -1111,6 +1148,7 @@ export class FormArray extends AbstractControl {
11111148 control . reset ( value [ index ] , { onlySelf : true , emitEvent : options . emitEvent } ) ;
11121149 } ) ;
11131150 this . updateValueAndValidity ( options ) ;
1151+ this . markAsUnsubmitted ( ) ;
11141152 this . _updatePristine ( options ) ;
11151153 this . _updateTouched ( options ) ;
11161154 }
@@ -1132,7 +1170,7 @@ export class FormArray extends AbstractControl {
11321170 let subtreeUpdated = this . controls . reduce ( ( updated , child ) => {
11331171 return child . _syncPendingControls ( ) ? true : updated ;
11341172 } , false ) ;
1135- if ( subtreeUpdated ) this . updateValueAndValidity ( { onlySelf : true } ) ;
1173+ if ( subtreeUpdated ) this . updateValueAndValidity ( ) ;
11361174 return subtreeUpdated ;
11371175 }
11381176
0 commit comments