FormBuilderValidators.equal() do not update value to compare
Discussed in https://github.com/flutter-form-builder-ecosystem/form_builder_validators/discussions/61
Originally posted by orbiteleven August 30, 2023
Using form_builder_validators with flutter_form_builder and I have what I think should be a pretty common password+confirm password form, but I'm a bit confused. This is what I have so far:
FormBuilderTextField(
name: 'password',
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators.minLength(6)
])),
FormBuilderTextField(
name: 'confirmPassword',
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators.minLength(6),
(value) {
print(
"value: $value matches ${_formKey.currentState?.instantValue['password']}");
return null;
},
FormBuilderValidators.equal(
_formKey.currentState?.instantValue['password'] ?? '',
errorText: 'Passwords do not match')
])),
the "custom" validator works fine, but FormBuilderValidators.equal() throws an error. What am I doing wrong?
For some reason, FormBuilderValidators.equal validator don't update value to compare with fieldValue A nice way to show the error, is create a validate method with print:
FormFieldValidator<T> equal<T>(
Object? value, {
String? errorText,
}) =>
(T? valueCandidate) {
print(
'value: $value valueCandidate: $valueCandidate'
);
// Value is null and valueCandidate the form field value, when update field value
return valueCandidate != value ? errorText : null;
};
Unfortunately I don't have a solution, but here is what I found out.
Apparently he does not get the new value or any value for the matching value. The cascading thing which keeps on going. I don't know what could cause that.
When I add a setState() to the confirmPassword field on the onChange callback it works fine.
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Form Builder Validators')),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: FormBuilder(
key: _formKey,
child: Column(
children: <Widget>[
FormBuilderTextField(
name: 'password',
initialValue: 'MyAwesomePassword',
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators.minLength(6)
])),
FormBuilderTextField(
name: 'confirmPassword',
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: (value) => {
setState(() {
print(value);
})
},
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators.minLength(6),
(value) {
var password =
_formKey.currentState?.instantValue['password'];
print(
"value: $value matches ${_formKey.currentState?.instantValue['password']}");
return null;
},
FormBuilderValidators.equal(
_formKey.currentState?.instantValue['password'] ?? '',
errorText: 'Passwords do not match second one'),
])),
],
),
),
),
);
This is the Widget with what I tested. What seems to also works is this:
(value) {
return FormBuilderValidators.equal<String>(
_formKey.currentState?.instantValue['password'] ?? '',
errorText: 'Passwords do not match first one')(value);
},
I think that the equal Funkton a Closure returns which saves the initial value (also tried it with another value and then I don't get the weird cascading String). Since the State is never set in the Component the value is never reevaluated.
I hope this helps, if anything is unclear please ask me anything and I will try to help.
Is there an update about this? As I see this is still an issue in the latest version 11.0.0 ?
i also have the same problem i now created my own code for this.
i also have the same problem i now created my own code for this.
You can use my solution
FormBuilderTextField(
name: 'password',
validator: FormBuilderValidators.password(),
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Enter your password',
prefixIcon: const Icon(Icons.lock),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
),
),
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w600,
),
),
FormBuilderTextField(
name: "confirm_password",
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
),
labelText: "Confirm password",
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
onPressed: () {},
icon: const Icon(Icons.remove_red_eye),
),
),
obscureText: true,
keyboardType: TextInputType.visiblePassword,
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(),
FormBuilderValidators. password(8),
(val) {
if (val != _formKey.currentState?.getRawValue("password")) {
return "Password not match";
}
return null;
}
]),
),