简体   繁体   中英

Using nested object names in formik/<ErrorMessage/>

Formik's documentation states you can use a lodash type dot path to name/access nested objects (eg name.firstName ). This is also supposed to apply to it's built in <ErrorMessage/> component. I was working with a React-Typescript tutorial app that uses formik for form inputs and it seemed to work fine under the hood when paired with backend code, but I did notice that the fields that fed nested object values would not throw any errors in the UI. The error itself would be generated, but the <ErrorMessage/> component didn't seem to want to render.

A pared down version of the app is below. The "Field is Required" error should be thrown if you exit a form field without a valid input but again it doesn't work for the nested object fields (first/last name). I was wondering if anyone else has run across this issue. It's a little annoying.

I've seen that formik seems to be paired frequently with Yup for validation, which may make this issue moot, but I haven't gotten quite that far yet. Thanks!

import React from 'react';
import ReactDOM from 'react-dom';

import { ErrorMessage, Field, FieldProps, Formik } from "formik";
import { Form, Button } from "semantic-ui-react";

interface TextProps extends FieldProps {
  label: string;
  placeholder: string;
}

const TextField: React.FC<TextProps> = ({
  field, label, placeholder
}) => (
  <Form.Field>
    <label>{label}</label>
    <Field placeholder={placeholder} {...field} />
    <div style={{ color: "red" }}>
      <ErrorMessage name={field.name} />
    </div>
  </Form.Field>
);

const App: React.FC = () => {

  return (
    <Formik 
    initialValues={{
      name: {
        firstName: "",
        lastName: ""
      },
      job: "",
    }}
    onSubmit={()=>console.log("submitted")}

    validate={values => {
      const requiredError = "Field is required";
      const errors: { [field: string]: string } = {};
      if (!values.name.firstName) {
        errors["name.firstName"] = requiredError;
      }
      if (!values.name.lastName) {
        errors["name.lastName"] = requiredError;
      }
      if (!values.job) {
        errors["job"] = requiredError;
      }
      return errors;
    }}
    >
    {({ isValid, dirty}) => {
      return (
      <Form>
        <Field label="First Name" name="name.firstName" component={TextField} />
        <Field label="Last Name" name="name.lastName" component={TextField} />
        <Field label="Job" name="job" component={TextField} />

        <Button type="submit" disabled={!dirty || !isValid}> Add</Button>
      </Form>
      );
    }}
    </Formik>
  );
};

Have you tried using formik's inbuilt function getIn()? It is used to extract values from deeply nested objects. Check this Q&A

Try changing validate function to this

validate={values => {
  const requiredError = "Field is required";
  const errors: any = {name: {}};
  if (!values.name.firstName) {
    errors.name.firstName = requiredError;
  }
  if (!values.name.lastName) {
    errors.name.lastName = requiredError;
  }
  if (!values.job) {
    errors["job"] = requiredError;
  }
  return errors;
}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM