Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate on Blur, but validate correctly on input #1426

Closed
CephNightmare opened this issue Jun 25, 2018 · 19 comments · Fixed by #1911
Closed

Validate on Blur, but validate correctly on input #1426

CephNightmare opened this issue Jun 25, 2018 · 19 comments · Fixed by #1911
Labels
duplicate This issue or pull request already exists ✨ enhancement a "nice to have" feature 🛳 In PR This issue is being addressed in a PR request This issue is a request by its author

Comments

@CephNightmare
Copy link

CephNightmare commented Jun 25, 2018

Is your feature request related to a problem? Please describe.
Whenever using validate on blur, the user does not get feedback when re-entering the field, only after blurring.

Describe the solution you'd like
A good solution would be to always validate the input field, but only changing the state of the field when the field has been entered correctly to provide instant feedback when they correct their mistake.

An example flow would be for an input field with blur validation without the proposed:

  1. User enters input field with email incorrectly and blurs
  2. Validation fails
  3. User corrects mistake, but doesn't see their warning message dissapear.
  4. User blurs
  5. Validation succeeds

The preferred method would be:

  1. User enters input field with email incorrectly and blurs
  2. Validation fails
  3. User corrects mistake, and instantly sees when user has correctly fixed their mistake
@logaretm logaretm added ✨ enhancement a "nice to have" feature request This issue is a request by its author duplicate This issue or pull request already exists labels Jun 25, 2018
@Dylan-Chapman
Copy link
Contributor

Just a thought in terms of creating an API for this... when declaring your input events, you could do something like events: blur.input which would mean: validate on blur if the validated flag is false, and validate on input if the validated flag is true.

@logaretm
Copy link
Owner

logaretm commented Jun 26, 2018

@Dylan-Chapman Well that makes the API messier than I would like. I'm thinking about a new behavior feature, where you can define multiple strategies for validation behavior with listeners, for example:

const behaviors = ['eager', 'aggressive', 'none'];

Vue.use(VeeValidate, {
  behavior: 'eager' // if the field has an error and the user just entered a valid value, remove the error
});

I would call the requested behavior eager as in its eager for success status, while the default being aggressive. This is undoubtedly more complex than your suggestion and would require a small state machine implementation so users can make their own behaviors, but I like how the API is being defined in this case.

But there are issues with the concept itself, remote rules will always be executed in the background since the listeners will only control when to show the error rather than when to validate which is the current behavior.

@aldarund
Copy link
Contributor

aldarund commented Jul 5, 2018

That would be really great feature for user experience :)

@CephNightmare
Copy link
Author

CephNightmare commented Jul 6, 2018

@logaretm

Perhaps a solution would consist of something like this:

Vue.use(VeeValidate, {
            statusEvents: {
                'pristine': 'blur',
                'invalid': 'change',
                'valid': 'blur'
            }
        });

statusEvents (or something similar) indicates the behavior per state of a field, where you could add listeners, and change the validation method for the field.

Provides a lot of configuration for the user. This feature would be a great improvement for usability!

P.S. It's a great plugin as it is, by far the best form validation tool i've used, so thank you!

@Dylan-Chapman
Copy link
Contributor

I like the approach @CephNightmare mentioned. It's simple/intuitive and you can maintain backwards compatibility by just allowing events to optionally take a flag-keyed object, while falling back to an all-flags-based validation (when using a string value) like it does currently.

@erik-viking
Copy link

Just started using this plugin and this would be great to have! I really don't want to write any custom validation to perform this if it can be part of the API itself.

@jimmyhappy19920308
Copy link

jimmyhappy19920308 commented Nov 26, 2018

The following something work.

Vue.use(VeeValidate, {
  events: 'input|change|blur',
});

@tz136
Copy link

tz136 commented Jan 7, 2019

Did you add this feature? @logaretm

@logaretm
Copy link
Owner

logaretm commented Jan 7, 2019

@tz136 Still working on getting few things correctly before I get to this one, I have a working draft for the ValidationProvider component, but the directive would be very tricky to implement for (might require a re-write I have been planning for some time).

@FrancescoMussi
Copy link

Any update on this issue?

@aldarund
Copy link
Contributor

@logaretm any news or eta ? :)

@tsongas
Copy link

tsongas commented Feb 23, 2019

Also eagerly looking forward to this.

@logaretm
Copy link
Owner

@aldarund So far the proposed API is to allow a function to provide an object of options for each field after each validation/render cycle. I would call a function that does this a "strategy" similar to what passport is doing.

Anyways a validation strategy is able to provide a list of events that the next validation attempt should trigger on, along with a "debounce".

I only implemented it so far for the ValidationProvider component

<template>
  <ValidationProvider :strategy="myStrat">
  // ...
  </ValidationProvider>
</template>

<script>
export default {
  methods: {
    // strats will receive an object containing
    // useful contextual information about the field.
    // like the current errors, if its valid or not.
    // also the list of flags.
    myStrat ({ errors, valid, untouched }) {
      if (valid) {
       // must always return an object.
        return {
         events: ['blur']
        }; 
      }

      // must always return an object.
      return {
       events: ['input']
      };
    }
  }
};
</script>

This last example shows a strategy that validates on blur when the field is valid. But once the field becomes invalid It will validate on each input event until the field becomes valid again, so its "eager" for success, you could register it globally as well.

import { strategy } from 'vee-validate';

strategy('eager', ({ errors, valid, untouched }) => {
  if (valid) {
    return {
      events: ['blur']
    }; 

  // must always return an object.
  return {
   events: ['input']
  };
});

There are still issues to iron out like cross-field validation rules like confirmed and impure rules where the value doesn't necessarily correspond to a valid state or not at any point in time, think of uniq or Math.rand() > 0.5, also the events option will be useless after this feature as its just a static "strategy". I have to decide few policies on that to properly document them.

For the directive, it would probably follow a global config option. Still, The directive needs to be re-written to take advantage of re-renders. Otherwise, it would be hard to implement for it in the current codebase (lots of moving parts).

@tsongas
Copy link

tsongas commented Feb 27, 2019

@logaretm have you seen the simple-vue-validator Interaction Modes? http://simple-vue-validator.magictek.cn/#m_modes. Unfortunately it does not have a mode that works as desired here (see semisleep/simple-vue-validator#53) but it has at least formalized the idea of interaction modes plus implemented and documented some options.

@savehansson
Copy link

Anyways a validation strategy is able to provide a list of events that the next validation attempt should trigger on, along with a "debounce".

I only implemented it so far for the ValidationProvider component

This is exactly what I need in ValidationProvider. (Hoping for a release in a near future.)

@logaretm
Copy link
Owner

logaretm commented Mar 7, 2019

@tsongas I like the interaction mode concept as a replacement to the events configuration. This will be breaking change for all users but for the simplicity sake, I prefer users to be able to customize the events via one source only. So I will release a couple of intermediary releases deprecating the events option.

@savehansson I think I'm able to do a release in a few days with this feature implemented in ValidationProviders, It works fine so far in my tests. We just have to test it with my team to see if the whole thing "feels right".

@logaretm logaretm added the 🛳 In PR This issue is being addressed in a PR label Mar 10, 2019
@logaretm logaretm mentioned this issue Mar 10, 2019
2 tasks
logaretm added a commit that referenced this issue Mar 11, 2019
🔎 __Overview__

Checklist:
- [x] Implementation.
- [x] Docs.

This PR adds the ability to specify an interaction mode as formalized by [simple-vue-validator](http://simple-vue-validator.magictek.cn/#m_modes).

There are 4 modes implemented for you by default:

- aggressive: this is the default mode and it always validates on `input`.
- passive: doesn't validate on any event, so you can only validate manually.
- lazy: validate on `change`.
- eager: validates on `change` for the first time, then if the field is invalid it will validate on `input`. If the field turns valid again it will go back to validating on `change`. This was a popular request by many developers #1426.

You can customize the mode for each validation provider using the `mode` prop:

```vue
<ValidationProvider rules="required|email" mode="eager">
  <div slot-scope="{ errors }">
    <input v-model="val">
    <span>{{ errors[0] }}</span>
  </div>
</ValidationProvider>
```

The vee-validate plugin has a new method `setMode` which will be used to provide custom modes and changing the mode dynamically as needed.

```js
import VeeValidate from 'vee-validate';

// set all future providers default mode to passive.
// does not affect existing ones.
VeeValidate.setMode('passive');
```

An interaction mode in vee-validate is a function that receives a context similar to the slot-scope props which can be used to customize the behavior of the validation. The function should return an object containing:

- on: Array of event names as strings, those events will be used as triggers for validation.
- debounce: A number to control the validation trigger frequency.

Here is a small example:

```js
import VeeValidate from 'vee-validate';

VeeValidate.setMode('betterEager', ({ errors }) => {
   // Become slightly aggressive if the field is invalid.
  if (errors.length) {
    return {
      on: ['input'],
      debounce: 400
    };
  }

  // validate after 2 seconds of leaving the field 
  return {
    on: ['change'],
    debounce: 2000
  };
});
```

Currently, the mode receives an object with those properties:

- errors: List of error messages.
- flags: the field flag object.
- value: the last validated field value.

These properties may change in the future to make it more powerful. One thing is to make sure that the browser/components emit the configured events properly.

__This feature will deprecate the `events` config but it will remain with a deprecation warning for a couple of releases.__

✔ __Issues affected__

list of issues formatted like this:

closes #1426, closes #1488, closes #501
@savehansson
Copy link

When can we expect this to be released on npm?

@savehansson
Copy link

@ZacJoffe It's live since a couple of weeks:
Doc: https://baianat.github.io/vee-validate/guide/interaction.html

@luveqz
Copy link

luveqz commented Oct 7, 2022

Hi, @logaretm. Is there a Vee Validate 4 equivalent for the "eager" behavior?

Update: I just saw that there isn't and that there are no plans to add it right now. So I made a little workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists ✨ enhancement a "nice to have" feature 🛳 In PR This issue is being addressed in a PR request This issue is a request by its author
Projects
None yet
Development

Successfully merging a pull request may close this issue.