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

Await for confirm method results #525

Merged
merged 1 commit into from
May 1, 2022
Merged

Conversation

excid3
Copy link
Contributor

@excid3 excid3 commented Jan 27, 2022

The browser's confirm is synchronous and waits for a boolean. This is really convenient, but makes it painful to implement a custom confirm modal in Boostrap, Tailwind, etc.

This PR adds await so a custom confirm can return a promise that waits until the user confirms or cancels the operation.

The overridden confirm method simply needs to return a Promise that resolves to true or `false.

Turbo.setConfirmMethod(() => {
  return new Promise((resolve, reject) => {
    // show modal
    // on confirm, resolve(true)
    // on cancel, resolve(false)
  })
})

Closes #522

Example of it in action:
https://user-images.githubusercontent.com/67093/151271318-5034bbff-6b24-462f-89f7-8e6e3f8d0466.mp4

@excid3
Copy link
Contributor Author

excid3 commented Jan 27, 2022

Tests are failing because main has failing tests.

@@ -113,7 +113,7 @@ export class FormSubmission {
const { initialized, requesting } = FormSubmissionState

if (this.needsConfirmation) {
const answer = FormSubmission.confirmMethod(this.confirmationMessage!, this.formElement)
const answer = await FormSubmission.confirmMethod(this.confirmationMessage!, this.formElement)
Copy link
Contributor

Choose a reason for hiding this comment

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

Switching to an assumption that FormSubmission.confirmMethod is a promise, what happens when a user-provided Promise set by Turbo.setConfirmMethod throws an exception?

Before the await, the async start() (the method that wraps these lines) would have to deal with the exception.

After adding the await, is that exception swallowed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Throwing an error in the promise raises the Uncaught (in promise) error in the start() method of FormSubmission:

return this.fetchRequest.perform()

It doesn't swallow the exception.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's good. In that case, should the default function also be translated into a Promise?

static confirmMethod(message: string, element: HTMLFormElement):boolean {
return confirm(message)
}

static confirmMethod(message: string, element: HTMLFormElement): Promise<boolean> {
  return Promise.resolve(confirm(message))
} 

Copy link
Contributor Author

@excid3 excid3 Jan 27, 2022

Choose a reason for hiding this comment

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

It didn't affect the default method, but we could.

Would we also want to change this to expect a Promise too?

export function setConfirmMethod(confirmMethod: (message: string, element: HTMLFormElement)=>Promise<boolean>) {
  FormSubmission.confirmMethod = confirmMethod
}

@kstratis
Copy link

kstratis commented Apr 5, 2022

Great work @excid3! Thank you!
Seems there are a couple of "duplicate" commits though - Could you please have a look?

commits

@excid3
Copy link
Contributor Author

excid3 commented Apr 5, 2022

@kstratis I botched the rebase from main on accident. 😅

@tabishiqbal
Copy link

tabishiqbal commented Apr 17, 2022

any update on this? @excid3

@MatheusRich
Copy link

Is there anything actionable here? How can we move this forward?

cc @dhh

src/core/drive/progress_bar.ts Outdated Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
@excid3
Copy link
Contributor Author

excid3 commented May 1, 2022

@dhh fixed this, so it's ready for review now. 👍

@excid3
Copy link
Contributor Author

excid3 commented May 1, 2022

Tests that are failing are the same ones in main.

@dhh dhh merged commit 933419b into hotwired:main May 1, 2022
@excid3 excid3 deleted the await-confirm branch May 2, 2022 12:15
@thewatts
Copy link

thewatts commented May 5, 2022

@excid3 congrats on the merge!

Does this mean that you're going to have a GoRails episode on implementing a custom confirm modal? 😇

@ivorpad
Copy link

ivorpad commented Jun 13, 2022

@thewatts https://gorails.com/episodes/custom-hotwire-turbo-confirm-modals

@thewatts
Copy link

@ivorpad YESSSSSSS! Thank you!

( And many thanks to you as well, @excid3 ! )

@rapcal
Copy link

rapcal commented Dec 1, 2022

@excid3 how would you go about i18n buttons rendered in insertConfirmModal?

@excid3
Copy link
Contributor Author

excid3 commented Dec 1, 2022

@rapcal Lots of options.

You could pass the text as extra data attributes on the element with the data-turbo-confirm, like data: { turbo_confirm_ok: I18n.t("ok"), turbo_confirm_cancel: I18n.t("cancel") } and then use those when rendering your modal HTML.

Or have Rails render the HTML for the dialog ahead of time like we do in the screencast linked here. #525 (comment)

@rapcal
Copy link

rapcal commented Dec 1, 2022

@rapcal Lots of options.

You could pass the text as extra data attributes on the element with the data-turbo-confirm, like data: { turbo_confirm_ok: I18n.t("ok"), turbo_confirm_cancel: I18n.t("cancel") } and then use those when rendering your modal HTML.

Or have Rails render the HTML for the dialog ahead of time like we do in the screencast linked here. #525 (comment)

Thanks, Chris!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Could you please add await keyword to FormSubmission.start method?
9 participants