How to achieve the best UX with Flutter form AutovalidateMode

Viewed 270

I am trying to achieve the best UX on Flutter using AutovalidateMode.onUserInteraction.

Option 1

When I set the validation on the form key, when a user tries to type one one texField the whole form goes red with errors.

 child: Form(
              key: _formKey,
              autovalidateMode: AutovalidateMode.onUserInteraction,

Option 2

When I set AutovalidateMode.onUserInteraction on each text field I end up getting the error on each textfield when the user tries to type and it disappears when they complete the input.

 RoundedPasswordResetField(
                                validator: (value) {
                                  if (value.isEmpty) {
                                        return 'Please Re-enter Password';
                                      }
                                      if (password != confirmpassword) {
                                        return "Password does not match";
                                      }
                                      //
                                      return null;
                                    },
                                    autovalidateMode: AutovalidateMode.onUserInteraction,
                                    hintText: "Please Re-enter Password",
                                    onChanged: (value) {
                                      confirmpassword = value;
                                    },
                                  ),

Option 3

When I set it to autovalidateMode: AutovalidateMode.disabled,, when the user tries to submit the fields when they are empty, the errors appear, but when they key in the specific correct details the errors don't clear out

 RoundedPasswordResetField(
                                        validator: (value) {
                                          if (value.isEmpty) {
                                            return 'Please Re-enter Password';
                                          }
                                          if (password != confirmpassword) {
                                            return "Password does not match";
                                          }
                                          //
                                          return null;
                                        },
                                        autovalidateMode: AutovalidateMode.disabled,
                                        hintText: "Please Re-enter Password",
                                        onChanged: (value) {
                                          confirmpassword = value;
                                        },
                                      ),

How can I use setState, so that when the user starts typing the errors wont be shown immediately, and shown when they complete inputting wrong details - and achieve the best UX?

1 Answers

This is something I implemented in one of my Android projects two years ago. Although, it was Kotlin, still I opened my Github and looked for it.

First, let's understand your question: The question says that Autovalidate mode shouldn't be there or should be left to default (AutovalidateMode.disabled) to not do the validation whenever user starts typing which is obviously a bad UX. But, it should work only after the user stops with enough delay to consider it as completion of typing which means whenever there is a brief stoppage in the input data stream.

Now, for this, PublishProcessor.debounce() of RxJava is a good option in Kotlin, which can be used in dart using packages like rxdart. What it does is it prevents continuous execution of a function and only executes the function after a certain delay, if the function is triggered again, it resets the delay. So, the funtion executes only once and that too, only after a certain delay imitating the effect of user stopped typing.

Use this - Just Debounce It package, it's not as over-kill as RxDart but still, there are many alternatives.

Implement it as

void function validateForm() {
  Debounce.seconds(2, //2 means run this function only after 2 second delay.
    () => formKey.currentState.validate()) //This is a function passed as a Callback which is executed only when it crosses the delay.
}

And call this function from onChanged as:

onChanged: (val) => validateForm()

That's it. Now, your form will only be validated if the user stops typing. This is the go-to way, not just good UX but good logic. There are hacks to make this work with booleans and postDelayed but that's bad code.

Related