In Rails 3, passing a :confirm parameter to link_to will populate the data-confirm attribute of the link. This will induce a JS alert() when the link is clicked.
I am using the rails jQuery UJS adapter (https://github.com/rails/jquery-ujs). The relevant code from rails.js is:
$('body').delegate('a[data-confirm], button[data-confirm], input[data-confirm]', 'click.rails', function () {
var el = $(this);
if (el.triggerAndReturn('confirm')) {
if (!confirm(el.attr('data-confirm'))) {
return false;
}
}
});
and
triggerAndReturn: function (name, data) {
var event = new $.Event(name);
this.trigger(event, data);
return event.result !== false;
}
I would like to know how this could be modified to instead yield a jQuery dialog (e.g. the jQuery UI Dialog) allowing the user to confirm or cancel.
My knowledge of JavaScript isn't sufficient to achieve this elegantly. My current approach would be to simply rewrite the $('body').delegate() function to instead instantiate a lightbox. However I imagine that there is a more effective approach than this.
I don't understand why you need to use the jQuery dialog when the JavaScript confirm() function will still work just fine. I would do something like this:
If you want to use a dialog instead, it's a little different. You can one-off each dialog you want, or you can probably take a uniform approach application wide so that your rails.js or your application.js can handle any dialog instance. For example, you'd need something like this on your page:
Then, in your js:
If you want to customize your dialog a little more, check out this example.
Edit
Now that I think of it, this would be a good opportunity for a custom form builder. You could override one of your Rails link tags to output html similar to what's listed above whenever a certain attribute is present, i.e.
:dialog => true
. Surely that would be the Railsy way to do it. You could add other options into your tag as well, like the dialog title, etc.Edit
Better yet, instead of
:dialog => true
, use:confirm => "my confirm message"
just as you would normally, but in your override of link_to, you will use the:confirm
option to create the dialog html that jQuery needs, delete that option, and then callsuper
.I just added an external API to the Rails jquery-ujs for exactly this kind of customization. You can now make rails.js use a custom confirm dialog by plugging into (and re-writing 1 line of) the
$.rails.allowAction
function.See my article, Rails jQuery UJS: Now Interactive, for a full explanation with examples.
EDIT: As of this commit, I moved the
confirm
dialog function to the$.rails
object, so that it can be modified or swapped out even more easily now. E.g.As others have mentioned, you cannot use a jQuery dialog box, as
$.rails.confirm
needs to block until it returns the users answer.However, you can overwrite
$.rails.allowAction
in yourapplication.js
file like this:It works by returning
false
immediately, thus effectively canceling the click event. However, your custom function can then call the callback to actually follow the link/submit the form.This is how I got it to work. Please suggest any corrections / improvements
#in rails.js
# #in application.js
# #in layout.html Alt you can place this div anywhere in your generated html
#This is how I solved this problem. I tried a lot of different ways, but only this one works.
In rails.js
In this place I used code of @Mark G. with some changes. Because this $(this).trigger('click.rails') snipped of the code didn't work for me.
Then in the html.erb file I have this code for link:
and this code for modal:
I hope, it will help someone.
I liked the answer from @Marc Schütz about overriding
$.rails.allowAction
the most of anything I found online - but I'm not a big fan of overriding the functionality inallowAction
since it's used all throughout the jquery-ujs codebase (what if there are side effects? Or if the source for that method changes in a future update?).By far, the best approach would be to make
$.rails.confirm
return a promise... But it doesn't look like that's going to happen anytime soon :(So... I rolled my own method which I think is worth mentioning because it's lighter weight than the method outlined above. It doesn't hijack
allowAction
. Here it is:How does it work? Well, if you look at the source, you'll notice that the
allowAction
method halts if theconfirm event
returns a falsy value. So the flow is:data-confirm
attribute. There is nodata-confirmed
present on the link or button, so we fall into the first if block, trigger our custom modal and return false, thereby stopping the action from continuing in the ujs click handler.data('confirmed', true)
and re-trigger the same event that was triggered previously (click.rails
).confirm event
will fall into theelse
block (sincedata('confirmed')
is truthy) and return true, causing theallowAction
block to evaluate to true.I'm sure I'm even missing other ways that might make this even simpler, but I think this is a really flexible approach to get a custom confirm modal without breaking core
jquery-ujs
functionality.(Also, because we're using
.on()
this will bind to anydata-confirm
elements on the page at load time or in the future, similarly to how.delegate()
works, in case you are wondering.)