挂钩到Rails内置远程:true'ajax:成功'事件

hook into Rails built-in remote: true 'ajax:success' event

本文关键字:ajax 成功 事件 Rails true 内置      更新时间:2023-09-26

几个星期以来,我一直在回避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事件。我遵循了这个链接的建议。然而,"ajax:成功"并没有被称为:

 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:成功"事件?

我解决了这个问题。我的目标是消除不必要的使用类似的东西:

$.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设置为"script",因此HTTP请求标头Accept标头设置为"application/javascript"。因此,响应中的内容类型将是: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函数创建的闭包。

我不知道你的$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();
});