Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle MultiSectionFormValidationContextProvider onSubmit action defined as Promise #43

Merged
merged 5 commits into from
Jan 17, 2022

Conversation

krithika369
Copy link
Collaborator

@krithika369 krithika369 commented Jan 16, 2022

Bug Description

The MultiSectionFormValidationContextProvider is used in various MLP components (Merlin, Turing, etc.), for different scenarios. Eg:

When the form is submitted, it triggers the validation and if successful, the onSubmit action is executed - this may simply be advancing to the next step in the step wizard or, submitting the form through an API call, as in the case of the last step in the step wizard or with the accordion form. In the latter case where there is an API call involved, it usually takes some time to get back a success/failure response. Usually, it is expected that the Submit button is disabled until the onSubmit action is fully completed, i.e., we have a success/failure response from the API and may be taken to the another view automatically or may attempt to submit the form again, accordingly. However, the Submit button is re-enabled too soon and causes confusion (nothing else happening to the form while we wait for the API response) which may lead to the user attempting to submit the form again (often resulting in unintended behavior).

The example below shows an edit form involving a successful API call where the Submit button is re-enabled too soon and is thus able to be clicked twice.

submit_button

Note: This bug is less noticeable when the forms are wrapped around a confirmation modal (although still reproducible), as with the examples quoted with Turing but it is proving to be apparent for some of our newer UI.

Details of the Fix

Instead of resetting the submitting status of the form immediately after validation, we should do so after the onSubmit action is fully executed and the result is known. Since this involves asynchronous calls, the onSubmit action can now be passed in as a lazy Promise which is expected to be resolved/rejected in the appropriate UI component, after we have the API response. The MultiSectionFormValidationContextProvider component will only reset the submitting status in the finally() block, ensuring that the action has been completed. The change is backward compatible and the onSubmit can also be a simple callback.

By passing in a Promise instead, we may have the form behave like this:

save_button_new

Most (if not all) API calls rely on the useApi hook. Its return value fetchData now also exposes the promise, so it may be passed in as the onSubmit argument to the MultiSectionFormValidationContextProvider component, defined like:

const onSubmit = () => submitForm({ body: experiment.stringify() }).promise;

@@ -48,16 +52,16 @@ export const MultiSectionFormValidationContextProvider = ({
zip(schemas, contexts).map(([schema, ctx]) => {
return !!schema
? new Promise((resolve, reject) => {
schema
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto formatting fix.

@krithika369 krithika369 changed the title Handle multi-section form onSubmit actions defined as Promise Handle MultiSectionFormValidationContextProvider onSubmit action defined as Promise Jan 16, 2022
Copy link
Contributor

@romanwozniak romanwozniak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To facilitate the creation and resolution of the Promise in the form, a usePromise hook is also introduced in this MR. Example usage

I'm not super comfortable with this. Exposing resolveOrReject from this useCallback function shifts the responsibility of "completing" the promise onto the "client" side, which seems to be error prone.

Assuming that submitForm from your example comes from useApi hook, I would suggest you to look into how to modify useApi itself, to make it possible to access the promise object, after this submitForm method is called.
Currently, userApi() return two objects:

const [result, fetchData] = useApi(...)
  • result - holds state of the api call (data, error, isLoading)
  • fetchData - is a function, a call to which returns an object with .cancel() method.
    It's possible to make fetchData to return an object with both .promise property and cancel: () => {} function.

With that, you don't need the usePromise hook altogether and your example can be rewritten as:

 const [submissionResponse, submitForm] = useApi(...);

 const onSubmit = () => (
   submitForm({ body: settings.stringify() }).promise
 )

  useEffect(() => {
    if (submissionResponse.isLoaded) {
      if (!submissionResponse.error) {
        // ...
        onSuccess(submissionResponse.data.id);
      }
    }
  }, [submissionResponse, onSuccess]);

@@ -129,7 +129,8 @@ export const useApi = (
return {
cancel: () => {
didCancel = true;
}
},
promise: promise,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capturing the promise and returning it is the only change here, the rest is auto formatting.

@krithika369
Copy link
Collaborator Author

@romanwozniak I was going to wait until Monday morning to assign this PR, thanks for the voluntary review. The changes are a whole lot cleaner now. I've updated the PR according to your suggestions.

@krithika369 krithika369 force-pushed the onsubmit_form_promise branch from c7a139c to c562334 Compare January 17, 2022 01:17
@krithika369 krithika369 merged commit e8f5e9b into main Jan 17, 2022
@krithika369 krithika369 deleted the onsubmit_form_promise branch January 17, 2022 01:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants