In versions of Rails previous to 5.1, which used jquery_ujs
, we could replace the browser's confirmation popup with our own by overriding $.rails.allowAction
, as explained here.
As of Rails 5.1+, which uses rails-ujs
, $.rails.allowAction
is no longer available. How can we override Rails' default confirmation with our own in Rails 5 without having to switch back to jquery_ujs
?
Thanks in advance.
In versions of Rails previous to 5.1, which used jquery_ujs
, we could replace the browser's confirmation popup with our own by overriding $.rails.allowAction
, as explained here.
As of Rails 5.1+, which uses rails-ujs
, $.rails.allowAction
is no longer available. How can we override Rails' default confirmation with our own in Rails 5 without having to switch back to jquery_ujs
?
Thanks in advance.
Share Improve this question asked Aug 28, 2017 at 16:51 BrunoFBrunoF 3,55328 silver badges41 bronze badges3 Answers
Reset to default 4I had the same challenge and I looked a little bit more into it. What I found out along the way can be read here: https://medium./store2be-tech/how-to-use-sweetalert2-for-your-rails-5-1-rails-ujs-confirms-without-jquery-8a5b516b2a1
Here the final solution:
(function() {
var handleConfirm = function(element) {
if (!allowAction(this)) {
Rails.stopEverything(element)
}
}
var allowAction = function(element) {
if (element.getAttribute('data-confirm-swal') === null) {
return true
}
showConfirmationDialog(element)
return false
}
// Display the confirmation dialog
var showConfirmationDialog = function(element) {
var message = element.getAttribute('data-confirm-swal')
var text = element.getAttribute('data-text')
swal({
title: message || 'Are you sure?',
text: text || '',
type: 'warning',
showCancelButton: true,
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
}).then(function(result) {
confirmed(element, result)
})
}
var confirmed = function(element, result) {
if (result.value) {
// User clicked confirm button
element.removeAttribute('data-confirm-swal')
element.click()
}
}
// Hook the event before the other rails events so it works togeter
// with `method: :delete`.
// See https://github./rails/rails/blob/master/actionview/app/assets/javascripts/rails-ujs/start.coffee#L69
document.addEventListener('rails:attachBindings', function(e) {
Rails.delegate(document, 'a[data-confirm-swal]', 'click', handleConfirm)
})
}).call(this)
I haven't found a beautiful way to tweak into rails_ujs, so I came with with this workaround (using CoffeeScript):
```
$(document).on 'mousedown', 'a[data-confirm]', (e) ->
e.preventDefault()
link = $(e.target)
message = link.data 'confirm'
modal = $('.modal.confirmation')
modal.find('.content').text(message)
approve = modal.find('.approve')
approve.attr('data-method', link.data('method'))
approve.attr('href', link.attr('href'))
modal.modal('show')
```
Mousedown event allows my event handler to be executed first (it goes before click event, which rails_ujs uses)
You can override it with Rails.confirm
, e.g. with CoffeeScript:
Rails.confirm = (message, element) ->
# your code
e.g. to have the confirm text show up for 2 seconds:
WAITING_CLASS = "waiting-for-confirmation"
TIMEOUT = 2000
Rails.confirm = (message, element) ->
if element.classList.contains(WAITING_CLASS)
true
else
element.dataset.beforeConfirm = element.textContent
element.textContent = element.dataset.confirm
element.classList.add(WAITING_CLASS)
timeout TIMEOUT, ->
element.classList.remove(WAITING_CLASS)
element.textContent = element.dataset.beforeConfirm
false
See: https://github./rails/rails/blob/master/actionview/app/assets/javascripts/rails-ujs/features/confirm.coffee
And timeout
and just a simple function that inverses the setTimeout
parameters:
var timeout = function(time, callback) {
setTimeout(callback, time)
}