33// found in the LICENSE file.
44
55import 'dart:async' ;
6+ import 'dart:collection' ;
67
78import 'package:flutter/foundation.dart' ;
89import 'package:reactive_forms/reactive_forms.dart' ;
@@ -29,7 +30,8 @@ abstract class AbstractControl<T> {
2930 < AsyncValidator <dynamic >> [];
3031
3132 StreamSubscription <Map <String , dynamic >?>? _asyncValidationSubscription;
32- Map <String , dynamic > _errors = < String , dynamic > {};
33+ final Map <String , dynamic > _errors = < String , dynamic > {};
34+ late final Map <String , dynamic > _errorsView = UnmodifiableMapView (_errors);
3335 bool _pristine = true ;
3436
3537 T ? _value;
@@ -106,8 +108,7 @@ abstract class AbstractControl<T> {
106108 ///
107109 /// In [FormGroup] these come in handy when you want to perform validation
108110 /// that considers the value of more than one child control.
109- List <Validator <dynamic >> get validators =>
110- List <Validator <dynamic >>.unmodifiable (_validators);
111+ List <Validator <dynamic >> get validators => UnmodifiableListView (_validators);
111112
112113 /// Sets the synchronous [validators] that are active on this control. Calling
113114 /// this overwrites any existing sync validators.
@@ -142,20 +143,24 @@ abstract class AbstractControl<T> {
142143 }
143144
144145 /// Empties out the sync validator list.
145- ///
146- /// When you add or remove a validator at run time, you must call
147- /// **updateValueAndValidity()**, or assign a new value to the control for
148- /// the new validation to take effect.
149- void clearValidators ( ) {
146+ void clearValidators ({
147+ bool autoValidate = false ,
148+ bool updateParent = true ,
149+ bool emitEvent = true ,
150+ } ) {
150151 _validators.clear ();
152+
153+ if (autoValidate) {
154+ updateValueAndValidity (updateParent: updateParent, emitEvent: emitEvent);
155+ }
151156 }
152157
153158 /// The list of async functions that determines the validity of this control.
154159 ///
155160 /// In [FormGroup] these come in handy when you want to perform validation
156161 /// that considers the value of more than one child control.
157162 List <AsyncValidator <dynamic >> get asyncValidators =>
158- List < AsyncValidator < dynamic >>. unmodifiable (_asyncValidators);
163+ UnmodifiableListView (_asyncValidators);
159164
160165 /// Sets the async [validators] that are active on this control. Calling this
161166 /// overwrites any existing async validators.
@@ -208,7 +213,7 @@ abstract class AbstractControl<T> {
208213
209214 /// An object containing any errors generated by failing validation,
210215 /// or empty [Map] if there are no errors.
211- Map <String , Object > get errors => Map < String , Object >. unmodifiable (_errors) ;
216+ Map <String , dynamic > get errors => _errorsView ;
212217
213218 /// A [Stream] that emits the status every time it changes.
214219 Stream <ControlStatus > get statusChanged => _statusChanges.stream;
@@ -237,7 +242,8 @@ abstract class AbstractControl<T> {
237242 bool get enabled => ! disabled;
238243
239244 /// True whether the control has validation errors.
240- bool get hasErrors => errors.isNotEmpty;
245+ bool get hasErrors =>
246+ _errors.isNotEmpty || anyControls ((control) => control.hasErrors);
241247
242248 /// The validation status of the control.
243249 ///
@@ -643,16 +649,14 @@ abstract class AbstractControl<T> {
643649 parent? ._updateControlsErrors ();
644650 }
645651
646- Map < String , dynamic > _runValidators () {
647- final errors = < String , dynamic > {} ;
648- for (final validator in validators ) {
652+ void _runValidators () {
653+ _errors. clear () ;
654+ for (final validator in _validators ) {
649655 final error = validator.validate (this );
650656 if (error != null ) {
651- errors .addAll (error);
657+ _errors .addAll (error);
652658 }
653659 }
654-
655- return errors;
656660 }
657661
658662 void _setInitialStatus () {
@@ -687,7 +691,7 @@ abstract class AbstractControl<T> {
687691 _updateValue ();
688692 if (enabled) {
689693 _cancelExistingSubscription ();
690- _errors = _runValidators ();
694+ _runValidators ();
691695 _status = _calculateStatus ();
692696 if (_status == ControlStatus .valid || _status == ControlStatus .pending) {
693697 _runAsyncValidators ();
@@ -1457,7 +1461,7 @@ class FormGroup extends FormControlCollection<Map<String, Object?>> {
14571461 }
14581462
14591463 @override
1460- Map <String , Object ?> get value => Map . unmodifiable (_value! );
1464+ Map <String , Object ?> get value => UnmodifiableMapView (_value! );
14611465
14621466 /// Set the complete value for the form group.
14631467 ///
@@ -1528,15 +1532,12 @@ class FormGroup extends FormControlCollection<Map<String, Object?>> {
15281532 ///
15291533 /// Contains all the errors of the group and the child errors.
15301534 @override
1531- Map <String , Object > get errors {
1532- final allErrors = Map <String , Object >.of (super .errors);
1535+ Map <String , dynamic > get errors {
1536+ final allErrors = < String , dynamic > {};
1537+ allErrors.addAll (_errors);
15331538 _controls.forEach ((name, control) {
15341539 if (control.enabled && control.hasErrors) {
1535- allErrors.update (
1536- name,
1537- (_) => control.errors,
1538- ifAbsent: () => control.errors,
1539- );
1540+ allErrors[name] = control.errors;
15401541 }
15411542 });
15421543
@@ -1853,10 +1854,14 @@ class FormArray<T> extends FormControlCollection<List<T?>> {
18531854 /// This method is for internal use only.
18541855 @override
18551856 List <T ?>? reduceValue () {
1856- return _controls
1857- .where ((control) => control.enabled || disabled)
1858- .map ((control) => control.value)
1859- .toList ();
1857+ final values = < T ? > [];
1858+ for (final control in _controls) {
1859+ if (control.enabled || disabled) {
1860+ values.add (control.value);
1861+ }
1862+ }
1863+
1864+ return values;
18601865 }
18611866
18621867 /// Disables the control.
@@ -2167,17 +2172,14 @@ class FormArray<T> extends FormControlCollection<List<T?>> {
21672172 ///
21682173 /// Contains all the errors of the array and the child errors.
21692174 @override
2170- Map <String , Object > get errors {
2171- final allErrors = Map .of (super .errors);
2175+ Map <String , dynamic > get errors {
2176+ final allErrors = < String , dynamic > {};
2177+ allErrors.addAll (_errors);
21722178 _controls.asMap ().entries.forEach ((entry) {
21732179 final control = entry.value;
21742180 final name = entry.key.toString ();
21752181 if (control.enabled && control.hasErrors) {
2176- allErrors.update (
2177- name,
2178- (_) => control.errors,
2179- ifAbsent: () => control.errors,
2180- );
2182+ allErrors[name] = control.errors;
21812183 }
21822184 });
21832185
0 commit comments