'(Yup) how to create multiple errors using a single .test() function
EDIT: while the accepted solution worked, this worked much better in my use case
I have one function that validates that neither input field A nor input field B are empty and with the way my form is built I have to write only one function to check both. (The actual function is much more complicated so I opted to create the example function below)
this is my test function:
function isValid(message) {
//I don't use the message variable but I added it anyway
return this.test("isValid", message, function (value) {
if(!value.A) {
return createError({path: `${this.path}.A`, message:"A is empty"});
}
if(!value.B) {
return createError({path: `${this.path}.B`, message:"B is empty"});
}
return true;
})
The result of this is that when A and B are empty I return the first createError so the rest of the function is skipped and this is what the formik.errors object looks like:
{
parent: {
A: "A is empty"
}
}
How do I create an array of errors and return it instead?
I tried:
returning an array of createErrors() but I got the same result,
using createErrors with an array of paths and messages but the formik.errors looked like this:
{
parent.A: { parent.B: "2 errors occured" }
}
instead of the desired:
{
parent: {
a: "A is empty",
b: "B is empty"
}
}
Solution 1:[1]
You can use ValidationError
from Yup
to achieve this goal. The constructor of ValidationError
accepts array of other ValidationError
instances. The individual ValidationError
instances are capable of holding path
and error message and the parent instance will combine them.
Here's the example test function:
import { ValidationError } from 'yup'
const testFunc = (value) => {
const keys = ['A', 'B']
const errors = keys.map((key) => {
if (value[key]) { return null } // Successful validation, no error
return new ValidationError(
`${key} is empty`,
value[key],
key
)
}).filter(Boolean)
if (errors.length === 0) { return true }
return new ValidationError(errors)
}
It is also possible to do the same thing with createError
judging by the source code.
You can pass a function instead of a string to message
property of createError
call. In this case the function would be called within createError
=> ValidationError.formatError
here. And if this function returned an array of the properly built VaildationError
instances we would get the same result.
Here's an example test function for that approach:
import { ValidationError } from 'yup'
const testFunc = (value, { createError }) => {
const keys = ['A', 'B']
const errors = keys.map((key) => {
if (value[key]) { return null } // Successful validation, no error
return new ValidationError(
`${key} is empty`,
value[key],
key
)
}).filter(Boolean)
if (errors.length === 0) { return true }
return createError({
message: () => errors
})
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | senya |