Yup:数组对象深度验证

54

我有一个这样的数据结构:

{
  "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
}

daysOfWeek 中,我希望确保至少有一项具有 checked: true

这是迄今为止的验证模式(但不起作用):

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(),
})

有没有可能验证 daysOfWeek 的值,并确保其中至少有一个值的 checked: true

6个回答

58

我使用compact()(过滤掉错误的值)以及在FieldArray修改器函数之后使用setTimeout来解决这个问题:

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

并且以表单的形式呈现:

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

setTimeout 这个东西真是让我开心极了 :-) 使用 arrayHelper 时出现了非常奇怪的行为。非常感谢。 - Klaus
1
我该如何在 when() 条件中引用(例如)description,并将其应用于(例如)dayOfWeek?基本上... dayOfWeek: Yup.string().when("description", {is: ..., then: ...} 但是它无法从数组内部工作。 - KaMZaTa
如果您使用compact(),表单数据也会被过滤。这意味着在验证后的表单数据中,数组将只包含真值。解决方案是使用test()进行自定义验证。test('atLeastOne', '错误消息', days => days.some(day => day.checked)) - SajithK

13
基于 @olefrank 的回答。这段代码在我的情况下可以工作。
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(),
});

4

我在我的Node.js(Express.js)项目中完成了这种类型的验证。你可以尝试按照这种方式进行验证。

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()
    })
  )
})

3
如果您正在使用最新版本,则应该这样使用: Yup.array().min(1, "至少需要一个选项").required(),其中“至少需要一个选项”是必填项的错误信息。

2
在我的情况下,我使用了 Formik 和 Yup 来完成这个任务。
我想仅选择一个数组中的值,如果未选择,则需要显示错误信息。
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})

它对我有效

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

这是在描述您遇到的问题/错误并需要帮助吗?还是在感谢现有答案中提出的建议解决方案?或者,您应该根据答案和https://stackoverflow.com/editing-help进行编辑,以更明显地表明您正在尝试贡献解决方案? - Yunnosch

0

我之前做过类似的验证。你可以尝试这种方法。

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()
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接