Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何使用Yup验证JSON对象数组的单个元素_Reactjs_Validation_Formik_Yup_Formik Material Ui - Fatal编程技术网

Reactjs 如何使用Yup验证JSON对象数组的单个元素

Reactjs 如何使用Yup验证JSON对象数组的单个元素,reactjs,validation,formik,yup,formik-material-ui,Reactjs,Validation,Formik,Yup,Formik Material Ui,我有一个JSON对象,它包含一个JSON对象数组。我需要的是2个数组元素(车辆),我只需要确保至少有一个数组元素填充了数据,即两个数组元素都不能为空。。请参阅下面的我的声明和我的Yum架构 const initialValues = { applicantID: "", applicantTypeID: "1", firstName: "", lastName: "", email: "

我有一个JSON对象,它包含一个JSON对象数组。我需要的是2个数组元素(车辆),我只需要确保至少有一个数组元素填充了数据,即两个数组元素都不能为空。。请参阅下面的我的声明和我的Yum架构

 const initialValues = {
  applicantID: "",
  applicantTypeID: "1",
  firstName: "",
  lastName: "",
  email: "user@abc.co",
  address1: "",
  address2: "",
  suburb: "",
  state: "AZ",
  postcode: "",
  phone: "",
  mobile: "",
  business_unit_school: "",
  building: "",
  level: "",
  room: "",
  applicationStatusID: "1",
  **vehicles: [
    { registrationNumber: "", make: "", model: "" },
    { registrationNumber: "", make: "", model: "" },
  ],**
  
};

const validationSchema = Yup.object({
  applicantID: Yup.string().required("Employee Number required."),
  firstName: Yup.string()
    .min(2, "Too Short!")
    .max(30, "Max 30 characters allowed.")
    .required("Firstname required."),
  lastName: Yup.string()
    .min(2, "Too Short!")
    .max(30, "Max 30 characters allowed.")
    .required("Lastname required."),
  email: Yup.string().email("Invalid email format").required("Email required."),
  address1: Yup.string()
    .min(2, "Too short.")
    .max(255, "Too Long!")
    .required("Address required."),
  address2: Yup.string().max(255, "Max 255 characters allowed."),
  suburb: Yup.string()
    .min(2, "Too Short!")
    .max(30, "Max 30 characters allowed.")
    .required("Suburb required."),
  state: Yup.string()
    .min(2, "Too Short!")
    .max(30, "Max 30 characters allowed.")
    .required("State required."),
  business_unit_school: Yup.string()
    .min(2, "Too Short!")
    .max(100, "Max 100 characters allowed.")
    .required("Business unit required."),
  **vehicles: Yup.array().of(
    Yup.object().shape({
      registrationNumber: Yup.string().required("Required"),
    })
  ),**
postcode: Yup.string().required("Postcode required."),
  phone: Yup.number()
    .required("Phone number required")
    .typeError("You must specify a number"),
  mobile: Yup.number().required("").typeError("You must specify a number"),
});
我的上述车辆验证工作,但它强制用户填写车辆下两个数组项的registrationNumber元素,这不是我想要的。任何帮助都将不胜感激。我也在下面试过,但不起作用

let vehicleschema = Yup.object({
  vehicles: Yup.array().of(
    Yup.object({
      registrationNumber: Yup.string().required("Required"),
      make: Yup.string().required("Required"),
    })
  ),
});

const validationSchema = Yup.object({
vehicles: vehicleschema.validateAt("vehicles[0].registrationNumber", initialValues)
}),
我得到以下验证错误

TypeError: field.resolve is not a function
(anonymous function)
node_modules/yup/es/object.js:146
  143 | 
  144 | innerOptions.path = makePath(_templateObject(), options.path, prop);
  145 | innerOptions.value = value[prop];
> 146 | field = field.resolve(innerOptions);
      | ^  147 | 
  148 | if (field._strip === true) {
  149 |   isChanged = isChanged || prop in value;
View compiled
ObjectSchema._cast
node_modules/yup/es/object.js:136
  133 | });
  134 | 
  135 | var isChanged = false;
> 136 | props.forEach(function (prop) {
      | ^  137 |   var field = fields[prop];
  138 |   var exists = has(value, prop);
  139 | 
好的,在使用下面Luis的解决方案之后,它似乎验证了注册号,尽管我现在得到了多个错误文本。我用的是Formik。。Formik代码如下所示

<Grid
              container
              item
              lg={12}
              md={12}
              xs={12}
              spacing={15}
              name="vehicles"
              style={{ marginBottom: "-4em" }}
            >
              <Box mx={3} my={2} textAlign="center">
                <h2>Vehicle Details</h2>
              </Box>
            </Grid>
            <Grid
              container
              item
              lg={12}
              md={12}
              xs={12}
              spacing={15}
              name="vehicles"
              style={{ marginBottom: "-4em" }}
            ></Grid>
            {initialValues.vehicles.map((vehicle, index) => (
              <Grid
                container
                item
                lg={10}
                md={12}
                xs={12}
                spacing={5}
                justify="space-between"
                className={classes.rowSpacing}
                key={index}
              >
                <Grid item lg={3} md={5} xs={12}>
                  <Field
                    component={TextField}
                    fullWidth={true}
                    label="Registration Number"
                    name={`vehicles[${index}].registrationNumber`}
                  />
                  <FormHelperText error>
                    <ErrorMessage name="vehicles" />
                  </FormHelperText>
                </Grid>

                <Grid item lg={2} md={5} xs={12}>
                  <Field
                    component={TextField}
                    fullWidth={true}
                    label="Make"
                    name={`vehicles[${index}].make`}
                  />
                </Grid>
                <Grid item lg={2} md={5} xs={12}>
                  <Field
                    component={TextField}
                    fullWidth={true}
                    label="Model"
                    name={`vehicles[${index}].model`}
                  />
                </Grid>
                <br />
              </Grid>
            ))}
          </Grid>
下面是我的更新代码

<Grid item lg={3} md={5} xs={12}>
                  <Field
                    //component={TextField}
                    fullWidth={true}
                    label="Registration Number"
                    name={`vehicles[${index}].registrationNumber`}
                    render={() => (
                      <muiTextField
                         error={Boolean(errors.vehicles)}
                         helperText= {
                            errors.vehicles && getVehiclesErrors(errors.vehicles)
                         }
                      />
                   )}
                  />
                  
                </Grid>

(
)}
/>
formik材质ui只是普通材质ui元素的包装。我很好奇为什么在getVehicleErrors()函数中有“email”引用。那是打字错误吗?在我更新代码(如上所述)后,这里的muiTextField指的是物料界面的TextField,现在我在我的表格上没有看到车辆登记字段。见下文

通过以下更改解决了此问题

    const getVehiclesErrors = (errors) => {
    return Array.isArray(errors)
      ? errors.filter((registrationNumber, i, arr) => arr.indexOf(registrationNumber) === i)
      : errors;
  }; 



<Grid item lg={3} md={5} xs={12}>
                      <Field
                        component={TextField}
                        fullWidth={true}
                        label="Registration Number"
                        name={`vehicles[${index}].registrationNumber`}
                      />
                      {errors.vehicles && touched.vehicles ? (
                        <div style={{ color: "red" }}>
                          {getVehiclesErrors(errors.vehicles)}
                        </div>
                      ) : null}
                    </Grid>
const getVehiclesErrors=(errors)=>{
返回数组.isArray(错误)
?错误。过滤器((注册号,i,arr)=>arr.indexOf(注册号)==i)
:错误;
}; 
{errors.vehicles&&toucted.vehicles(
{getVehiclesErrors(errors.vehicles)}
):null}

您可以这样做:

*我已经做了一个示例,其中数组中至少应该填充一个registrationNumber 对于您的车辆模式:

车辆:是的(
是的({
注册号:Yup.string(),
make:Yup.string().required(“make required”),
}).测试(
“注册号测试”,
//测试失败时应显示的错误消息
“至少应填写一个注册号”,
//函数,该函数对此数组执行自定义验证
验证以前的
)
)
下面的函数只是一个示例。你可以在这里做你自己的逻辑

function validateAgainstPrevious() {
  // In this case, parent is the entire array
  const { parent } = this;
  
  // filtered array vechicles that doens't have registrationNumber
  const filteredArray = parent.filter((e) => !e.registrationNumber);
  
  // If length of vehicles that doesn't have registrationNumber is equals to vehicles  array length then return false;
  if (filteredArray.length === parent.length) return false;

  return true;
}
已更新

对于多个错误文本问题,您可以采取以下解决方法:

而是将TextField组件传递给Field,如下所示:

<Field
   component={TextField}
   fullWidth={true}
   label="Registration Number"
   name={`vehicles[${index}].registrationNumber`}
/>

感谢@Luis提供的解决方案。您的解决方案不会正确验证注册号,尽管它不会显示错误消息“至少应填写一个注册号”。。我将Yup与Formik一起使用,在我输入至少一个注册号之前,可以看到“保存”按钮未启用,因此,逻辑是100%有效的。。现在只是错误消息部分的问题。您好@dev,您是如何使用formik的?你能用它更新问题吗?你是如何将错误设置成表格的?嗨@Luis,实际上这是我的错,忘记为注册号添加Formik错误标签,尽管现在错误文本在每个验证错误上出现两次。。请参阅下面我的Formik代码。。。我猜这种重复是由于它检查JSON对象的vehicles数组中的registration number元素的方式造成的。。我说得对吗?抱歉,代码文本太长,不允许我在此处发布,但添加的部分类似于ok@Luis我已使用Formik代码片段和屏幕图像更新了原始问题,以供您参考。嘿@Dev,我更新了答案,解决了您的多个错误文本问题。
<Field
   component={TextField}
   fullWidth={true}
   label="Registration Number"
   name={`vehicles[${index}].registrationNumber`}
/>
<Field
   // component={TextField}
   fullWidth={true}
   label="Registration Number"
   name={`vehicles[${index}].registrationNumber`}
   render={() => (
      <TextField
         error={Boolean(errors.vehicles)}
         helperText= {
            errors.vehicles && getVehiclesErrors(errors.vehicles)
         }
      />
   )}
/>
const getVehiclesErrors = (errors) => {
  return Array.isArray(errors)
    ? errors.filter((email, i, arr) => arr.indexOf(email) === i)
    : errors;
};