DEV Community

loading...
Cover image for How to validate two fields that depend on each other with Yup

How to validate two fields that depend on each other with Yup

gabrielterriaga profile image Gabriel Terriaga ・2 min read

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 😎

Discussion (0)

pic
Editor guide