jaredpalmer / formik

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

Validate on blur/change but only after the form has been submitted at least once. #3292

Open ybrodsky opened 3 years ago

ybrodsky commented 3 years ago

Feature request

Current Behavior

Right now you have the option to set validateOnBlur. When using this in combination with the handler handleBlur whenever you blur out of a field the validations are run. However this causes some thing that looks weird: imagine you have a form with 10 fields. You click the first field, write, go to the next field and instantly the whole form is validated. You get error messages for fields which you still haven't touched. Looks weird.

Desired Behavior

Would be nice that the fields validate on blur only after a form has been submitted. For example: You clock the first field, write. Click submit. The form validation runs and you get the error for invalid fields. You click on an invalid field, complete it and blur out of it. The form is re-validated.

Suggested Solution

Might be good to have an extra option that let's you decide whether or not you want to validate on blur only after the form has been submitted at least once. validateOnBlurAfterSubmittion: true | validateOnChangeAfterSubmittion: true. There's a prop that formik exposes submitCount. I am doing a hand-made hack to only validate on blur when submitCount > 0. I guess you could do something like that internally.

Who does this impact? Who is this for?

This impacts every form that needs to validate on blur on certain conditions. Imagine a login form. You complete the email, when you go to the password field the field has an error. Why? I still havent done anything in that field, I got no chance. The more fields the form has the weirder it looks

Describe alternatives you've considered

No alternatives I have seen other than doing some sort of hack.

grunklejp commented 2 years ago

You get error messages for fields which you still haven't touched. Looks weird.

You can render the error message only when the field is touched. See: https://formik.org/docs/tutorial#visited-fields

ybrodsky commented 2 years ago

Doesnt change the fact that the validation will be running a lot of times without purpose. Specially if you have validateOnChange.

This is how I fixed it. "Fixed"

export const useFormik = (props) => {
  const [submitted, setSubmitted] = React.useState(false);

  const formik = useFormikOriginal({
    ...props,
    validateOnChange: submitted,
    validateOnBlur: submitted,
  });

  React.useEffect(() => {
    if (formik.submitCount > 0) {
      setSubmitted(true);
    }
  }, [formik.submitCount]);

  return formik;
};

🤷

lid3rs commented 1 year ago

Same issue. UP!

luisgustavolf commented 3 weeks ago

Doesnt change the fact that the validation will be running a lot of times without purpose. Specially if you have validateOnChange.

This is how I fixed it. "Fixed"

export const useFormik = (props) => {
  const [submitted, setSubmitted] = React.useState(false);

  const formik = useFormikOriginal({
    ...props,
    validateOnChange: submitted,
    validateOnBlur: submitted,
  });

  React.useEffect(() => {
    if (formik.submitCount > 0) {
      setSubmitted(true);
    }
  }, [formik.submitCount]);

  return formik;
};

🤷

Just complementing if you want to make it typed for TS usage:

import { FormikConfig, FormikValues, useFormik } from "formik"
import { useEffect, useState } from "react";

export function useEnhancedFormik<Values extends FormikValues = FormikValues>(props: FormikConfig<Values>) {
  const [shouldValidate, setShouldValidate] = useState(false);

  const form = useFormik({
    validateOnBlur: shouldValidate,
    validateOnChange: shouldValidate,
    ...props
  })

  useEffect(() => {
    if (form.submitCount > 0) {
      setShouldValidate(true);
    }
  }, [form.submitCount]);

  return form
}

Just a small update to your suggestion: place validateOnBlur and validateOnChange above props. This way, if the user needs to activate this behavior for any reason, their configuration will take priority.