@@ -153,6 +153,7 @@ export class AbstractControl {
153
153
* a `blur` event on it.
154
154
*/
155
155
this . touched = false ;
156
+ this . submitted = false ;
156
157
/**
157
158
* A control is `pristine` if the user has not yet changed
158
159
* the value in the UI.
@@ -300,13 +301,13 @@ export class AbstractControl {
300
301
updateValueAndValidity ( options = { } ) {
301
302
this . setInitialStatus ( ) ;
302
303
this . _updateValue ( ) ;
303
- const shouldValidate = this . enabled && ( this . updateOn === "change " || options . validate ) ;
304
+ const shouldValidate = this . enabled && ( this . updateOn !== "submit " || this . submitted ) ;
304
305
if ( shouldValidate ) {
305
306
this . _cancelExistingSubscription ( ) ;
306
307
this . errors = this . _runValidator ( ) ;
307
308
this . status = this . _calculateStatus ( ) ;
308
309
if ( this . status === VALID || this . status === PENDING ) {
309
- this . _runAsyncValidator ( options . emitEvent ) ;
310
+ this . _runAsyncValidator ( true ) ;
310
311
}
311
312
}
312
313
if ( options . emitEvent !== false ) {
@@ -332,6 +333,39 @@ export class AbstractControl {
332
333
this . _parent . markAsTouched ( opts ) ;
333
334
}
334
335
}
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
+ }
335
369
/**
336
370
* Marks the control as `pristine`.
337
371
*
@@ -645,14 +679,17 @@ export class FormControl extends AbstractControl {
645
679
if ( this . updateOn === "blur" ) {
646
680
if ( ! this . dirty ) { this . markAsDirty ( ) ; }
647
681
if ( ! this . touched ) { this . markAsTouched ( ) ; }
648
- this . setValue ( this . _pendingValue , { validate : true } ) ;
682
+ this . setValue ( this . _pendingValue ) ;
649
683
} else if ( this . updateOn === "submit" ) {
650
684
this . _pendingTouched = true ;
651
685
this . _pendingDirty = true ;
652
686
} else {
687
+ const emitChangeToView = ! this . touched ;
653
688
if ( ! this . dirty ) { this . markAsDirty ( ) ; }
654
689
if ( ! this . touched ) { this . markAsTouched ( ) ; }
655
- this . stateChanges . next ( ) ;
690
+ if ( emitChangeToView ) {
691
+ this . stateChanges . next ( ) ;
692
+ }
656
693
}
657
694
} ;
658
695
/**
@@ -728,7 +765,8 @@ export class FormControl extends AbstractControl {
728
765
if ( this . _pendingDirty ) this . markAsDirty ( ) ;
729
766
if ( this . _pendingTouched ) this . markAsTouched ( ) ;
730
767
if ( this . _pendingChange ) {
731
- this . setValue ( this . _pendingValue , { validate : true } ) ;
768
+ this . setValue ( this . _pendingValue ) ;
769
+ this . _pendingChange = false ;
732
770
return true ;
733
771
}
734
772
}
@@ -740,16 +778,15 @@ export class FormGroup extends AbstractControl {
740
778
super ( coerceToValidator ( validatorOrOpts ) ,
741
779
coerceToAsyncValidator ( asyncValidator , validatorOrOpts ) ) ;
742
780
this . controls = controls ;
743
- this . submitted = false ;
744
781
this . validatorOrOpts = validatorOrOpts ;
745
782
this . _initObservables ( ) ;
746
783
this . _setUpdateStrategy ( validatorOrOpts ) ;
747
784
this . _setUpControls ( ) ;
748
785
this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
749
786
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 ( ) } ;
753
790
}
754
791
}
755
792
/**
@@ -851,6 +888,7 @@ export class FormGroup extends AbstractControl {
851
888
control . reset ( value [ name ] , { onlySelf : true , emitEvent : options . emitEvent } ) ;
852
889
} ) ;
853
890
this . updateValueAndValidity ( options ) ;
891
+ this . markAsUnsubmitted ( ) ;
854
892
this . _updatePristine ( options ) ;
855
893
this . _updateTouched ( options ) ;
856
894
}
@@ -982,7 +1020,7 @@ export class FormGroup extends AbstractControl {
982
1020
let subtreeUpdated = this . _reduceChildren ( false , ( updated , child ) => {
983
1021
return child . _syncPendingControls ( ) ? true : updated ;
984
1022
} ) ;
985
- if ( subtreeUpdated ) this . updateValueAndValidity ( { onlySelf : true } ) ;
1023
+ if ( subtreeUpdated ) this . updateValueAndValidity ( ) ;
986
1024
return subtreeUpdated ;
987
1025
}
988
1026
}
@@ -992,16 +1030,15 @@ export class FormArray extends AbstractControl {
992
1030
coerceToValidator ( validatorOrOpts ) ,
993
1031
coerceToAsyncValidator ( asyncValidator , validatorOrOpts ) ) ;
994
1032
this . controls = controls ;
995
- this . submitted = false ;
996
1033
this . validatorOrOpts = validatorOrOpts ;
997
1034
this . _initObservables ( ) ;
998
1035
this . _setUpdateStrategy ( validatorOrOpts ) ;
999
1036
this . _setUpControls ( ) ;
1000
1037
this . updateValueAndValidity ( { onlySelf : true , emitEvent : false } ) ;
1001
1038
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 ( ) } ;
1005
1042
}
1006
1043
}
1007
1044
/**
@@ -1111,6 +1148,7 @@ export class FormArray extends AbstractControl {
1111
1148
control . reset ( value [ index ] , { onlySelf : true , emitEvent : options . emitEvent } ) ;
1112
1149
} ) ;
1113
1150
this . updateValueAndValidity ( options ) ;
1151
+ this . markAsUnsubmitted ( ) ;
1114
1152
this . _updatePristine ( options ) ;
1115
1153
this . _updateTouched ( options ) ;
1116
1154
}
@@ -1132,7 +1170,7 @@ export class FormArray extends AbstractControl {
1132
1170
let subtreeUpdated = this . controls . reduce ( ( updated , child ) => {
1133
1171
return child . _syncPendingControls ( ) ? true : updated ;
1134
1172
} , false ) ;
1135
- if ( subtreeUpdated ) this . updateValueAndValidity ( { onlySelf : true } ) ;
1173
+ if ( subtreeUpdated ) this . updateValueAndValidity ( ) ;
1136
1174
return subtreeUpdated ;
1137
1175
}
1138
1176
0 commit comments