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 }, {...
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();
});
}}
/>;
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})
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()
})