formik: Initial validation or initialErrors prop

What if the user has set some field values, and we do store them somewhere, and when the user returns to the app those values are invalid. Is there no way to run validate on initialization?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 23
  • Comments: 50 (13 by maintainers)

Most upvoted comments

+1 for this use case.

I would like to display validation errors & disable form submission for a record that is already persisted, and will now be newly invalid based on some recent changes in the underlying business logic.

So I would like the initial form load to reflect this, but ran into the same issue where the validator function is not run until some field is touched. This has the effect of leaving the form’s submit button initially enabled for what we consider to be an invalid record.

For now I am working around this by moving logic out of the validator function and into various form components, which seems a shame given all the wins we’ve enjoyed by relying on Formik’s awesome default behavior so far.

I think initialErrors makes a lot of sense. Feel free to submit a PR. It should be almost identical to initialValues.

 <Formik
      initialValues={{text: '', password: '', active: ''}}
      onSubmit={values => {
        console.log(values);
      }}
      validateOnMount={true}
      validationSchema={signInSchema}>

Use this for validating initial values

validateOnMount={true}

@anandaroop The workaround that I am using is to call this.refs.formikForm.getFormikBag().validateForm() in the parent’s componentDidMount method.

The solution to initial validation on load is quite simple:

in your form component, the one which is wrapped into withFormik or Formik (I’ve tested with the latter) add:

  componentDidMount() {
    const { isValid, validateForm } = this.props;

    if (!isValid) {
      validateForm();
    }
  }

What about the update form where the initial values are loaded from redux state using mapPropsToValues and enableReinitialize: true?? How will you initially validate the form in that case?

OLD and obsolete, ignore. For anyone coming from Google Search, until this functionality will be built in, use this:
class ParentComponent extends Component {
    constructor(props) {
         super(props);
         this.form = React.createRef();
    }

    componentDidMount() {
        // runs "on load" and validates the form immediately with the initialValues
        this.form.current.validateForm();
    }

    render() {
        <Formik
            // other props...
            ref={this.form}
        >
            // children...
        </Formik>
    }
}

This is for pretty basic usage…if you actually need to check validity on init and also “trick” your app into believing that the form was filled in, focused and blurred, look at this comment.

If you just need to control the “disable” prop of a submit button, my solution works just fine.

If you’re using React >= 16.8, you can do the above with useRef and useEffect:

const form = useRef();
useEffect(() => {
  if (form.current) {
    form.current.getFormikActions().validateForm();
  }
});
return <Formik ref={form} ...

validateOnMount={true} still doesn’t work for me. I have updated to version 2.1.5.

Use case: I have some initial values for the form, but the form is not validated on mount. So the isValid is false for this case and I have disabled the submit button, but since the errors are not shown for the initial values on the field unless onBlur() is triggered on each field the user doesn’t know why the submit button is disabled.

A work around for this (for eg the phone number field is): useEffect(() => { values.phone && setFieldTouched(“phone”); }, []); But I don’t want to do it for all the fields. Does anyone know how to fix this?

I’ve also encountered a use-case for this, where a form is persisted, even in an invalid state, since it is shared between multiple users and takes time to complete.

I would like the form to be validated immediately on initialization, so that its isValid and errors are correctly populated at all times.

I really don’t see why the form’s ‘validation state’ shouldn’t reflect its values at all times.

If it’s not appropriate to show validation errors for whatever reason, then I think of this a display problem, not a validation problem.

The tricky thing is with keeping formik compatible with SSR. You can set the initial validity using isInitialValid

What about the errors equivalent of isInitialValid? Like initialErrors?

I guess I’m trying to ask you if you agree there is a use case. Because if there is, I’m sure there’s a way to do it.

calling validateForm on mount is not working for me at all. tried setFieldTouched as well.

validate is called when validateForm is called, and it’s returning the errors object. do I just need to set the error manually as well?

Added initialErrors v2 #1626

If you’re using React >= 16.8, you can do the above with useRef and useEffect:

const form = useRef();
useEffect(() => {
  if (form.current) {
    form.current.getFormikActions().validateForm();
  }
});
return <Formik ref={form} ...

React >= 16.8 useEffect and useRef worked for me …

@jaredpalmer Does that mean that #622 won’t be merged in prior to a v2 release? Do you have a recommended temp fix in the meantime? There are several options people have posted here but they haven’t seemed to work for me so far… (there is a decent chance I’m doing something wrong though as well)

Alright PR is fixed/updated: #622 waiting on the man.

@rajprakash00 i get the complete object of formik

{ "values": { "id": 1, "email": "irzumshahid@gmail.com", "first_name": "irzum", "last_name": "acntMngr" }, "errors": {}, "touched": {}, "isSubmitting": false, "isValidating": false, "submitCount": 0, "initialValues": { "id": 1, "email": "irzumshahid@gmail.com", "first_name": "irzum", "last_name": "acntMngr" }, "initialErrors": {}, "initialTouched": {}, "isValid": true, "dirty": false, "validateOnBlur": true, "validateOnChange": true, "validateOnMount": false }

@mjangir with the HOC? It injects the validateForm as Prop

  useEffect(() => {
    if (form.current) {
      this.props.validateForm();
    }
  }, [form]);

This or an equivalent will be in v2 btw.

Reviewing now. This is a large change, but understandable.

The solution to initial validation on load is quite simple:

in your form component, the one which is wrapped into withFormik or Formik (I’ve tested with the latter) add:

  componentDidMount() {
    const { isValid, validateForm } = this.props;

    if (!isValid) {
      validateForm();
    }
  }