question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Better handling of form submission errors

See original GitHub issue

Is 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:closed
  • Created 4 years ago
  • Reactions:4
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

4reactions
bmihelaccommented, May 20, 2020

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/21e88e61a840d5534befb491b1d030e0775b1a19

Final 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:

If you need to mutate your data via dispatching Redux actions, you should probably use Redux Form.

In #4703 @oleg-andreyev propose returning promise in custom save property. I liked and have tried this in combination with useDataProvider hook (which returns promise as opposed to useMutation). 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 to useMutation only or that it would generally not possible to go this way, because it would break other things.

3reactions
fzaninottocommented, Jan 24, 2020

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

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error Handling in Forms - Medium
Always show the submit button. Without a click to action, the user becomes confuse and might even think there is something wrong with...
Read more >
6 Form Error Message Mistakes Almost Everyone Makes
Error Message Design: 6 Mistakes to Avoid and Good Examples to Follow · 1. Error Message Placement · 2. Blame the User ·...
Read more >
Error handling on form submit - javascript - Stack Overflow
Actully on form submit , from backend due to some special charecter , submit fails. am not sure how to treat on response...
Read more >
Handling Validation Errors in Forms - Up Your A11y
Consider the challenges faced by screen reader users when filling out forms · Implement a minimal feedback list on form submission to communicate...
Read more >
Forms & error handling - Access & Use
If you present a list of errors after submitting the form, insert it before the form, set the focus to the beginning of...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found