formz icon indicating copy to clipboard operation
formz copied to clipboard

Trigger validation when user clicks on submit

Open praveengitsit opened this issue 2 years ago • 1 comments

I have introduced Bloc and Formz for a Flutter application which I am currently doing.

What I was trying to achieve currently was a simple text field in a form that shows validation errors. I noticed that the behaviors of valid and invalid are working differently than one would expect.

If I have a property called fullname in a Bloc, I expect that these two would have the same behaviors:

  • state.fullName.valid
  • !state.fullName.invalid

But the results are different for both. Am I missing something here?

To Reproduce

Steps to reproduce the behavior: We can follow @felangel 's flutter_login project for a reference to this.

https://github.com/felangel/bloc/tree/master/examples/flutter_login

Here, in the widgets of the login form, we can try switching the "errorText" values to have either of the values.

  • errorText: state.username.valid ? null: 'invalid username',
  • errorText: state.username.invalid ? 'invalid username' : null,

Expected behavior

I expect that the boolean returned by valid and invalid would be opposites of each other, which is not the case.

Screenshots With: errorText: state.password.valid ? null : 'invalid password',

Screenshot from 2022-04-19 10-06-39

With: errorText: state.password.invalid ? 'invalid password' : null,

Screenshot from 2022-04-19 10-07-05

Additional context I have a sign up form, which has a couple of text fields, and drop downs. The issue I am having is that the when using the valid property, the error text is being displayed to the user even before the user has entered anything (in the pure state).

When I am using the invalid property, this issue is solved. But, unlike the flutter_login example, we have a user requirement where we don't disable the submit button. And I need to trigger the validation error texts for the text fields once the submit is pressed. I have an event which emits this validation.


      emit(
        state.copyWith(
          status: Formz.validate(
            [
              state.fullName,
              state.email,
              state.phoneNumber,
            ],
          ),
        ),
      );

But this does not work. It would be of tremendous help if someone could show me a resolve for this issue.

praveengitsit avatar Apr 19 '22 04:04 praveengitsit

fullName.valid and fullName.invalid triggers validator(), which will return the result whether it's Pure or not.

You'd be better off doing something along the lines of

errorText: state.fullName.status == FormzInputStatus.pure ? null : state.fullName.error,

Assuming your ErrorType is string, otherwise handle the error.

As for only triggering once the submit button is pressed, I haven't used bloc but something like this should work:

In your .bloc:

bool _canSubmit(
  LoginPressed event,
  Emitter<LoginState> emit,
) {
  final result = Formz.validate([state.password, state.username]),
  if (result == FormzStatus.valid) {
    return true;
} else {
    return false;
}
}

Add a bool to your state class which indicates whether to show errors, then in your textfields you can do:

errorText: state.showErrors ? 'some error' : null,

Then check in your button what the return value is before submitting.

onPressed: () => _canSubmit() ? _performSubmit() : _setStateToShowErrors(),

atruby21 avatar Apr 30 '22 12:04 atruby21

Hey @ praveengitsit, it has been some time, did the above explanation help your use case?

renancaraujo avatar Jul 18 '23 12:07 renancaraujo

For cleanliness of issues, I am closing this one for now. If we can be of any further assistance, please fell free to open another issue.

renancaraujo avatar Aug 07 '23 14:08 renancaraujo