Skip to content

Commit c6247c7

Browse files
committed
Merge branch 'release/18.2.2'
2 parents 3eea882 + caafd03 commit c6247c7

File tree

4 files changed

+59
-39
lines changed

4 files changed

+59
-39
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
# 18.2.2
2+
3+
## Fixes
4+
5+
- Correct `hasErrors` to check child controls.
6+
7+
## Enhances
8+
9+
- Improve `errors` getter performance.
10+
- Optimize list and map access.
11+
12+
# 18.2.1
13+
14+
## Enhances
15+
16+
- Added optional parameters to the `clearValidators` method to support automatic validation after
17+
clearing validators.
18+
119
# 18.2.0
220

321
## Features

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ dependencies:
8888
flutter:
8989
sdk: flutter
9090

91-
reactive_forms: ^18.2.0
91+
reactive_forms: ^18.2.2
9292
```
9393
9494
Then, run the command `flutter packages get` in the console.

lib/src/models/models.dart

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6+
import 'dart:collection';
67

78
import 'package:flutter/foundation.dart';
89
import '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

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: reactive_forms
22
description: This is a model-driven approach to handling form inputs and validations, heavily inspired in Angular Reactive Forms.
3-
version: 18.2.0
3+
version: 18.2.2
44
homepage: "https://github.com/joanpablo/reactive_forms"
55

66
environment:

0 commit comments

Comments
 (0)