Reputation: 3019
I am trying to display inline errors returned via API, for each invalid field. I am following the Submission Errors example from here with something like this:
const handleSubmit = async (values) => {
let errors;
await createProduct(values) // axios.post(...)
.then((res) => ...)
.catch((error) => {
errors = error.response.data.errors;
console.log(errors); // returns { title: ["can't be blank"] }
});
return errors; // returns { title: ["can't be blank"] }
}
then my form looks like this:
<Form onSubmit={handleSubmit}>
{({
submitError,
handleSubmit,
...
}) => (
<BSForm onSubmit={handleSubmit}> // BSForm for boostrapform
{submitError && (
<div className="error">{submitError}</div> // not showing
)}
{console.log(submitError)} // returns 'undefined'
<TextField
name="title"
...
/>
and I am only able to invoke submitError
if I pass {[FORM_ERROR]: 'error message'}
instead of returning the errors
obj.
I'd love to be able to just relay these API errors into corresponding fields' meta: { error }
props, but I can totally live with submitError
wrapping API errors.
Upvotes: 0
Views: 4915
Reputation: 103
Here is what worked for my use case! In the submit handler
, I just needed to resolve the promise with the error object sent by the api, then React-final-form(RFF) would propagate the error messages
down to the individual field states via the meta.submitError
.
The other thing to note here is that, the error object that gets resolved should contain matching object keys or property names
as the ones sent to the server(i.e. field names in form.values
should match the object keys you resolve
back when you receive a submit error
). My submit handler
finally looked like this:
const submit = (values) => {
const promise = 'some promise or api call';
return new Promise(resolve => {
promise(values))
.then(response => {
// ...do whatever
resolve(true);
})
.catch(error =>{
if (error.validationErrors) {
resolve({ [FORM_ERROR]: error.validationErrors });
} else {
//Depending on the shape of the error object from the server, destructure it or transform it so the keys match the field names in the form
//Example submissionErrors object would look like: {name: "Duplicate name detected", age: "Invalid age"}
const submissionErrors = {
...error.data?.errors,
...error.response?.data?.errors,
};
// Then finally `resolve` the errorObject back to the form.
//This `resolve` is what makes RFF to update the fieldState of the affected fields with `meta.submitError`
// You can then use `meta.submitError`, from `fieldState` of a given field, to display its `submission error`
resolve({ ...submissionErrors});
}
});
});
};
Upvotes: 2
Reputation: 3019
Found the solution 30 seconds after posting. I missed the meta: { submissionError }
prop in the example.
So the way I am returning errors seems to be correct, the only difference is instead of displaying Field level errors with meta.error && meta.touched
, I have to add meta.submitError
like so:
(meta.error || meta.submitError) && meta.touched;
then to display the error:
{(meta.error || meta.submitError) && meta.touched && (
<span>{meta.error || meta.submitError}</span>
)}
Upvotes: 1