Feature request
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>
)}
/>
);
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:
1) I could use yup again in onSubmit - highly inefficient as all validation logic would be triggered again
2) Maybe I could pass FormApi to validate myself to my validate helper, and then I could update values there.
3) We could add FormApi to Form validate prop next to values, then it would be already available
4) 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 refactor validate 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;
};
5) 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
react-final-form: 3.0.2, final-form: 4.0.0
Actually validate is called on field value change as well of course, not only on submit, so maybe we could add another form hook prop like onPreSubmit or parseValues? It could be a simple pure function values => parsedValues. When used, not values would be injected into onSubmit anymore, but returned parsedValues from parseValues|onPreSubmit
UPDATE:
But then it doesnt make any sense, we could just add this in our onSubmitHandler itself... I am only interested in this because yup library casts form values during validation process, and it is a waste to do it again in onSubmit.
So we also need a boolean flag isSubmitValidation or sth, so certain logic could be triggered only before submit (like changing field values) - but actually should we change form values to casted ones at all? Apologies for this issue in advance, as I am not sure what is the best approach to move forward, I am brainstorming with myself for now :)
- I could use yup again in onSubmit - highly inefficient as all validation logic would be triggered again
I think that's your answer. I'm dubious of your use of the word "highly". If you're already running validation on every keypress, it's probably going to be fast enough to run just once more when you submit your form, no?
I think you are right, I think I run into a premature optimization mistake :+1: So closing I think :)
Great topic though, thanks for posting. As it gives me idea on how to use yup. I wanted to use yup.
@Noitidart Yup (no pun intended) me too, would be good to add a Yup example to the docs
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Great topic though, thanks for posting. As it gives me idea on how to use
yup. I wanted to useyup.