flutter_form_builder
flutter_form_builder copied to clipboard
autovalidateMode breaks the invalidate method
Is there an existing issue for this?
- [X] I have searched the existing issues
Package/Plugin version
9.1.0
Platforms
- [X] Android
- [X] iOS
- [ ] Linux
- [ ] MacOS
- [X] Web
- [ ] Windows
Flutter doctor
Flutter doctor
[!] Flutter (Channel stable, 3.10.5, on macOS 13.4.1 22F82 darwin-arm64, locale
en-RU)
• Flutter version 3.10.5 on channel stable at
/Users/dmitry/fvm/versions/3.10.5
! Warning: `dart` on your path resolves to
/opt/homebrew/Cellar/dart/2.18.6/libexec/bin/dart, which is not inside
your current Flutter SDK checkout at /Users/dmitry/fvm/versions/3.10.5.
Consider adding /Users/dmitry/fvm/versions/3.10.5/bin to the front of your
path.
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 796c8ef792 (9 weeks ago), 2023-06-13 15:51:02 -0700
• Engine revision 45f6e00911
• Dart version 3.0.5
• DevTools version 2.23.1
• If those were intentional, you can disregard the above warnings; however
it is recommended to use "git" directly to perform update checks and
upgrades.
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
• Android SDK at /Users/dmitry/Library/Android/sdk
• Platform android-33, build-tools 33.0.1
• Java binary at: /Applications/Android
Studio.app/Contents/jbr/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
11.0.15+0-b2043.56-8887301)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 14.3)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 14E222b
• CocoaPods version 1.12.1
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2022.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build
11.0.15+0-b2043.56-8887301)
[✓] VS Code (version 1.81.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.70.0
[✓] Connected device (2 available)
• macOS (desktop) • macos • darwin-arm64 • macOS 13.4.1 22F82
darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 115.0.5790.170
[✓] Network resources
• All expected network resources are available.
Minimal code example
Code sample
typedef FormErrors = Map<String, String>;
mixin FormHelperMixin<T extends StatefulWidget> on State<T> {
final formKey = GlobalKey<FormBuilderState>();
AutovalidateMode autovalidateMode = AutovalidateMode.disabled;
FormBuilderState? get _form => formKey.currentState;
FormErrors? _formErrors;
Map<String, void Function(dynamic)> formHelpers = {};
Future<FormErrors?> onSubmitForm(Map<String, dynamic> values);
Future<void> submitForm() async {
if (autovalidateMode != AutovalidateMode.always) {
setState(() {
autovalidateMode = AutovalidateMode.always;
});
}
if (_form?.validate(autoScrollWhenFocusOnInvalid: true) ?? false) {
final formErrors = await onSubmitForm(_form!.instantValue);
_handleFormErrors(formErrors);
}
}
void _handleFormErrors(FormErrors? formErrors) {
if (!mounted || _form == null) {
return;
}
setState(() {
_formErrors = formErrors;
formHelpers = {};
if (formErrors != null) {
for (final entry in formErrors.entries) {
final name = entry.key;
final error = entry.value;
final field = _form?.fields[name];
if (field != null && error.isNotEmpty) {
field.invalidate(error, shouldFocus: false);
formHelpers[name] = (_) {
if (_formErrors?[name] != null) {
_formErrors?.remove(name);
_form?.fields[name]?.validate();
}
};
}
}
}
});
}
}
typedef OnSubmit = Future<FormErrors?> Function({
required String email,
required String password,
});
enum LoginFields { email, password }
class LoginForm extends StatefulWidget {
final bool isLoading;
final OnSubmit? onSubmit;
const LoginForm({
super.key,
this.isLoading = false,
this.onSubmit,
});
@override
State<LoginForm> createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> with FormHelperMixin {
final _email = LoginFields.email.name;
final _password = LoginFields.password.name;
@override
Future<FormErrors?> onSubmitForm(Map<String, dynamic> values) async {
return widget.onSubmit?.call(
email: values[_email]?.trim() ?? '',
password: values[_password]?.trim() ?? '',
);
}
@override
Widget build(BuildContext context) {
return FormBuilder(
key: formKey,
autovalidateMode: autovalidateMode,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
FormBuilderField<String>(
name: _email,
onChanged: formHelpers[_email],
builder: (field) {
return OutlinedTextField(
label: 'E-mail',
value: field.value,
errorText: field.errorText,
onChanged: field.didChange,
);
},
),
const SizedBox(height: 20),
FormBuilderField<String>(
name: _password,
onChanged: formHelpers[_password],
builder: (field) {
return OutlinedTextField(
label: 'Password',
isPassword: true,
value: field.value,
errorText: field.errorText,
onChanged: field.didChange,
);
},
),
const SizedBox(height: 28),
PrimaryButton.title(
'Enter',
isLoading: widget.isLoading,
onPressed: submitForm,
),
],
),
);
}
}
Current Behavior
The problem is that after changing autovalidateMode to always or onUserInteraction, the field's invalidate method doesn't work, and previous custom errors disappear.
Expected Behavior
The most common behavior in my opinion.
The form is not automatically validated, the user enters the data, clicks the submit button, the validation becomes autovalidateMode.always, if the form is valid, a request is sent to the backend, if some fields are not correct, the backend returns Map<String, String> with errors and I write them to the fields with formKey.currentState.fields[fireldName].invalidate(error). Now when the user changes the value of the field, the error from the backend should disappear and validation should only take place by local form validators.
Steps To Reproduce
look at code and videos
Aditional information
https://github.com/flutter-form-builder-ecosystem/flutter_form_builder/assets/33316685/1c376642-f1b8-4998-98da-fd02ad4c2513
https://github.com/flutter-form-builder-ecosystem/flutter_form_builder/assets/33316685/60c75006-1a5a-4482-a0c1-c7a809cea447