字段数组中的Formik验证

时间:2019-09-14 17:52:35

标签: reactjs formik

我有一个这样的表格:-

import Drawer from "components/atoms/Drawer";
/* import Input from "components/atoms/Input";
import InputGroup from "components/atoms/InputGroup";
import Label from "components/atoms/Label"; */
import Scrim from "components/atoms/Scrim";
import DrawerBody from "components/molecules/DrawerBody";
import { Field, FieldArray, Form, FormikErrors, FormikProps, withFormik } from "formik";
import { ITrackedPage } from "hocs/withAppDynamics";
import * as React from "react";
import { Box, Flex, Text } from "rebass";
import * as AmenitiesActions from "store/amenities/actions";
import { IAmenity, IAmenityRanking } from "store/amenities/models";
import DrawerHeader from "./DrawerHeader";
// import ErrorMessage from 'components/atoms/ErrorMessage';




interface IAmenitiesDrawerProps {
    drawerOpen: boolean;
    onDrawerClose: () => void;
    tenantAssessmentId: string;
    actions: typeof AmenitiesActions;
    maxRank?: number;
  }



interface IAmenitiesDrawerValues {
    amenitieslist: IAmenity[];
}

const InnerForm: React.FC<
IAmenitiesDrawerProps & ITrackedPage & FormikProps<IAmenitiesDrawerValues>
> = ({
  errors,
  drawerOpen,
  onDrawerClose,
  handleChange,
  values,
  setValues,
  isValid,
  tenantAssessmentId,
  sendAnalyticsData,
  actions
}) => {

  const handleDrawerClose = () => {
    onDrawerClose();
  };

  return (
    <>
      <Scrim isOpen={drawerOpen} onClose={handleDrawerClose} />
      <Drawer isOpen={drawerOpen} direction="right" drawerWidth="700px">
        <DrawerHeader handleCloseDrawer={handleDrawerClose} />
        <DrawerBody p={5}>
          <Flex mb={4}>
            <Box flex={1}>
              <Text fontWeight="light" fontSize={4} mt={3} mb={4}>
                Add custom amenities
              </Text>
            </Box>
          </Flex>
          <Form>
          <FieldArray
              name="amenitieslist"
              render={arrayHelpers => (
                <div>
                {// values.amenitieslist && values.amenitieslist.length > 0 ? (
                  values.amenitieslist.map((amenity, index) => (
                    <div key={index}>
                      <Field name={`amenitieslist.${index}.name`} />
                      <button
                        type="button"
                        onClick={() => arrayHelpers.remove(index)} // remove a amenity from the list
                      >
                        -
                      </button>
                      {errors.amenitieslist}
                    </div>
                  ))}
                  <button type="button" onClick={() => arrayHelpers.push({ id: "", name: "", imageUrl: '', description: '', tenantAssessmentId })}>
                    {/* show this when user has removed all amenities from the list */}
                    Add a Amenity
                  </button>
              </div>
            )}
            />
            <div>
                <button type="submit">Submit</button>
              </div>
    </Form>
        </DrawerBody>
      </Drawer>
    </>
  );
};

export const AmenitiesDrawer = withFormik<IAmenitiesDrawerProps, IAmenitiesDrawerValues>({
  enableReinitialize: true,
  handleSubmit: (values, {props}) => {
    const seed: number = props.maxRank? props.maxRank : 0;
    const amenityRankings: IAmenityRanking[] = values.amenitieslist.map((a, index)=>({
        amenityId: 1,
        rank: index + 1 + seed,
        amenityName: a.name,
        customAmenity: true
      }));
      console.log(amenityRankings);
      console.log(props.actions.customSaveAmenities);
      console.log(props.tenantAssessmentId);
      props.actions.customSaveAmenities(props.tenantAssessmentId, amenityRankings);
  },
  mapPropsToValues: ({tenantAssessmentId}) => ({
      amenitieslist:[{id: 0, name: '', imageUrl: '', description: '', tenantAssessmentId}]
  }),
  validate: values => {
    const errors: FormikErrors<{ validAmenity: string }> = {};
    console.log('In the Validate method');
    const { amenitieslist } = values;

    const amenityValid = amenitieslist[0].name.length < 28;
    if (!amenityValid) {
        console.log('Amenity is not valid');
      errors.validAmenity = "Amenity needs to be atmost 28 characters";
      console.log(errors);
    }

    return errors;
  }
})(InnerForm);

大家都可以看到我有文本输入。当长度超过28个字符时,我想在文本字段下方抛出错误消息。

这怎么可能?请帮我解决一下这个。

1 个答案:

答案 0 :(得分:0)

我发现验证Formik表单最方便的方法是按照文档中的建议使用yup。您可以定义一个验证模式,并将其作为道具传递给主要的Formik组件(或您正在使用的HOC),并删除自定义验证功能:

validationSchema: yup.object().shape({
  amenitieslist: yup.array()
    .of(yup.object().shape({
      name: yup.string().max(28, "Max 28 chars")
      // Rest of your amenities object properties
    }))
})

然后在您的FieldArray中:

<FieldArray
    name="amenitieslist"
    render={arrayHelpers => (
        <div>
          {// values.amenitieslist && values.amenitieslist.length > 0 ? (
            values.amenitieslist.map((amenity, index) => (
                <div key={index}>
                  <Field name={`amenitieslist[${index}].name`} />
                  <button
                      type="button"
                      onClick={() => arrayHelpers.remove(index)} // remove a amenity from the list
                  >
                    -
                  </button>
                  {errors.amenitieslist[index].name}
                </div>
            ))}
          <button type="button" onClick={() => arrayHelpers.push({ id: "", name: "", imageUrl: '', description: '', tenantAssessmentId })}>
            {/* show this when user has removed all amenities from the list */}
            Add a Amenity
          </button>
        </div>
    )}
/>

我只是更改了用于指定字段名称的访问器(要对数组元素使用索引,必须使用方括号表示法),并且在哪里可以找到错误,yup应该自动生成它们。很难确定我不会在不进行测试的情况下错过任何东西,希望这会有所帮助!