jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.98k stars 2.79k forks source link

"validateForm is not a function" #1066

Closed man1cato closed 6 years ago

man1cato commented 6 years ago

🐛 Bug report

Current Behavior

I'm attempting to create a multi-page form and want to be able to run validation between each page. When attempting to do this using the manual validation method, I get the error: "validateForm is not a function"

Expected behavior

Upon clicking the button, the form should run the validation.

Reproducible example

https://codesandbox.io/s/03mo7606zw

Your environment

Software Version(s)
Formik 1.3.0
React 16.1.0
Browser Chrome v70
Yarn 1.10.1
Operating System Windows 10 x64
dylangarcia commented 6 years ago

validateForm is not a function because Formik passes the FormikProps as a render prop.

You need to destructure the render prop to get validateForm out of it, see https://codesandbox.io/s/qlnpwqywmw for a working example.

<Formik
  initialValues={{ name: "" }}
  validationSchema={validationSchema}
>
  {({ validateForm }) => (
    <Form>
      <div>
        <div>
          <Field name="name" placeholder="Name" />
        </div>
        <ErrorMessage name="name" />
      </div>
      <button
        type="button"
        onClick={() =>
          validateForm().then(() => console.log("validated!"))
        }
      >
        Next
      </button>
    </Form>
  )}
</Formik>

See more at https://github.com/jaredpalmer/formik/blob/master/docs/api/formik.md#children-func

man1cato commented 6 years ago

Ok, so while I definitely feel stupid for not catching that, why doesn't the error message for the empty name field trigger when the button is clicked?

dylangarcia commented 6 years ago

Ok, so while I definitely feel stupid for not catching that, why doesn't the error message for the empty name field trigger when the button is clicked?

https://codesandbox.io/s/qlnpwqywmw

validateForm() returns a Promise that resolves in to an errors object. Click the button and you can see the error message in the console.

man1cato commented 6 years ago

Ok, so while I definitely feel stupid for not catching that, why doesn't the error message for the empty name field trigger when the button is clicked?

https://codesandbox.io/s/qlnpwqywmw

validateForm() returns a Promise that resolves in to an errors object. Click the button and you can see the error message in the console.

Right, but isn't the whole point of this method to trigger all the ErrorMessage components in the form? At least, that's what I concluded from reading the documentation.

dylangarcia commented 6 years ago

Ok, so while I definitely feel stupid for not catching that, why doesn't the error message for the empty name field trigger when the button is clicked?

https://codesandbox.io/s/qlnpwqywmw validateForm() returns a Promise that resolves in to an errors object. Click the button and you can see the error message in the console.

Right, but isn't the whole point of this method to trigger all the ErrorMessage components in the form? At least, that's what I concluded from reading the documentation.

ErrorMessage components are triggered after an error occurs and the element has been touched. Click the textbox in the codesandbox I posted, type one character, then click away.

man1cato commented 6 years ago

Ok, so while I definitely feel stupid for not catching that, why doesn't the error message for the empty name field trigger when the button is clicked?

https://codesandbox.io/s/qlnpwqywmw validateForm() returns a Promise that resolves in to an errors object. Click the button and you can see the error message in the console.

Right, but isn't the whole point of this method to trigger all the ErrorMessage components in the form? At least, that's what I concluded from reading the documentation.

ErrorMessage components are triggered after an error occurs and the element has been touched. Click the textbox in the codesandbox I posted, type one character, then click away.

Right, so then it's not possible to trigger them using validateForm and I gotta figure out another solution. Thanks.

graysonhicks commented 5 years ago

@man1cato I am working with the same issue. I feel the expected behavior is to validate in the same way as when submitting, not just a 'silent' validation that doesn't display the error messages. Did you come up with a solution you were happy with?

Right now, I am leaning towards somehow using the errors object from validateForm to manually display the error messages based on what my active step of the form is. I feel like this goes against the ease of validation using a Yup validationSchema so would love to know if anyone has a better solution.

Thanks.

brendengifford commented 5 years ago

@man1cato @graysonhicks I'm not sure if this is the right way to do this, but I think I got your expected behavior by passing the validation into setTouched.

See this fork of your sandbox https://codesandbox.io/s/7o2q7164x0

omonk commented 5 years ago
setFieldError('sets[0].rows[0].condition', 'condition error');
setFieldTouched('sets[0].rows[0].condition', true, false);

This is something I'm up against at the moment. I'm using nested FieldArrays (sets[] and rows[]) which I'm able to validate perfectly fine with Yup but displaying any sort of error messaging to the UI is cumbersome.

values: {
    sets: [
        {
          rows: [....]
        },
        {
         rows: [....]
        }
   ]
}

It would be great if you could do validateForm({setErrors: true}) instead of having to iterate over the error response from validateForm and setting errors and touched manually with setFieldError and setFieldTouched