semisleep / simple-vue-validator

A simple yet flexible validator library for vue.js
MIT License
293 stars 28 forks source link

validation status flags #53

Open sabob opened 5 years ago

sabob commented 5 years ago

Hi all,

I'm looking to implement validation feedback as follows:

  1. only show errors when input value has changed and focus is lost e.g user moves to the next field. 1.1. when user returns to the field feedback becomes instant 1.2. however, if users tab from field to field without editing, no errors are shown

Out of the box, simple vue validator seems to support either 1 or 1.1 depending on if the lazy modifier is used. But switching between lazy and instant doesn't seem possible.

Some validation libraries provide flags for each validation binding e.g. Vee Validate has these flags:

from https://baianat.github.io/vee-validate/guide/flags.html: touched: indicates that the field has been touched or focused. untouched: indicates that the field has not been touched nor focused. dirty: indicates that the field has been manipulated. pristine: indicates that the field has not been manipulated. valid: indicates that the field has passed the validation. invalid: indicates that the field has failed the validation. pending: indicates that the field validation is in progress. validated: indicates that the field has been validated at least once by an event or manually using validate() or validateAll(). changed: indicates that the field value has been changed (strict check).

With these type of flags one can implement the above validation pattern like this :

// Only show error if the field hasbeen modified and visited (focus lost)
methods: canShowError(name) {

  return validation.getField(name).flags.dirty &&
    validation.getField(name).flags.visited &&
    validation.getField(name).flags.invalid
}

<div class="message"v-if="canShowError('email')">
     <div class="message">{{ validation.firstError('email') }}</div>
</div>

What do you think?

Kind regards

Bob

tsongas commented 5 years ago

I'm searching for a validation library for Vue/Nuxt that will make it easy to accomplish what you describe. I was excited to see simple-vue-validator has three different Interaction Modes however none of them works in a way that is optimal for the user in my opinion.

The trouble with interactive + v-model:lazy is that when an error get displayed and the user fixes the error, the error message doesn't go away unless the user leaves the field. I think this makes for a more confusing experience than if error messages go away immediately as errors are fixed.

The trouble with conservative is that users don't see any errors until they try to submit the form. I think it is more convenient for the user to see an error immediately after changing a value, but not until they are done changing the value i.e. saying an email is invalid after the user types one letter is jarring and unhelpful...that's why I don't just use interactive.

Maybe there could be a fourth interaction mode to support this? Or maybe there is a way to do this now with simple-vue-validator using the ValidationBag instance and some combination of hasError/isPassed/isTouched? I'm not sure when ValidationBag gets updated....

tsongas commented 5 years ago

P.S. I tried Vee Validate but had multiple problems getting it to work including not being able to customize error messages, and not being able to get password confirmation validation working.

I have enjoyed using Formik with React as it gives a lot of control over when to show errors and disable the submit button, and someone has created https://github.com/blocka/vue-simpleform for Vue inspired by Formik, so maybe that would be an alternative library that could handle this?

semisleep commented 5 years ago

@sabob @tsongas I think what you guys want are reasonable, and "a fourth interaction mode" sounds like a good idea. However I don't have time to work on new features anymore (sorry about that).

So if you still want to use this library, you will have to detect whether you want validation or not by yourself, and store the value in data object (e.g. shouldValidateName), then implement cross field validation like this:

'shouldValidateName, name': function (shouldValidateName, name) {
        if (this.shouldValidateName || this.formSubmitted) {
          return Validator.value(name).required();
        }
      }