formik: How to trigger form submit on change
🐛 Bug report
Current Behavior
In our project we’ve created an MUI Select
component and want it to do something every time its value has changed.
We’ve chosen to wrap it inside a <Formik>
tag in order to avoid dealing with events, and to keep code familiar to other members of the group. (since we use Formik in a great many places of the project)
Currently we write things like this: (details are omitted)
<Formik
initialValues={{ value: initialValue }}
onSubmit={({ value }, formikBag) => onSubmit(value, formikBag)}
>{({ values, handleChange, submitForm }) => (
<Select
name="value"
value={values.value}
onChange={(e) => {
handleChange(e);
submitForm();
}}
/>
)}
</Formik>
Expected behavior
Before Formik 1.4.0
, everything works as fine.
When users click on the Select
component, its onChange()
handler got triggered, which calls handleChange()
first (and sets value
) then submitForm()
(and triggers onSubmit()
).
Reproducible example
https://codesandbox.io/s/2307zv53zy
In the example, when value
of <select>
changes, the alert dialog does not popup.
Suggested solution(s)
One available solution is to set validateOnChange
to false
on the Formik
component.
Have dug into Formik code (v1.4.1
) for a bit, I found the cause of this problem.
Both handleChange()
and submitForm()
call Formik._runValidations()
, which starts a Promise
to run validations. Since v1.4.0
introduced cancellable Promise
s, the Promise
started later will cancel the one started earlier.
I expected the Promise
created by submitForm()
to be started after the one created by handleChange()
, however handleChange()
actually starts the Promise
in the callback of React Component.setState()
, which is deferred by React to the next frame and therefore started later than the one created by submitForm()
and, boom.
I don’t know whether what I’ve done is recommended by or even should be done with Formik, or, whether this will be considered a bug. If not, should this behavior be documented? It was pretty confusing to me at the beginning.
In case of any suggestions, please let me know. Thanks.
Your environment
Software | Version(s) |
---|---|
Formik | 1.4.1 |
React | 16.6.3 |
Browser | Chrome v71 |
npm/Yarn | npm 6.4.1 |
Operating System | Windows |
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 29
- Comments: 34 (11 by maintainers)
@pupudu exactly, we could call it as
onValidationSuccess
as wellre difference with validate, also I would add that validate is for validation, so I cannot see how it could be hard to explain the difference in docs
again, forms without submit buttons are quite a common use case, especially for filter kind of forms, form library imho should support this use case with clean code too, especially this is just 1 extra prop easy to explain
submitOnChange
would also be fine, but probably it would be less flexible, in theory you could do different thing in formonChange/onValidationSuccess
andonSubmit
(clicking submit button vs just changing some field without explicit submit)setTimeout
could get it works too. The magic is to let it run on the next cycle tick.This has been solved in Formik 2. There is now an official auto save example as well.
Commit: https://github.com/jaredpalmer/formik/commit/1fd9580d7da1b5d05f0c4183f038657d6b2b4a02
@jaredpalmer would you consider adding
onChange
to top level formik component, instead of or next to onSubmit? this callback would be called anytime a value is changed, provided the form is valid, then we wouldnt need to add hacks like this to submit the form on each key strokeAdding a async await on handleChange, fix it.
Check: https://codesandbox.io/s/ql8v2l8ll9
@JaredDahlke sounds complicated. Provide a codesandbox and I’ll take a look. A quick test against initialValues should help you.
@kelly-tock I guess you could do something like this
@johnrom
I implemented this and it worked perfectly. Now the problem is my API is having a hard time handling all of the patch requests I’m sending to it lol.
I ended up implementing this version based off of the doc’s example. I also added dirty to your equality test:
And my withFormik object looks like this:
Instead of showing the AutoSave verbiage from the example I’m going to just render a custom loader based off of some redux state. I know this is messy but I’m still learning! Really starting to see the power of the library, but it has had a pretty rough learning curve for me.
@jaredpalmer I come up with a scenario where trigger submit onChange is really necessary.
Say I have a page editor, left side is a preview of the page, right side is a form, when I type some kind of config on the right side, the preview will show content immediately.
And I shouldn’t use a submit button because it would really break user experience when you have to click a button every time you want to see the change.
Do you have any suggestions for this kind of situation ? Thanks.
Something went wrong Request failed with status code 404
@klis87 I don’t think an additional top-level onChange() is a good idea. The difference between onChange() and validate() is hard to explain.
wow.
Well
handleChange()
doc doesn’t say that it returns aPromise
. Is this intentional?I guess my question is why you need to validate through formik submission on every keystroke. Can you just call your submit function directly from your handler and avoid validation altogether?
If you really really want to do this, just note that your onSubmit function will still not run if there are errors returned by validation. Regardless, here my suggested solution: https://codesandbox.io/s/m4mzpn166j.
For those who are wondering how to handle this with useFormik, I used as following.
Two issues :Version of @jaredpalmer and @vojtechportes are behaving the same way:
is there an example of this that is not formik 2.0? I basically an keeping a form with no submit button in sync the hard way… onValidateSuccess sounds great to me.