Post validate values processing before onSubmit call
See original GitHub issueAre you submitting a bug report or a feature request?
Feature request
What is the current behavior?
I use yup
validation together with this library. I implemented a simple helper:
import yup from 'yup';
import { setIn } from 'final-form';
const validate = async (values, schema) => {
if (typeof schema === 'function') {
schema = schema();
}
try {
await schema.validate(values, { abortEarly: false });
} catch (e) {
return e.inner.reduce((errors, error) => {
return setIn(errors, error.path, error.message);
}, {});
}
};
which I can use like this:
import React from 'react';
import yup from 'yup';
import { Form, Field } from 'react-final-form';
const schema = yup.object({
name: yup.string().required(),
surname: yup.string().required(),
});
const UserForm = ({ onSubmit }) => (
<Form
onSubmit={onSubmit}
validate={values => validate(values, schema)}
render={({ handleSubmit, values }) => (
<form onSubmit={handleSubmit} autoComplete="off">
<Field name="name" placeholder="name" component="input" />
<Field name="surname" placeholder="surname" component="input" />
<button type="submit" >Submit</Button>
</form>
)}
/>
);
What is the expected behavior?
Currently, Form
validate
prop is used only to validate, but there is no way to change form values here, I can only return errors or nothing, when I return nothing, form values which were validated will go to onSubmit
handler. It would be great to allow values postprocessing in validate
step.
One use case - very popular yup
library has casting abilities before validation, for example yup.number()
will try to convert '1'
to 1
before validation. I need this because I have a really complex form, in which many fields are conditionally based on type
field. For instance, type a
has x
and y
fields, type b
has z
field. Now, if a user goes back and forth between type a
and b
and he fills them, my values
object will contain x
, y
and z
keys, but in onSubmit
with type b
, I want values
to have only z
key. Now, whats nice about yup
, its validate
method returns casted object, with optional removing unnecessary attrs as well. Here are the options I see:
- I could use yup again in
onSubmit
- highly inefficient as all validation logic would be triggered again - Maybe I could pass
FormApi
tovalidate
myself to myvalidate
helper, and then I could update values there. - We could add
FormApi
toForm
validate
prop next to values, then it would be already available - This option is hardcore (breaking change), but the cleanest in my opinion would be to change how
validate
prop works. Currently,validate
return errors or undefined or a corresponding Promise. We could change it to throw an error or return a rejected promise in case of a submit error, or a values object in case user input was valid - we could return casted values here if we wanted. So I could refactorvalidate
like this:
import yup from 'yup';
import { setIn } from 'final-form';
const validate = async (values, schema) => {
if (typeof schema === 'function') {
schema = schema();
}
try {
const castedValues = await schema.validate(values, { abortEarly: false, stripUnknown: true });
} catch (e) {
throw e.inner.reduce((errors, error) => {
return setIn(errors, error.path, error.message);
}, {});
}
return castedValues;
};
- Softer version of above, implementing a new prop like preSubmit, which would exist next to validate, so it woudn’t be a breaking change anymore
What’s your environment?
react-final-form: 3.0.2, final-form: 4.0.0
Issue Analytics
- State:
- Created 6 years ago
- Reactions:2
- Comments:6 (2 by maintainers)
Top GitHub Comments
Great topic though, thanks for posting. As it gives me idea on how to use
yup
. I wanted to useyup
.@Noitidart Yup (no pun intended) me too, would be good to add a Yup example to the docs