form_bloc icon indicating copy to clipboard operation
form_bloc copied to clipboard

Turn on autovalidation after submit

Open maguro opened this issue 4 years ago • 7 comments

I would like to turn on autovalidation after a submit. I also would like to validate the fields when they loose focus.

How can I accomplish this?

maguro avatar Apr 06 '20 23:04 maguro

I will add a method to enable / disable auto validation in a few days :)

Respect validate when loose focus, I am not sure how it would be, I will try this in a few days and if it works I will add a property that allows to choose which type of validation must have the text field,

  • onLossFocus
  • onChanges
  • other? this is only for text field? If you know any solution it would be good to tell me, I know that this will have its complications on mobile because the focus is not lost automatically when you click outside the fields, unlike flutter web.

__

P.D. Respect to turn on auto validation this mean that you set autoValidete to false in the super constructor, and the use enable auto validation ?

  MyFormBloc() : super(autoValidate: false) {
    ...
  }
  void onSubmitting(){
    enableAutoValidation(); // do you want this method? 
  }

GiancarloCode avatar Apr 07 '20 00:04 GiancarloCode

I can submit a patch, here's what I was thinking:

RaisedButton(
  onPressed: () {
    loginFormBloc.autoValidate = true;
    loginFormBloc.submit();
  },
  child: Text('LOGIN'),
),

The class FormBloc would have something like:

bool get autoValidate => _autoValidate;
set autoValidate(bool value) {
  _autoValidate = value ?? false;
  _setAutoValidateForFields(_allFieldBlocsUsed);
}

where _setAutoValidateForFields() is

void _setAutoValidateForFields(Iterable<FieldBloc> fieldBlocs) {
  FormBlocUtils.getAllFieldBlocs(fieldBlocs).forEach((e) {
    if (e is SingleFieldBloc) {
      e.add(
        AddFormBlocAndAutoValidateToFieldBloc(
            formBloc: this, autoValidate: _autoValidate),
      );
    } else if (e is ListFieldBloc) {
      e.add(
        AddFormBlocAndAutoValidateToListFieldBloc(
            formBloc: this, autoValidate: _autoValidate),
      );
    } else if (e is GroupFieldBloc) {
      e.add(
        AddFormBlocAndAutoValidateToGroupFieldBloc(
            formBloc: this, autoValidate: _autoValidate),
      );
    }
  });
}

and _onAddFieldBloc() calls _setAutoValidateForFields() as well.

maguro avatar Apr 07 '20 00:04 maguro

Yes, more or less that's the idea, But it would be creating events for the form bloc and the public methods for this events EnableAutoValidation() DisableAutoValidation() and process them on the mapEventToState

There you can call _setAutoValidateForFields

In this way the pattern is followed and we have a record of these events in the bloc delegate

I'm not sure with the names, I always have doubts about that haha

GiancarloCode avatar Apr 07 '20 00:04 GiancarloCode

Gotcha.

re: unfocus, in the login form,

_emailFocusNode = FocusNode()
  ..addListener(() {
    if (!_emailFocusNode.hasFocus) {
      setState(() {
        bloc.add(
            AutoValidateFieldBloc(formBloc: bloc.email, autoValidate: true));
      });
    }
  });

maguro avatar Apr 07 '20 01:04 maguro

Autovalidation true/false This a good approach that validators are executed on each field change. This allows to track the form consistency at every moment. But the error display logic is not adjustable(correct if I'm wrong) If I have an autovalidate: true and email field(Simple example from https://giancarlocode.github.io/). Just after I enter the first symbol the form notifies me that the field is badly formatted. But I'm not done with input yet :-) How the form knows that I'm wrong?) The other case is autovalidate: false - I do not see the errors until I press 'Submit' this is a little bit annoying(from users perspective). It could lead the case that user fills long form and sees the errors far later.

This could be improved with two things - introducing the field meta data, and display error hook(callback).

Example from react-final-form(pretty proven solution)

isErrorField = (meta: Meta): boolean =>
    !!(meta && ((meta.error && meta.touched) || (meta.submitError && meta.submitFailed)));

This function checks if field has errors, if it was touched before or has submit errors and submit was failed. Returns the true/false and this is a sign whether to display an error.

Here is a link to full list of meta data of the field https://github.com/final-form/react-final-form/blob/master/src/types.js.flow#L32

How this will help.

If user hits the field for the first time the meta.touched is false. So we do not disturb the user during possible errors while he entering value for the first time. After he switches to another field meta.touched becomes true and only than we can show an error. If user gets back to the editing the meta.touched already true and now we show the realtime error display based on the assumption that the previous value was correct and if user alters it we notify him immediately that there is an error.

The default error display logic could stay the same. But with this extended meta data and error display hook everyone can alter the logic on his own demands.

vasilich6107 avatar Apr 18 '20 13:04 vasilich6107

Any update on this? I'm also interested in disabling autovalidation until, for example, the user submits the form with some errors. I've tried to handle this use case, but I'm not sure this is the correct/best way to implement it

// MyFormBloc
@override
void onChange(Change<FormBlocState<String, String>> change) {
  super.onChange(change);

  // catch state change as with FormBlocListener.onSubmissionFailed
  if (change.nextState is FormBlocSubmissionFailed) {
    // iterate over all form fields (don't know a better way)...
    mySingleFieldBloc1.add(AddFormBlocAndAutoValidateToFieldBloc(
      formBloc: this,
      autoValidate: true,
    ));

    mySingleFieldBloc2.add(AddFormBlocAndAutoValidateToFieldBloc(
      formBloc: this,
      autoValidate: true,
    ));

     ...
  }
}

ferrerogg avatar Nov 09 '21 15:11 ferrerogg

My proposal: #331

ingmferrer avatar Feb 02 '23 02:02 ingmferrer