钩入Rails内置的远程:真正的'ajax:成功'事件

时间:2016-05-04 21:29:43

标签: javascript ruby-on-rails ajax

几周以来,我一直在避免使用rails.js和remote: true提供的Rails UJS“Ajax助手”。结果,我做了这样的事情:

// erb
<li>
  <button type="button" class="btn btn-default btn-md">
    <span class="glyphicon glyphicon-remove" aria-hidden="true"></span><%= tagging.tag.name %>
    <%= hidden_field_tag :id, tagging.id %>
  </button>
</li>

// js
    remove_tag: function(){
        $view.on('click','.cloud .glyphicon-remove', function(){  
            var id = $(this).next().val();              
            $.ajax({
                type: "POST",
                data: {id: id},
                url: 'taggings/destroy',
                beforeSend: function() {
                    $('.loading').show();
                },
                complete: function(){
                    $('.loading').hide();
                },
                success: function(resp){
                   alert( resp );
                }
            });
        })
    },

但是反复做这件事显然需要付出很多努力。所以我决定使用remote: true和rails.js内置的不引人注目的功能更优雅:

 <li>
  <button type="button" class="btn btn-default btn-md">
    <%= link_to tagging, remote: true, method: :delete, class: 'remove-tag' do %>
      <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
    <% end %>
    <%= tagging.tag.name %>
  </button>
</li>

这转化为这个漂亮的代码:

<li>
  <button type="button" class="btn btn-default btn-md">
    <a class= "remove-tag" data-method="delete" data-remote="true" href="/taggings/1" rel="nofollow">
      <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
    </a>
    orange
  </button>
</li>   

现在我可以调用beforeSend并完成但是不会触发成功ajax事件。我遵循了this链接的建议。但是,'ajax:success'没有被称为:

 remove_tag: function(){
        $view.on('ajax:beforeSend', '.cloud .remove-tag', function(event, xhr, settings) {
            $('.loading').show();
        })

        $view.on('ajax:complete', '.cloud .remove-tag', function(event, xhr, settings) {
            $('.loading').hide();
        })

        $view.on('ajax:success', '.cloud .remove-tag', function(event, xhr, settings) {
            alert("It was a success!")
        })
    },

如何调用'ajax:success'事件?

2 个答案:

答案 0 :(得分:2)

我弄明白了这个问题。我的目标是消除不必要的使用:

$.ajax({
     type: "POST",
     data: $form.serialize(),
     url: $form.attr('action'),
     beforeSend: function() {
       $('.loading').show();
     },
     complete: function(){
       $('.loading').hide();
       $form.closest('.modal').modal('hide')
     },
     success: function(resp){
       console.log(resp);
     }
});

通过在链接上使用remote: true,Rails link_to帮助器生成data-remote属性,rails.js文件将为ajax请求添加事件监听器,因此不需要jquery $.ajax()方法。

我没有意识到的是,ajax调用BY DEFAULT将dataType设置为&#39;脚本&#39;因此,HTTP请求标头Accept标头设置为&#39; application / javascript&#39;。因此,响应中的内容类型将是:js(application / javascript)。这要求您定义:action.js.erb文件或传递块。但是如果你传递一个块,它将被一个被评估为JavaScript的块,而不是JSON或TEXT!因此,当我将JSON发送回浏览器时,它感到困惑。它期望评估javascript,而不是解析JSON,因此会发生解析错误。

$view.on('ajax:beforeSend', '.cloud .remove-tag', function(xhr, settings) {
    $('.loading').show();
})

$view.on('ajax:complete', '.cloud .remove-tag', function(xhr, status) {
    $('.loading').hide();
})

// this only triggered if you actually destroy record
$view.on('ajax:success', '.cloud .remove-tag', function(data, status, xhr) {
    $('.loading').hide();

    // JSON.parse not needed; status already parsed as json
    var data_id = JSON.parse(status['data-id']);
    $('.cloud').find("li[data-id='"+data_id['data-id']+"']").remove();
            })
$view.on('ajax:error', '.cloud .remove-tag', function(xhr, status, error) {
   console.log( error );
})

因此,ajax:error被触发而不是ajax:success。 当我更改链接以指定我想要json作为响应时,则ajax:success被触发。

<%= link_to tagging, remote: true, method: :delete, class: 'remove-tag', :'data-type' => 'json' do %>
  <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
<% end %>

那么为什么我选择返回JSON而不只是使用format.js并添加delete.js.erb文件?因为这意味着我必须在js.erb文件中引用DOM id或类,因为我会丢失我创建的模块的上下文。通过将数据传递回事件监听器,我能够继续使用javascript函数创建的闭包。

答案 1 :(得分:1)

我不知道,你的$view是什么,但下面的例子应该处理它。

$(document).ready(function() {
    //form id
    $('.remove-tag')
    .bind('ajax:success', function(evt, data, status, xhr) {
      //function called on status: 200 (for ex.)
      console.log('success');
      alert("It was a success!");
    })
    .bind("ajax:error", function(evt, xhr, status, error) {
      //function called on status: 401 or 500 (for ex.)
      console.log(xhr.responseText);
    });
  });

您还有第二个选项可以处理它,只需创建destroy.js.erb文件。

console.log("Coupon | destroy.js.erb file");

$('nav').after("<div class='alert alert-danger'> Successfully Destroyed </div>");
$(".coupon_" + <%= @coupon.id %>).fadeOut(250, function(){
    $(this).remove();
});