Better handling of form submission errors
See original GitHub issueIs your feature request related to a problem? Please describe. The documentation is missing a section on how to display validation errors for fields that are coming from API 400 responses. Example response:
{
"errors": {
"myField": ["error1", "error2"]
}
}
Describe the solution you’d like Clear documentation with straightforward way of displaying validation errors from API.
Describe alternatives you’ve considered I have found several issue and answers for this problem when react-admin still used redux-form. I’ve tried those solutions to no avail just to realize that it is now using react-final-form. Looking through the code I haven’t found any easy or straightforward solution.
One solution could be composing the save
callback provided to the create and edit view by the useEditController
and useCreateController
and then saving the error somehow in state and returning it in the validate
callback. But this solution is in no way simple and straightforwards.
Another solution that I’ve implemented is using saga to capture the FETCH_ERROR and saving the error in redux. This on the other hand made a big mess on managing state as it had to be removed after displaying it, otherwise it would have affected other forms as well.
Other than that it was hard to figure out how to actually make these errors go away after displaying them, because if they were not removed you couldn’t submit the form. For this I had to also save the form state values to figure out which fields changed and which error I didn’t have to display anymore.
And to put the cherry on the cake making both frontend and API errors display at the same time was again quite hard. In the end I ended up with a hook of 100 lines, and a lot more lines extract from it to different services.
export default function useEntityFormValidator(
schema: any,
customErrorMessages?: ISchemaErrorToTranslationCustomMapper,
): (entity: any) => IValidationErrorMapUntranslated | void {
const [
schemaErrorTransformer,
apiErrorTransformer,
jointErrorTransformer,
schemaValidator,
] = useDependencyInjections(
ServiceTypes.TRANSFORMER_SCHEMA_ERROR_TO_TRANSLATION,
ServiceTypes.TRANSFORMER_API_ERROR_TO_TRANSLATION,
ServiceTypes.TRANSFORMER_TRANSLATION_ERRORS_TO_JOINT,
ServiceTypes.VALIDATOR_SCHEMA,
);
const dispatch = useDispatch();
const lastBadRequest = useSelector<any, IHttpError | null>(
(state: any) => state.apiError?.lastBadRequest,
);
const [
apiErrorMessages,
setApiErrorMessages,
] = useState<IValidationErrorMapTranslated | null>(null);
const [apiErrorBody, setApiErrorBody] = useState<{ [k in string]: any }>({});
const computeRemainingApiErrorMessages = useCallback(
(entity: any) => {
const leftApiErrors: any = {};
Object.keys(apiErrorMessages || {}).forEach(field => {
if (entity[field] === apiErrorBody[field]) {
leftApiErrors[field] = (apiErrorMessages || {})[field];
}
});
return leftApiErrors;
},
[apiErrorMessages, apiErrorBody],
);
useEffect(() => {
if (lastBadRequest?.body?.errors) {
setApiErrorBody(lastBadRequest.requestBody);
setApiErrorMessages(apiErrorTransformer.transform(lastBadRequest.body));
// In order to not leave errors behind we consume it from the state.
// Otherwise other forms could potentially display errors from wrong
// places.
dispatch({ type: apiErrorActions.SET_400, data: null });
// Have to focus the body because if an input remains focused error
// messages will not be displayed until it loses focus.
document.body.focus();
}
}, [lastBadRequest]);
return useCallback(
(entity: any) => {
const schemaErrors = schemaValidator.validate(entity, schema) || {};
return jointErrorTransformer.transform(
[
computeRemainingApiErrorMessages(entity),
schemaErrorTransformer.transform(schemaErrors, customErrorMessages),
],
'• ',
);
},
[schema, customErrorMessages, computeRemainingApiErrorMessages],
);
}
Issue Analytics
- State:
- Created 4 years ago
- Reactions:4
- Comments:9 (6 by maintainers)
Hello everyone,
I would like to share my thoughts and get info if displaying submission errors is achievable with current react-admin:
React Final Form submission errors are stored in
meta.submitError
- react-admin fields could be easily updated to display this errors, ie: https://github.com/bmihelac/react-admin/commit/21e88e61a840d5534befb491b1d030e0775b1a19Final form Submission Error example expect submission errors to be returned as object literal in
onSubmit
. If I understand correctly, react-admin updates/creates resources as side effect and react-final-form does not recommend to mutate form state using dispatching actions:In #4703 @oleg-andreyev propose returning promise in custom
save
property. I liked and have tried this in combination withuseDataProvider
hook (which returns promise as opposed touseMutation
). Code is available in commit https://github.com/bmihelac/react-admin/commit/1a9f02b65f1342c695a10b5aad7a6a63603fb9ba and it looks like this could work. Unfortunately, I am not sure if comment https://github.com/marmelab/react-admin/issues/4703#issuecomment-616456129 relates touseMutation
only or that it would generally not possible to go this way, because it would break other things.Submission errors are indeed not well covered by react-admin, and require a lot of boilerplate code. It’s not just a matter of documentation - we need better APIs on how to customize the behavior in case of submission error.
Marking this as enhancement request, feel free to suggest changes.
As a side note, here is the relevant section of the react-final-form documentation : https://final-form.org/docs/react-final-form/examples/submission-errors