Hotwire Discussion

Button_to not showing the data-confirm?

I’m trying to have a confirmation dialog box show with my button_to, but it doesn’t seem to want to show. The code is being fired but the confirmation isn’t showing. I’ve tried adding it to the button and the form but neither are showing the data-confirm dialog. Can anyone help me work out what’s happening?

Thanks

<%= button_to delete_hamper_order_path(hamperorder: hamperorder.id, hamper: hamperorder.hamper), method: :post, class: "bg-transparent hover:bg-red-500 font-semibold text-red-500 hover:text-white text-sm py-1 px-2 border border-red-500 hover:border-white rounded my-2 w-full", data: {confirm: "This will permanently delete this hamper. Are you sure you wish to continue?"} do %>
    Delete Hamper
  <% end %>
1 Like

Hey @dazza !

I believe one of the things that the Turbo install script does is remove rails-ujs. This is a fairly old solution that was added to Rails to help simplify some of the simple JS that people ran into. This includes the data-confirm behavior, as well as a few other behaviors such as disable-with and the use of method on link_to.

That said, you should be able to replicate this behavior easily with Stimulus. Looking at the source for data-confirm, it looks like you could wrap the behavior in a Stimulus controller like this:

// javascripts/controllers/confirmation_controller.js
import { Controller } from "stimulus"

export default class extends Controller {
  static values = { message: String };

  confirm(event) {
    if (!(window.confirm(this.messageValue))) {
      event.preventDefault()
    };
  };
}
<!-- app/views/some_resource/_form.html.erb -->
<%= form_with model: @some_resource, data: { controller:  "confirmation", "message-value": "Are you sure?", action: "submit->confirmation#confirm" } do %>
  <!-- Form goes here -->
<% end %>

This is totally untested code that I just hacked together, so please do give it a test in your app. I haven’t used this controller in particular, but I wrote a controller for disable-with, and it’s worked fairly well so far. I’ve found it’s not been too hard to replicate rails-ujs behavior so far using the great Stimulus API.

EDIT: @dazza I’ve now tested this code as part of this conversation. I’ve updated the code snippet accordingly.

DOUBLE EDIT: I’m sharing this link to a relevant GitHub issue for reference by future readers of this thread.

1 Like

Thanks so much! That makes total sense … I’ll just add a warning to the webpage for the moment :wink:

1 Like

@jacobdaddario thaks for the idea! I did some tests and I find out that preventDefault is not enought to stop the execution, I had to add stopImmediatePropagation too:

import { Controller } from “stimulus”

export default class extends Controller {
  static values = { confirmMessage: String };

  confirm(event) {
    if (!(window.confirm(this.confirmMessageValue))) {
      event.preventDefault();
      event.stopImmediatePropagation();
    };
  };
}

Hope it helps!

/cc @dazza

2 Likes

This is great! I wasn’t aware that this method existed. Reading the JS docs though, I’m concerned that the order that controllers are installed will create some problems. In the PR in stimulus-rails, I’ve actually considered dispatching a custom event instead. It’s definitely a tricky situation.

Well, if you have lots of forms in your web application that could be a lot of work. Instead you can do it globally using events.

document.addEventListener("turbo:submit-start", (event) => {
  confirmSubmission(event).then(() => {
    // show progress bar and set submit state here.
    // this block is optional.
  })
})

function confirmSubmission(event) {
  const button = event.target.querySelector("[data-confirm]")
  const message = button?.dataset?.confirm

  return new Promise(resolve => {
    if (!message || confirm(message)) {
      resolve()
    } else {
      event.detail.formSubmission.stop()
      event.preventDefault()
      event.stopImmediatePropagation()
    }
  })
}
1 Like

Great! Thank you very much :slight_smile: