最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ruby on rails - Can javascript listen for the result of a confirm dialogue from a separate method? - Stack Overflow

programmeradmin4浏览0评论

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?

Share Improve this question edited Nov 5, 2014 at 10:10 joanwolk asked Nov 4, 2014 at 11:57 joanwolkjoanwolk 1,1051 gold badge16 silver badges27 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

All 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.
});

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论