How to validate two fields that depend on each other with Yup
Gabriel Terriaga
Posted on October 1, 2020
Hey guys, let's get straight to the point, I'll show you how to Yup validate two fields that depend on each other.
You may have faced this problem already. If not, you'll face it.
Here is an example of what will happen:
const yup = require('yup')
const {
setLocale
} = yup
setLocale({
mixed: {
notType: 'the ${path} is obligatory',
required: 'the field ${path} is obligatory',
oneOf: 'the field ${path} must have one of the following values: ${values}'
}
})
const myNameSchema = yup.object().shape({
first_name: yup.string().ensure().when('surname', {
is: '',
then: yup.string().required()
}),
surname: yup.string().ensure().when('first_name', {
is: '',
then: yup.string().required()
})
})
[...]
Error: Cyclic dependency, node was:"surname"
at visit (/home/{yourPath}/node_modules/toposort/index.js:45:13)
at visit (/home/{yourPath}/node_modules/toposort/index.js:62:9)
at visit (/home/{yourPath}/node_modules/toposort/index.js:62:9)
at Function.toposort [as array]...
Cyclic error, but how are we going to solve this?
Fields that depend on each other to be validated need to sorted so they are "constructed" in the correct order, e.g. if depend on field A
in field B
, you needs to cast and coerce the value in field A
before it's handed to B
.
What is happening here is that we are just adding a validation to the condition, so there is really no need to request anything for the validation to happen after everything is constructed already. Due to the flexibility and programmatic nature of Yup it can't distinguish between those two cases.
Solution:
const yup = require('yup')
const {
setLocale
} = yup
setLocale({
mixed: {
notType: 'the ${path} is obligatory',
required: 'the field ${path} is obligatory',
oneOf: 'the field ${path} must have one of the following values: ${values}'
}
})
const myNameSchema = yup.object().shape({
first_name: yup.string().ensure().when('surname', {
is: '',
then: yup.string().required()
}),
surname: yup.string().ensure().when('first_name', {
is: '',
then: yup.string().required()
})
}, [['surname', 'first_name']]) // <--- adding your fields which need validation
[...]
{
"message": "there was an error validating data",
"error": [
"the field first_name is obligatory",
"the field surname is obligatory"
]
}
Another example with extra fields:
[...]
const myNameSchema = yup.object().shape({
first_name: yup.string().when(['surname', 'age'], {
is: (surname, age) => !surname && !age,
then: yup.string().required()
}),
surname: yup.string().when(['first_name', 'age'], {
is: (first_name, age) => !first_name && !age,
then: yup.string().required()
}),
age: yup.number().when(['first_name', 'surname'], {
is: (first_name, surname) => !first_name && !surname,
then: yup.number().required()
})
}, [
['first_name', 'surname'], // <--- adding your fields which need validation
['first_name', 'age'],
['surname', 'age']
])
[...]
{
"message": "there was an error validating data",
"error": [
"the field first_name is obligatory",
"the field surname is obligatory",
"the field age is obligatory"
]
}
I hope I helped you! 😉
Thank you!!
My GitHub 😎
Posted on October 1, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.