首页 > 解决方案 > 使用 Joi 和/或 Yup 进行模式验证,如果存在任何其他属性,是否有办法制作所需的属性集合?

问题描述

以收集个人详细信息的 HTML 表单为例。

样本表格

注意:代码片段已简化,与屏幕截图不完全匹配。此外,代码片段是使用 Yup 编写的,Yup 是一个与 Joi 非常相似的库,针对的是浏览器而不是 NodeJS。

为了提交表单,我想对地址字段进行验证并使其成为必需,但前提是用户已部分填写了地址部分。总的来说,我想让地址详细信息成为可选的。

这是我的 PersonSchema 的简化版本...

import { object, string, number } from 'yup'

const PersonSchema = object().shape({
  name: string().required(),
  age: number()
    .positive()
    .integer()
    .required(),
  address: AddressSchema
})

以这种方式定义 AddressSchema 不起作用,因为这些字段始终是必需的......

const AddressSchema = object().shape({
  street: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  city: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  state: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required()
})

这是我尝试使地址字段依赖于其他地址字段的存在,但这不起作用,因为您遇到了循环依赖问题......

const AddressSchema = object().shape({
  street: string()
    .when(['city', 'state'], {
      is: (city, state) => city || state,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    }),
  city: string()
    .when(['street', 'state'], {
      is: (street, state) => street || state,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    }),
  state: string()
    .when(['street', 'city'], {
      is: (street, city) => street || city,
      then: string()
        .min(2, 'Too Short!')
        .max(50, 'Too Long!')
        .required(),
      otherwise: string()
    })
})

标签: javascriptvalidationschemajoiyup

解决方案


我需要相同的可选地址检查:而不是根据每个其他地址字段检查每个字段,只需在您的表单/模式中设置一个名为“addressStarted”之类的标志,然后将其用作您的 when 触发器。就我而言,该标志是用户明确选择的,但它也可以很容易地成为隐藏值;只需在每个 onChange 处理程序中将值切换为 true (如果您使用的是 Formik 之类的东西),甚至只是一个包含所有地址字段的元素上的事件侦听器。

import { object, string, number } from 'yup'

const AddressSchema = object().shape({
  street: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  city: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required(),
  state: string()
    .min(2, 'Too Short!')
    .max(50, 'Too Long!')
    .required()
})

const PersonSchema = object().shape({
  name: string().required(),
  age: number()
    .positive()
    .integer()
    .required(),
  addressStarted: Yup.boolean(),
  address: object().when('addressStarted', {
    is: true,
    then: AddressSchema,
    otherwise: object().notRequired()
  }),
})


推荐阅读