Skip to content

Commit b85c868

Browse files
EdgarJanMairramer
authored andcommitted
Fix and Test Conditional Validator Behavior in FormField (flutter#132714)
In the FormField widget, if a validator is initially set (and validation fails), then subsequently the validator is set to null, the form incorrectly retains its error state. This is not expected behavior as removing the validator should clear any validation errors.
1 parent a9a0cf1 commit b85c868

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

packages/flutter/lib/src/widgets/form.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin {
524524
void _validate() {
525525
if (widget.validator != null) {
526526
_errorText.value = widget.validator!(_value);
527+
} else {
528+
_errorText.value = null;
527529
}
528530
}
529531

packages/flutter/test/widgets/form_test.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,4 +945,71 @@ void main() {
945945
fieldKey.currentState!.reset();
946946
expect(fieldKey.currentState!.hasInteractedByUser, isFalse);
947947
});
948+
949+
testWidgets('Validator is nullified and error text behaves accordingly',
950+
(WidgetTester tester) async {
951+
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
952+
bool useValidator = false;
953+
late StateSetter setState;
954+
955+
String? validator(String? value) {
956+
if (value == null || value.isEmpty) {
957+
return 'test_error';
958+
}
959+
return null;
960+
}
961+
962+
Widget builder() {
963+
return StatefulBuilder(
964+
builder: (BuildContext context, StateSetter setter) {
965+
setState = setter;
966+
return MaterialApp(
967+
home: MediaQuery(
968+
data: const MediaQueryData(),
969+
child: Directionality(
970+
textDirection: TextDirection.ltr,
971+
child: Center(
972+
child: Material(
973+
child: Form(
974+
key: formKey,
975+
child: TextFormField(
976+
validator: useValidator ? validator : null,
977+
),
978+
),
979+
),
980+
),
981+
),
982+
),
983+
);
984+
},
985+
);
986+
}
987+
988+
await tester.pumpWidget(builder());
989+
990+
// Start with no validator.
991+
await tester.enterText(find.byType(TextFormField), '');
992+
await tester.pump();
993+
formKey.currentState!.validate();
994+
await tester.pump();
995+
expect(find.text('test_error'), findsNothing);
996+
997+
// Now use the validator.
998+
setState(() {
999+
useValidator = true;
1000+
});
1001+
await tester.pump();
1002+
formKey.currentState!.validate();
1003+
await tester.pump();
1004+
expect(find.text('test_error'), findsOneWidget);
1005+
1006+
// Remove the validator again and expect the error to disappear.
1007+
setState(() {
1008+
useValidator = false;
1009+
});
1010+
await tester.pump();
1011+
formKey.currentState!.validate();
1012+
await tester.pump();
1013+
expect(find.text('test_error'), findsNothing);
1014+
});
9481015
}

0 commit comments

Comments
 (0)