This question is over a month old when writing this answer, but maybe it could help someone or at least point them in the right direction.
I had the Cyclic issue, but I had three fields. I wanted either non of the fields to be entered, or all three must be required.
This link: https://github.com/jquense/yup/issues/176#issuecomment-369925782 helped but did not work for me. But after a few tweaks, I made it work; here is what worked for me.
const SettingsSchema = Yup.object().shape({
password: Yup.string().ensure()
.when(['new_password', 'confirm_password'], {
is: (new_password, confirm_password) => new_password !== '' || confirm_password !== '',
then: (SettingsSchema) => SettingsSchema.required(t('Password is required.')),
}),
new_password: Yup.string().ensure()
.when(['password', 'confirm_password'], {
is: (password, confirm_password) => password !== '' || confirm_password !== '',
then: (SettingsSchema) => SettingsSchema.required(t('New Password is required.'))
.min(8, t('Password cannot be shorted than 8 characters.')),
}),
confirm_password: Yup.string().ensure()
.when(['password', 'new_password'], {
is: (password, new_password) => password !== '' || new_password !== '',
then: (SettingsSchema) => SettingsSchema.required(t('Confirm Password is required.'))
.oneOf([Yup.ref('new_password')], t('New Password and Confirm Password must match.')),
}),
}, [['password', 'new_password'], ['password', 'confirm_password'], ['new_password', 'confirm_password']]);
What was required to remove the cyclic error and make the validation work was:
- The last parameter of
shape it's an array containing arrays of pairs.
The documentation on that part is not very clear at the time of writing. https://github.com/jquense/yup#objectshapefields-object-nosortedges-arraystring-string-schema
Things to note:
- On each field, I call
.ensure(). This ensures that if values are undefined or null, they will be transformed into empty strings.
- Because you have four fields, you will need an extra pair in the array of pairs of fields as the last parameter of
shape.
So I think your example above could be rewritten as:
const schema = Yup.object().shape({
field1: Yup.mixed().ensure().when(["field2", "field3", "field4"], {
is: (field2, field3, field4) => field2 !== '' || field3 !== '' || field4 !== '',
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired()
}),
field2: Yup.mixed().ensure().when(["field1", "field3", "field4"], {
is: (field1, field3, field4) => field1 !== '' || field3 !== '' || field4 !== '',
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired(),
}),
field3: Yup.mixed().ensure().when(["field1", "field2", "field4"], {
is: (field1, field2, field4) => field1 !== '' || field2 !== '' || field4 !== '',
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired(),
}),
field4: Yup.mixed().ensure().when(["field1", "field2", "field3"], {
is: (field1, field2, field3) => field1 !== '' || field2 !== '' || field3 !== '',
then: (schema) => schema.required(),
otherwise: (schema) => schema.notRequired(),
})
}, [["field1", "field2"], ["field2", "field3"], ["field3", "field4"], ["field1", "field4"]]);
I know the example with three fields works as I am using it in my code. The example with four parameters is derived from the example of three parameters and I did not test it so I am not sure is totally correct.