I know that the usual JS way of taking an action only if a confirmation dialog is to have the confirmation inside the function, like this jQuery example:
<script type="text/javascript">
$(function () {
$("#dropdown").change(function () {
var success = confirm('Are you sure want to change the Dropdown ????');
if (success == true) {
// do something
}
else {
// Cancel the change event and keep the selected element
}
});
});
</script>
This doesn't work in my case, because the confirmation is part of a Rails helper:
<%= link_to "Delete", {:controller => 'foo', :action => 'delete', :id => @item.id},
{:method => :post, :confirm => "Are you sure?", :class => "start_spinner"} %>
I want to run some javascript on click (hide the link to prevent clicking twice), but only if the confirmation is true. Unfortunately, at least in Rails 2.3.x, it's not possible to use :onclick
when the :method
or :confirm
options are present. (This behavior is noted on ApiDock for the link_to helper and is the same in my application.)
EDIT:
I think I created some confusion by including the example from ApiDock instead of my exact code. Sorry about that. I've modified the code below to reflect the behavior that Rails has when the :method => :post
option is included, as it must be in my code. The difference between the two outputs is still just dropping the destroyJsFunction
method, but there's a whole bunch of other stuff that does happen in the onclick
that seems to interfere with implementing the solutions suggested by Sukima and agnoster.
<%= link_to "Delete", {:controller => 'foo', :action => 'delete', :id => @item.id}, :method => :post, :confirm=>"Are you sure?", :onclick=>"destroyJsFunction()", :class => "start_spinner" %>
# expected output
# => <a href="/foo/delete/1" class='start_spinner' onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'CSRF_TOKEN'); f.appendChild(s);f.submit(); }; {destroyJsFunction()}; return false;">Delete</a>
# actual output
# => <a href="/foo/delete/1" class='start_spinner' onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'CSRF_TOKEN'); f.appendChild(s);f.submit(); }; return false;">Delete</a>
END EDIT
Because I'm using Rails to submit the POST
request, I can't just re-write the link in plain HTML.
I'd like to run my javascript on click of a link with the class start_spinner
, but I can't find a way to re-display the link if the confirmation is false. Is there a way to have a separate javascript listen for the results of a confirmation dialogue?
I know that the usual JS way of taking an action only if a confirmation dialog is to have the confirmation inside the function, like this jQuery example:
<script type="text/javascript">
$(function () {
$("#dropdown").change(function () {
var success = confirm('Are you sure want to change the Dropdown ????');
if (success == true) {
// do something
}
else {
// Cancel the change event and keep the selected element
}
});
});
</script>
This doesn't work in my case, because the confirmation is part of a Rails helper:
<%= link_to "Delete", {:controller => 'foo', :action => 'delete', :id => @item.id},
{:method => :post, :confirm => "Are you sure?", :class => "start_spinner"} %>
I want to run some javascript on click (hide the link to prevent clicking twice), but only if the confirmation is true. Unfortunately, at least in Rails 2.3.x, it's not possible to use :onclick
when the :method
or :confirm
options are present. (This behavior is noted on ApiDock for the link_to helper and is the same in my application.)
EDIT:
I think I created some confusion by including the example from ApiDock instead of my exact code. Sorry about that. I've modified the code below to reflect the behavior that Rails has when the :method => :post
option is included, as it must be in my code. The difference between the two outputs is still just dropping the destroyJsFunction
method, but there's a whole bunch of other stuff that does happen in the onclick
that seems to interfere with implementing the solutions suggested by Sukima and agnoster.
<%= link_to "Delete", {:controller => 'foo', :action => 'delete', :id => @item.id}, :method => :post, :confirm=>"Are you sure?", :onclick=>"destroyJsFunction()", :class => "start_spinner" %>
# expected output
# => <a href="/foo/delete/1" class='start_spinner' onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'CSRF_TOKEN'); f.appendChild(s);f.submit(); }; {destroyJsFunction()}; return false;">Delete</a>
# actual output
# => <a href="/foo/delete/1" class='start_spinner' onclick="if (confirm('Are you sure?')) { var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', 'CSRF_TOKEN'); f.appendChild(s);f.submit(); }; return false;">Delete</a>
END EDIT
Because I'm using Rails to submit the POST
request, I can't just re-write the link in plain HTML.
I'd like to run my javascript on click of a link with the class start_spinner
, but I can't find a way to re-display the link if the confirmation is false. Is there a way to have a separate javascript listen for the results of a confirmation dialogue?
4 Answers
Reset to default 3All confirm does is place some JavaScript in the HTML which does exactly what you describe: prompt the user and then submit the form on a success response.
If you want to do something different then you will have to write your own confirm method. Since the logic is so simple I'm sure the rails team felt if you wanted more you could write it yourself.
Make a function that does the confirm and if/else logic. I'd use my own unobtrusive JS like using jQuery to attach a click event but you could also use the rails link_to helper option :onclick
like you mentioned above (I personally detest this option.)
jQuery Example:
$(function() {
$('a.destroy').on('click', function(e) {
e.preventDefault();
var $el = $(this);
var response = confirm($el.data('confirm') || 'Are you sure?');
if (!response) { return; }
$el.css({'pointer-events': 'none'});
$.ajax({
url: $el.attr('href'),
type: 'DELETE',
data: {_method: 'delete'}
})
.then(function() {
alert('Deleted! we should do something here');
})
.fail(function() {
alert('Opps, it didn\'t delete, check the respose to see why.');
})
.always(function() {
$el.css({'pointer-events': 'auto'});
});
});
// Only for SO example not needed for real code
$('#reset').on('click', function(e) {
e.preventDefault();
$('a').css({'pointer-events': 'auto'});
});
});
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#/path/with/:id" class="destroy" data-confirm="Are your sure?">Confirm?</a>
(<a href="#" id="reset" title="this is not need in real code">reset</a>)
Short answer: kind of, sort of, but it's a little hacky.
So you want to know if the clicking of the link was confirmed or not. The only way to tell from elsewhere (without being able to inject a callback, which it sounds like would be a Rails issue) is to capture the event and check if the default action was prevented (which is what return confirm()
is doing here).
Using jQuery you could add some JS to the page like so:
$('#confirm-link').click(function(e) {
if (e.isDefaultPrevented()) {
alert("I feel rejected")
} else {
alert("I feel confirmed")
}
})
I twiddled with JSFiddle. It'll be a little brittle, though.
If you trigger the delete link as an Ajax call, then you can render a js.erb
file that can handle the display after you confirm the dialog. For example:
AJAX trigger in the view:
<li id="post_<%= post.id %>">
<%= link_to "Delete", post_path(post), method: :delete, data: { confirm: "Are you sure you want to remove this post?" }, remote: true %>
</li>
Controller:
# app/controller/posts_controller.rb
class PostsController < ApplicationController
def destroy
@post = Post.find(params[:id])
@post.destroy
end
end
Rendered view:
# app/views/posts/destroy.js.erb
$('#post_<%= @post.id %>').hide()
If you are using Rails UJS's data-confirm
and want to run some custom script based on whether the confirm was true or not, use the confirm:plete
event:
= link_to "#", data: { confirm: "Are you sure?"}, class: "btn-remove" do
JS:
$('.list').on('confirm:plete', '.btn-remove', function removeCallback(ev, answer) {
if (answer) {
// Remove some element
}
return false; // prevents jumping to top of page.
});