I am catching errors from api and showing them in form, and that is working fine. But the problem is when I change one field in form all errors disappear. For form I am using Formik and for validation Yup.
const handleSubmit = (values, {setSubmitting, setFieldError, setStatus}) => {
someApiCall(values)
.then(
() => {
},
(error) => {
// example of setting error
setFieldError('email', 'email is already used');
})
.finally(() => {
setSubmitting(false)
});
};
I tried with adding third parametar false to setFieldError, but nothing changed.
The way that Formik handles errors is that the returned error structure should map an error message to same structure as your values. In our case we have a single level object with a firstName key. So if our value below is set like this, then our error should map accordingly.
Formik has its own handleChange method that you can use to update the state with user inputs, there is no need to implement your own handleChange method. The handleChange method updates the form values based on the input's name attribute that was changed.
Like errors and values , Formik keeps track of which fields have been visited. It stores this information in an object called touched that also mirrors the shape of values / initialValues . The keys of touched are the field names, and the values of touched are booleans true / false .
Here's my working example: https://codesandbox.io/s/formik-example-dynamic-server-rendered-values-1uv4l
There's a callback validate
available in Formik: https://jaredpalmer.com/formik/docs/api/formik#validate-values-values-formikerrors-values-promise-any using which you can probably try to do something like below.
I initiated emailsAlreadyInUse
with empty array and then in your API call once error gets returned then add that user to the array and once user uses the same email again and tried to validate, although it will pass Yup validation but it will be caught in validate
callback which I believe runs after Yup validation (though I could be wrong but in your case doesn't matter).
const emailsAlreadyInUse= [];
const handleSubmit = (values, {
setSubmitting,
setFieldError,
setStatus
}) => {
someApiCall(values)
.then(
() => {
// Do something
// possibly reset emailsAlreadyInUse if needed unless component is going to be unmounted.
},
(error) => {
// example of setting error
setFieldError('email', 'email is already used');
// Assuming error object you receive has data object that has email property
emailsAlreadyInUse.push(error.data.email);
})
.finally(() => {
setSubmitting(false)
});
};
<Formik
...
...
validate = {
values => {
let errors = {};
if (emailsAlreadyInUse.includes(values.email)) {
errors.email = 'email is already used';
}
return errors;
}
}
/>
I found simplier method to make API validation errors always visible than using validate
method. You can set validateOnBlur
and validateOnChange
on your form to false
. It will cause validation only on submit and errors returned from API will remain after changing field value.
Usage:
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validateOnBlur={false}
validateOnChange={false}
>
...form fields...
</Formik>
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