flutter-form-builder-ecosystem / form_builder_validators

Form Builder Validators is set of validators for FormFields. It provides common validators and a way to reuse multiple validators
https://pub.dev/packages/form_builder_validators
BSD 3-Clause "New" or "Revised" License
50 stars 98 forks source link

FormBuilderValidators.equal() do not update value to compare #63

Open deandreamatias opened 1 year ago

deandreamatias commented 1 year ago

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: ```dart 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;
    };
the-devbear commented 10 months ago

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.

image

When I add a setState() to the confirmPassword field on the onChange callback it works fine.

image
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.

petodavid commented 2 months ago

Is there an update about this? As I see this is still an issue in the latest version 11.0.0 ?