-
Notifications
You must be signed in to change notification settings - Fork 18
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
Conversation
@@ -48,16 +52,16 @@ export const MultiSectionFormValidationContextProvider = ({ | |||
zip(schemas, contexts).map(([schema, ctx]) => { | |||
return !!schema | |||
? new Promise((resolve, reject) => { | |||
schema |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto formatting fix.
There was a problem hiding this 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 makefetchData
to return an object with both.promise
property andcancel: () => {}
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]);
ui/packages/lib/src/components/form/validation/multi_section_provider.js
Outdated
Show resolved
Hide resolved
…rovider.js Rewrite resolve promise Co-authored-by: Roman Wozniak <[email protected]>
@@ -129,7 +129,8 @@ export const useApi = ( | |||
return { | |||
cancel: () => { | |||
didCancel = true; | |||
} | |||
}, | |||
promise: promise, |
There was a problem hiding this comment.
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.
@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. |
c7a139c
to
c562334
Compare
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 theonSubmit
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.
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, theonSubmit
action can now be passed in as a lazyPromise
which is expected to be resolved/rejected in the appropriate UI component, after we have the API response. TheMultiSectionFormValidationContextProvider
component will only reset the submitting status in thefinally()
block, ensuring that the action has been completed. The change is backward compatible and theonSubmit
can also be a simple callback.By passing in a Promise instead, we may have the form behave like this:
Most (if not all) API calls rely on the
useApi
hook. Its return valuefetchData
now also exposes the promise, so it may be passed in as theonSubmit
argument to theMultiSectionFormValidationContextProvider
component, defined like: