availity-reactstrap-validation icon indicating copy to clipboard operation
availity-reactstrap-validation copied to clipboard

"Short-circuit" validation

Open galacticglum opened this issue 6 years ago • 2 comments

Pretty much, I have a custom async validator that is used to check whether a user with the entered email already exists; however, I don't want to actually make the API call unless the email is valid (via the email validator).

In addition, I would like to only my the API call when the user is done typing; rather, than making an API call every time the input changes. However, I DO want the email and required validators to run whenever the input changes (as these are local and have little processing).

checkUserExists = _debounce((value, ctx, input, cb) => {
    if (!value || value === '') {
        cb(false);
        return;
    }
    clearTimeout(this.checkUserExistsTimeout);
    this.checkUserExistsTimeout = setTimeout(() => {
        this.props.userExists({['email']:value})
        .then(() => {
            cb('This email address is already taken.');
        }).catch(() => {
            cb(true);
        });
    }, 500);
});
// render
<BetterAvField type="email" groupAttrs={{ className: 'form-label-group' }}
    id="inputEmail" name="email"
    placeholder="Email Address" label="Email Address"
    validate={{
        required: {
            value: true,
            errorMessage: 'We need your email address.'
        },
        // run only when the user is done typing
        email: {
            value: true,
            errorMessage: 'That\'s not a valid email address.'
        },
        async: this.checkUserExists
    }} labelAfter />

galacticglum avatar Nov 29 '18 23:11 galacticglum

The validations are all done in parallel (async) and not in any specific order (though, it would probably end up being in the order of the keys defined on the validate prop object.) It's not a pipeline approach as it probably should have been (allowing for ordering and differentiating between local/sync and remote/async validation) In order to get what you want, you would need to import the email validation from the library and run it in your async validation function. Use debounce to avoid firing you function with every keystroke. You don't really need the timeout within the debounce.

import { debounce } from 'lodash';
import { AvValidator } from 'availity-reactstrap-validation';
//...
checkUserExists = debounce((value, ctx, input, cb) => {
  if(AvValidator.required(value) !== true || AvValidator.email(value) !== true) {
    cb(false);
    return;
  }
  this.props.userExists({['email']:value})
    .then(() => {
      cb('This email address is already taken.');
    }).catch(() => {
      cb(true);
    });
}, 500);

TheSharpieOne avatar Dec 01 '18 20:12 TheSharpieOne

Okay, thanks. I tried using denounce without the timeout and I had experienced a lot of lag when I was typing.

I'll try giving your solution a go and see whether it works!

galacticglum avatar Dec 01 '18 20:12 galacticglum