Once a form's fields have been validated, submitting doesn't trigger a rerun of the validation. Is there a way I can trigger a rerun of the validation when the form is submitted?
I have a form field whose value can become invalid if it's not submitted within a particular timeframe. It's not async; I'm just trying to cover a scenario in which the user doesn't click submit for a while, and when they eventually do, the value would have become invalid. Final form remembers the result of the validation that happens immediately after the value is changed, which means that the unchanged value remains valid regardless of how much time passes between the validation and the submission. This is the behavior I want to hook into and change; the intervening time matters in my use case. I have tried using the beforeSubmit
listener from the final-form-submit-listener
package but it only gives access to the FormApi
object. I tried using the pauseValidation
and resumeValidation
functions from FormApi
but they couldn't achieve what I want, or maybe I'm not using them correctly. I have a feeling it's painfully obvious how to do this, but I can't figure it out. 😩
I created this Sandbox to demonstrate what I mean.
Thanks!
UPDATE: Some additional information:
meta
object for the form fields. My codebase is complex and relies heavily upon the meta
object to display error messages. Trying to replicate that functionality in the submit handler may work but it's hacky and goes against the convention used throughout the codebase.Library author here. I'm always fascinated by new ways people can invalidate my assumptions. I mean that in a sincerely positive way, as it results in learning.
🏁 Final Form makes the assumption that your validation functions are "pure" or "idempotent", i.e. will always return the same result when given the same values. This is why it doesn't run the synchronous validation again (just to double check) before allowing the submission: because it's already stored the results of the last time it ran it. By using an outside timer, you've invalidated that assumption.
If you have a better/simpler/"more official" solution, I'd still love to see it!
No need for mutators or decorators for this problem.
The more official way to do this would be to run the check (you could even reuse this.validate
) in onSubmit
. The only tricky part is that the error will come back as meta.submitError
, so you need to check for both when displaying your error. Like so:
So I have found a way to do this! 🎉
I use a mutator and use it's changeValue
function to 'change' the value of the relevant field (I supply the same value). This in turn notifies all relevant parties of the change to the form's state, and a validation is triggered. The key is to call the mutator inside the submit handler, which therefore ensures that the validation is performed when the form is submitted. Have a look at this new Sandbox.
The relevant bits are as follows:
// this is a stateful component
...
...
mutateValue([name], state, { changeValue }) {
// change the value to the same value, thus
// triggering a revalidation of the same value
changeValue(state, name, value => value);
}
handleSubmit(values) {
alert("submitted");
}
render() {
return (
...
...
<Form
onSubmit={this.handleSubmit}
mutators={{ mutateValue: this.mutateValue }}
render={({
handleSubmit,
form: {
mutators: { mutateValue }
}
}) => {
const mutateBeforeSubmit = values => {
// supply the name of the relevant form field
mutateValue("revalidate");
// submit handler gets called if revalidation still passes
handleSubmit(values);
};
return (
<form onSubmit={mutateBeforeSubmit}>
...
...
</form>
);
}}
/>
...
...
And because it's triggering the same validation mechanism, meta
gets used accordingly!
If you have a better/simpler/"more official" solution, I'd still love to see it!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With