ZingB

Yup: deep validation in array of objects

I have a data structure like this:

{ "subject": "Ah yeah", "description": "Jeg siger...", "daysOfWeek": [ { "dayOfWeek": "MONDAY", "checked": false }, { "dayOfWeek": "TUESDAY", "checked": false }, { "dayOfWeek": "WEDNESDAY", "checked": true }, { "dayOfWeek": "THURSDAY", "checked": false }, { "dayOfWeek": "FRIDAY", "checked": false }, { "dayOfWeek": "SATURDAY", "checked": true }, { "dayOfWeek": "SUNDAY", "checked": true } ], "uuid": "da8f56a2-625f-400d-800d-c975bead0cff", "taskSchedules": [], "isInitial": false, "hasChanged": false } 

In daysOfWeek I want to ensure that at least one of the items has checked: true.

This is my validation schema so far (but not working):

const taskValidationSchema = Yup.object().shape({ subject: Yup.string().required('Required'), description: Yup.string(), daysOfWeek: Yup.array() .of( Yup.object().shape({ dayOfWeek: Yup.string(), checked: Yup.boolean(), }) ) .required('Required'), taskSchedules: Yup.array(), }) 

Is it possible to validate the values of daysOfWeek ensuring that at least one of them has checked: true?

6 Answers

I solved it using compact() (filtering out falsely values) together with setTimeout after the FieldArray modifier function:

const validationSchema = Yup.object().shape({ subject: Yup.string().required(i18n.t('required-field')), description: Yup.string(), daysOfWeek: Yup.array() .of( Yup.object().shape({ dayOfWeek: Yup.string(), checked: Yup.boolean(), }) ) .compact((v) => !v.checked) .required(i18n.t('required-field')), taskSchedules: Yup.array(), }); 

And in form:

<Checkbox value={day.dayOfWeek} checked={day.checked} onChange={(e) => { replace(idx, { ...day, checked: !day.checked }); setTimeout(() => { validateForm(); }); }} />; 
3

Base on @olefrank's answer. This code work with me.

const validationSchema = Yup.object().shape({ subject: Yup.string().required(i18n.t('required-field')), description: Yup.string(), daysOfWeek: Yup.array() .of( Yup.object().shape({ dayOfWeek: Yup.string(), checked: Yup.boolean(), }) ) .compact((v) => !v.checked) .min(1, i18n.t('required-field')), // <– `.min(1)` instead of `.required()` taskSchedules: Yup.array(), }); 

I have done this type of validation in my Node.js(Express.js) project. You can try validation in this way.

const validationSchema = yup.object({ subject: yup.string().required(), description: yup.string().required(), daysOfWeek: yup.array( yup.object({ dayOfWeek: yup.string().required(), checked: yup.boolean().required() }) ) }) 

If you trying in latest version it should be used like this Yup.array().min(1, "At least one option is required").required()

In my case I have used formik with yup for this,

I want to select only one value in an array if not selected I need to display the error

array = [{"label": "Option 1", "selected": false, "value": "option-1"}, {"label": "Option 2", "selected": false, "value": "option-2"}, {"label": "Option 3", "selected": false, "value": "option-3"}] Yup.mixed().test({ message: 'Required',test: val => val.filter(i => i.selected === true).length === 1}) 

it worked for me

Yup.mixed().test({ message: 'Required',test: val => val.filter(i => i.selected === true).length !== 0}) 
1

I did a similar validation like this. You can try this approach

const schema = yup.object().shape({ subject: yup.string().required(), description: yup.string() daysOfWeek: yup.array().of( yup.lazy(value => { const { checked } = value // Get the value of checked field return checked ? yup.object().shape({ dayOfWeek: yup.string().required(), // validate only if checked is true checked: yup.boolean() }) : yup.object().shape({ dayOfWeek: yup.string(), checked: yup.boolean() }) }) ), taskSchedules: yup.array() }) 

ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJobHJpaWyCdn2OsqypZZSasrF51ZqjopyRqbawuoyipWaZoqeuunnOn2SompqasLW%2F

Arica Deslauriers

Update: 2024-05-18