semisleep / simple-vue-validator

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

ability to stop on first error #43

Open dasDaniel opened 6 years ago

dasDaniel commented 6 years ago

I'm using a combination of client and server side validation

a validator object may look like this:

validator: (value) => {
  return Validator
  .value(value)
  .required()
  .custom(() => {
     // my async validation
  })
}

the problem is that the async validation happens in parallel with the required() validator, meaning that I"m sending API requests even though i know they will fail.

Instead I end up implementing all the validations, such as required and min length, within the custom.

an option to have request run in series would help

debounce: 500, cache: true, sequntial: false|true ...

chip commented 6 years ago

Thanks so much for this repo.

I could really use this feature, too. 👍

@dasDaniel - How do you implement all those other validations within custom? I'm having trouble because Validator.value(value).email() returns a Rule object with only private properties. It would be great if a Rule had a boolean function that indicated if the rule passes or fails.

Thanks in advance for any suggestions.

dasDaniel commented 6 years ago

This is how I'm solving it I've got a validator class with my own validations that I call

        return Validator
          .value(value)
          .custom(() => {
            // step 1 - check format
            // validateEmail returns true if passed, message (String) if failed
            const localValidate = validateEmail(value);
            if (localValidate !== true) {
              return localValidate;
            }
            this.validatingEmail = true; // this adds a spinner icon and removes response
            // do async validation

the validation rule for email is

export function validateEmail(value) {
  if (value === null || value.trim() === '') {
    return 'This field cannot be blank';
  }
  const emailregex = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
  if (!emailregex.test(value)) {
    return 'Please enter a valid email';
  }
  return true;
}

but, obviously, this doesn't make use of built-in validations, hence having it stop on first fail would be helpful.

chip commented 6 years ago

@dasDaniel - Yeah, that's roughly the approach that I was thinking about implementing. Thanks so much for confirming your solution. 👍 Hopefully, your suggestion will get addressed at some point soon.

semisleep commented 6 years ago

@dasDaniel thank you for your solution 👍, following that direction, I updating the code a little bit, so that built-in validation rules can also be used. (please check out the new version 0.15.1)

  let validator = Validator.value(value).required();
  if (!validator.hasImmediateError()) {
   // skip the custom validation if there's already some errors
    validator.custom(() => {
       // my async validation
    })
  }
  return validator;
dasDaniel commented 6 years ago

could you provide an example of use with validators definition? I'll see if I can test and post example if I get to it.

semisleep commented 6 years ago

Sorry for the late reply, I thought I already posted the sample code, here's a more complete version of code:

validators: {
  email(value) {
    let validator = Validator.value(value).required().email();
    if (!validator.hasImmediateError()) {
     // skip the custom validation if email format is invalid
      validator.custom(() => {
         // ajax code to check if the email is already existed in backend
      })
    } 
    return validator;
  }
}

And the key is this hasImmediateError() method, which checks if there's any immediate error in current validator.