验证对象数组最多包含一个对象,其中属性=值

时间:2020-06-24 21:04:01

标签: reactjs formik yup

我正在使用Formik的FieldArray将对象动态添加到数组中,并在对象push()被添加到数组中时渲染其他表单元素。

我的架构如下:

const EMAIL_SCHEMA = Yup.object().shape({
  address: Yup.string().email().required( 'E-mail address is required.' ),
  isPreferredContact: Yup.boolean()
})

const SCHEMA = Yup.object().shape({
  emails: Yup.array()
             .of( EMAIL_SCHEMA )
             .ensure()
             .compact( v => !v.address )
             .required( 'At least one e-mail address is required.' )
})

对于每个电子邮件输入,都有一个对应的复选框,以指示它是否是首选的联系人电子邮件地址。不需要需要将电子邮件地址标记为首选。

我想做的是验证数组是否包含最多一个对象,其中isPreferredContacttrue。如果数组中有3个电子邮件对象,并且所有对象的isPreferredContactfalse,则为有效状态。就是说:

let values = [
  {address: '1@email.com', isPreferredContact: false},
  {address: '2@email.com', isPreferredContact: false},
  {address: '3@email.com', isPreferredContact: false}
] // OK

let values = [
  {address: '1@email.com', isPreferredContact: true},
  {address: '2@email.com', isPreferredContact: false},
  {address: '3@email.com', isPreferredContact: false}
] // OK

let values = [
  {address: '1@email.com', isPreferredContact: true},
  {address: '2@email.com', isPreferredContact: true},
  {address: '3@email.com', isPreferredContact: false}
] // Invalid

我看到了这个答案

Yup: deep validation in array of objects

显示compact()方法可用于验证至少一个,因为如果从数组中删除“虚假”值后,该数组为空,则很容易将模式密钥视为无效。

但是,对于验证数组最多包含一个具有property = value谓词的对象,我什么也看不到。

有没有办法做到这一点?

1 个答案:

答案 0 :(得分:2)

在GitHub上浏览Yup的问题,盯着API文档(addMethod的文档确实很糟糕),并在Code Sandbox中进行测试后,我发现这可行:

Yup.addMethod(Yup.array, 'atMostOne', function(args) {
  const { message, predicate } = args
  return this.test('atMostOne', message, function(list) {
    // If there are 2+ elements after filtering, we know atMostOne must be false.
    return list.filter(predicate).length < 2
  })
})

显然,谓词是一个函数,该函数接受数组的元素并对其执行测试,并返回boolean

对于标量值数组,这就像el => el === value一样简单。对于一组对象,它应该是el => el.property === valueel[property] === value

希望这可以帮助其他对此感到好奇的人。