Formik: async submitForm

Created on 5 Mar 2018  路  15Comments  路  Source: formium/formik

Bug, Feature, or Question?

Feature

Current Behavior

formikBag.submitForm does not consider submit handlers that return promises.

Desired Behavior

formikBag.submitForm should return a Promise (ideally the submit handler's own Promise) so the developer can handle server API rejections accordingly in cases where it is not possible / desirable to handle them in the original submit handler.

Suggested Solutions

Would require changes in src/Formik.tsx. In it, methods submitForm and executeSubmit.

Additional Information

Commented here #42, but created a new issue for visibility as I think I have a valid use-case. To reiterate, I want to create a custom reusable form component that handles server API validation errors in a generic way.

Small example of what I want to do:

class LoginForm extends React.Component {
  async handleSubmit(values) {
    await axios.post('login', values) // no try/catch here
  }

  render() {
    return (
      <Formik
        onSubmit={this.handleSubmit}
        render={() => (
          <CustomGenericForm>
            ...stuff
          </CustomGenericForm>
        )}
      />
    )
  }
}

class CustomGenericForm extends React.Component {
  handleSubmit = async event => {
    event.preventDefault()
    const { formik } = this.context
    try {
      await formik.submitForm()
    } catch (error) {
      if (error.response && error.response.data && error.response.data.validationErrors) {
        formik.setErrors(error.response.data.validationErrors)
      } else {
        throw error
      }
    } finally {
      formik.setSubmitting(false)
    }
  }

  render() {
    const { children } = this.props
    return <form onSubmit={this.handleSubmit}>{children}</form>
  }
}

CustomGenericForm.contextTypes = {
  formik: PropTypes.object,
}

Or is there a way to achieve what I want with the current version?


stale

Most helpful comment

This is now available in formik@canary

All 15 comments

Hola! So here's the deal, between open source and my day job and life and what not, I have a lot to manage, so I use a GitHub bot to automate a few things here and there. This particular GitHub bot is going to mark this as stale because it has not had recent activity for a while. It will be closed if no further activity occurs in a few days. Do not take this personally--seriously--this is a completely automated action. If this is a mistake, just make a comment, DM me, send a carrier pidgeon, or a smoke signal.

There is still a PR open for this issue.

+1 on that feature.
I'm trying to define handleSubmit as a function returning promise. Would like to get benefit from it when triggered submitForm() inside form component. Currently, submitForm returns "a promise", but it is not that one I expected. Triggering handleSubmit directly (as said in the docs, it should also start submit process) it returns nothing.

I'm not sure if i missed something but I guess it's a good issue to comment. Any suggestions (even for workaround) are welcome :wink:

I saw that there is something developed currently. #500
Any updates about the work status?Long time since the issue has been reported.

I am missing this feature too

Has anyone been able to work around this issue while waiting for the PR to go through?

I mainly wanted to use it to automatically manage buttons state during submit process. I ended up with component being explicitly put inside the view and conditionally configure it with formik's isSubmitted flag and manually perform some further steps after my submit function is resolved. @lashiec9, if You show your use case, maybe we could find a work around :wink:

Oh was about to make an issue about this myself. Need this for testing purposes.

This is now available in formik@canary

@jaredpalmer is there an example using it? I have a simple form using the v1.x.x and it works until I submit a form with errors, then the form won't let me submit again.

Update:

What was happening is that if the form had errors the isSubmitting kept true, therefore, not revalidating any fields.

@jaredpalmer My reading of @rhyek's issue is that he'd like to be able to call submitForm asynchronously and have it return the resolved value from the onSubmit handler (if the function optionally returns a promise).

Here's a codesandbox mockup I used w/ your latest 2.0 canary tag:
https://codesandbox.io/s/jzm92qr6ow

For above, would ideally have the submitForm call first trigger the alert of the validated email and THEN the alert of the resolved message: 'onSubmitHandler complete' . However, the opposite happens, since submitForm returns before the onSubmit promise has executed.

@jaredpalmer Submitted a PR for this in 1.4.2 here:
https://github.com/jaredpalmer/formik/pull/1229

This also affects the WIP 2.0 canary implementation

I created this utility function which is able to handle the async submit with the current version of Formik (1.5.1), without making any changes to Formik. I also added a function that is able to validate the form and make it display the errors, since that feature is missing in the current version too.

import { Formik, FormikTouched, setNestedObjectValues } from 'formik';

export const validateForm = (form: Formik) => {
  form.setState(prevState => ({
    touched: setNestedObjectValues<FormikTouched<any>>(prevState.values, true),
    isValidating: true,
    submitCount: prevState.submitCount + 1,
  }));

  return form.runValidations(form.state.values).then(combinedErrors => {
    if (form.didMount) {
      form.setState({ isValidating: false });
    }
    const isValid = Object.keys(combinedErrors).length === 0;
    if (!isValid) {
      throw new Error('Validation failed');
    }
  });
};

export const submitForm = (form: Formik) =>
  validateForm(form).then(() => form.props.onSubmit(form.state.values, form.getFormikActions()));

You can use this like:

validateForm(form)
  .then(() => {
    // Form is valid
  })
  .catch(() => {
    // Form it not valid
  });

and:

submitForm(form)
  .then(() => {
    // Form is submitted
  })
  .catch(() => {
    // Submission failed
  });

+1

Hey everyone, with the new edition, you can easily use async submission in formik.
Ref - https://formik.org/docs/examples/async-submission

Was this page helpful?
0 / 5 - 0 ratings