Debouncing Asynchronous tests via Yup
See original GitHub issueIs your feature request related to a problem? Please describe.
Just picked up vee-validate v4 for a Vue 3 application for work. I ran into my problem while trying to implement an email field with asynchronous validation towards our backend. I’m using the composition API functions useForm
and useField
to create custom field components and Yup to pass schemas for each field down to each field component. The schema for my email field looks like this:
email: string()
.test({
name: "uniqueEmailParent",
message: $t("EMAIL_IS_NOT_UNIQUE_ERROR"),
test: checkEmail,
exclusive: true
})
.label($t("EMAIL")),
And the test function for the field looks like this.
const checkEmail = async (value, testContext) => {
console.log("Checking email", value);
const schema = string()
.required()
.email();
try {
schema.validateSync(value);
} catch (err) {
/* Returns validation error message */
return err;
}
const response = await Registration.validateEmail(value);
console.log(response);
if (!response.valid) {
return testContext.createError({
message: $t("FIELD_IS_NOT_AN_EMAIL")
});
}
if (!response.available) {
return testContext.createError({
message: $t("EMAIL_IS_NOT_UNIQUE_ERROR")
});
}
return true;
};
First I tried to find a way to run the test function after required
and email
rules passed, but that didn’t work so I included the two rules inside the test function and stop the function upon failing those validations there. The scenario now is: if the value passes the required
and email
rules it sends request every time the value for the field updates.
Describe the solution you’d like
Is there any way to debounce the checkEmail function? Prevent the test rule to run until I stopped typing for 1000 milliseconds?
Describe alternatives you’ve considered
I tried using lodash
’s debounce function like this:
email: string()
.test({
name: "uniqueEmailParent",
message: $t("EMAIL_IS_NOT_UNIQUE_ERROR"),
test: debounce(checkEmail, 1000),
exclusive: true
})
.label($t("EMAIL")),
But considering the returned value is function the field doesn’t pass the validation, I’m guessing since it’s not any of the accepted return values true
, false
or ValidationError
.
If anything is poorly explained, let me know and I’ll do my best to explain further. Thank you for your efforts in this library.
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (3 by maintainers)
Thank you for your thorough explanation. I implemented a working solution using your example.
I don’t think this works as well as you think:
The way such
debounce
functions work is by returning a higher-order function (non-async) that returns mostlyundefined
, which is why I didn’t opt into time-based debouncing in the original example, the difference is that I explicitly return a promise that resolves after a set time.This means
await debounceValidation()
doesn’t wait for the validation to be done which explains why thepending
flag not changing, you can verify this by usingthen
instead of await and you will notice it crashes.