【问题标题】:Processing an AJAX call in Rails 4 (success, error, beforeSend, complete)在 Rails 4 中处理 AJAX 调用(成功、错误、beforeSend、完成)
【发布时间】:2014-03-29 10:16:12
【问题描述】:

我想知道在Rails 4中处理ajax调用的正确方法是什么(使用remote:true选项时),问题是我想在处理过程中使用所有经典步骤,例如成功,错误,beforeSend 并完成。

假设我有这个按钮,它会加载一个带有一些 ajax 的模式窗口:

查看(产品/索引):

<%= link_to('Order this', new_order_path(product: product), remote: true) %> 

orders_controller:

  def new
        @order = Order.new
        @product = Product.find(params[:product])

        respond_to do |format|
          format.html
          format.js
        end
      end

new.js.erb:

(function(){
  var $modalWindow = ...
  // some code that loads the modal window and closes it

  $modalWindow.html("<%= j render('form') %>"); // puts the needed product form 
                                                   into my modal window
}());

这很好用,但是这段代码中的之前/之后/成功/错误在哪里?

接下来,当点击“订购产品”按钮时,我的订单控制器中有这个:

def create
    @product = Product.find_by(params[:id])
    @order = current_office.orders.build(order_params)

    respond_to do |format|
      if @order.save

        format.html { 
          flash[:success] = 'Order created'
          redirect_to products_url
        }
        format.js
      else
        render :new
        format.html { render :new }
        format.js   { render :js=>'alert("ajax error");' }
      end
    end
  end

再次,当单击“创建”按钮时,如何进行处理?我的 create.js.erb 只关闭模式窗口,但我希望它能够完全处理请求,在发送前显示预加载器,然后显示成功/错误,然后再显示。

希望不要太混乱!

【问题讨论】:

    标签: jquery ruby-on-rails ruby ajax ruby-on-rails-4


    【解决方案1】:

    这段代码中的之前/之后/成功/错误在哪里?

    ajax events 不属于该代码 - 因为它们不能绑定到原始 DOM 元素。您需要将它们放在原始 JS 中 - 因为只有这样才能将元素绑定到发送请求的 DOM 元素:

    #app/assets/javascripts/application.js
    $(document).on("ajax:success", "#element", function() {
        //do something
    });
    

    这里有一个很好的资源:@​​987654321@


    后端

    如果您要在后端处理处理代码,则需要使用某种验证来确定应该发生什么:

     #app/controllers/orders_controller.rb
     def new
        @order = Order.new
        @product = Product.find(params[:product])
    
        respond_to do |format|
          format.html
          format.js { @state = "success" }
        end
      end
    
    #app/views/orders/new.js.erb
    (function(){
      <% if @state && @state == "success" %>
          var $modalWindow = ...
              $modalWindow.html("<%= j render('form') %>");
      <% else %>
          alert ("not successful");
      <% end %>
    }());
    

    前端

    如果你想在前端处理 ajax 请求,你最好这样做:

    #app/assets/javascripts/application.js
    $(document).on("ajax:success", "#element", function(){
        //do something
    });
    

    插件

    我还没有这方面的任何文档:

    (function( $ ){        
    
       $.fn.leanModal = function(options) {
    
            //Defaults
            var defaults = {
                overlay: 0.5,
                overlay_color: "#000",
                closeButton: null,
                delay: null,
                drag: ".modal_title",
                removeModal: null,
                autoLoad: null,
                ajax: false
            };
    
            //Definitions
            var xhr;
            var plugin = this;
            var options = $.extend(defaults, options);
    
            //Init
            plugin.init = function() {
    
                if(options.autoLoad){
                    $.extend(options, {modal_id: $(this)});
                    create();
                }else{
                    return this.each(function() {
                        $(this).click(function(e) {
                            e.preventDefault();
                            var href = $(this).attr("href");
                            var image = CheckImg(href);
    
                            var random = Math.floor(Math.random()*90000) + 10000;
                            var extras = (options.ajax || image) ? {modal_id: "#modal_" + random, ajax: href.replace(/\/$/, '')} : {modal_id: href};
    
                            $.extend(options, extras);
                            create();
                        });
                    }); 
                }
            }
    
            //////////////////
            //    Actions   //
            //////////////////
    
            //Build
            var create = function() {
                if(options.ajax){
    
                    //Loading
                    load();
    
                    //Image
                    switch (true) {
                        case CheckImg(options.ajax):
                            append("img", options.modal_id.substring(1), options.ajax);
                            show();
                            break;
                        default:
                            fetch(options.ajax, function(data){
                                append("modal", options.modal_id.substring(1), options.ajax, data);
                                show();
                            }, function(xhr, text_status, error_thrown){
                                load();
                                alert("Sorry, there was an error!");
                            });
                            break;
                    }
    
                }else{
                    show();
                }
            }
    
            //Ajax
            var fetch = function(link, success, error) {
                xhr = 
                $.ajax({
                    url: link,
                    success: function(data) { success(data); },
                    error: function(data)   { error(data); }
                });
            }
    
            //Overlay
            var olay = function(modal_id, removeModal, closeButton, ajax) {
                var overlay = document.createElement("div");
                    overlay.setAttribute("id", "lean_overlay");
    
                document.body.appendChild(overlay);
                overlay.onclick = function() { close(modal_id, removeModal, $(closeButton), ajax); return false; };
            }
    
            //Show
            var show = function() {
    
                /* Vars */
                var id          = options.modal_id
                var removeModal = options.removeModal
                var closeButton = options.closeButton
                var drag        = options.drag
                var ajax        = options.ajax
                var opacity     = options.overlay
    
                /* Overlay */
                olay(id, removeModal, closeButton, ajax);
    
                /* Elements */
                var modal       = $(id);
                var overlay     = $("#lean_overlay");
    
                /* Display */
                var disp        = "test";
    
                /* Options */
                if (closeButton) {
                    $(closeButton).css("z-index", "900");
                    $(closeButton).on("click", function (e) {
                        e.preventDefault();
                        close(id, removeModal, $(closeButton));
                        return false;
                    });
                }
    
                /* Load */
                if (ajax) {
                    modal.waitUntilExists(function() {
                        load();
                        display($("#lean_overlay"), options.overlay_color, $(options.modal_id), options.overlay, options.drag);
                    })
                } else { display($("#lean_overlay"), options.overlay_color, $(options.modal_id), options.modal, options.overlay, options.drag); }
            }
    
            //Close
            var close = function(modal, removeModal, closeButton, ajax) {
    
                /* Ajax */
                if(ajax){
                    if (xhr) { xhr.abort(); }
                    load(true);
                }
    
                /* Overlay */
                $("#lean_overlay").fadeOut(150, function(){
                    $(this).remove();
                    if(closeButton) {
                        closeButton.off("click");
                        closeButton.removeAttr('style');
                    }
                });
    
                /* Modal */
                $(modal).fadeOut(150, function(){
                    if (removeModal) {
                        $(this).remove();
                     }
                });
    
            }
    
            //Go
            plugin.init();
       }; 
    
    
        //////////////////
        // Dependencies //
        //////////////////
    
        //Image?
        var CheckImg   = function(url) { if(url) { return(url.match(/\.(jpeg|jpg|gif|png)/) != null); }}
    
        //Create
        var append     = function(type, id, src, data) {
    
            //Definitions
            var style = element = type;
    
            if (type == "modal") {
                var style = "ajax";
                var element = "div";
            }
    
            //Element
            var el = document.createElement(element);
                el.setAttribute("id", id);
                el.setAttribute("src", src);
                el.className = 'modal ' + style;
    
            //Ajax
            if (data) { el.innerHTML = data; }
    
            //Append
            document.body.appendChild(el);
        }
    
        //Show
        var display = function(overlay, overlay_color, modal, opacity, drag)    {
    
            /* Styling */
            overlay.css({
                "display": "block",
                "background": overlay_color,
                opacity: 0
            });
            modal.css({
                "display": "block",
                "position": "fixed",
                "opacity": 0,
                "z-index": 10200,
                "left": 0,
                "right": 0,
                "top": 0,
                "bottom": 0,
                "margin": "auto"
            });
    
            /* Init */
            overlay.fadeTo(150, opacity);
            modal.fadeTo(200, 1);
            if(drag.length > 0) { modal.draggable({ handle: drag }); }
    
        }
    
        //Ajax Load
        var load  = function(close) {
            if (close) { $(document).ajax_load({close: true});  } else {  $(document).ajax_load(); }
        }
    
    })( jQuery );
    

    用法

    #app/assets/javascripts/application.js
    var load = function() {
        $('a[rel*=LeanModal]').leanModal({
            overlay: 0.9,
            removeModal: true,
            closeButton: ".title .close"
            ajax: true,
            drag: ".title"
        });
    }
    $(document).on("ready page:load", load);
    
    #app/assets/sytlesheets/application.css.sass
    /Overlay
    #lean_overlay
    position: fixed
    z-index: 1500
    top: 0px
    left: 0px
    height: 100%
    width: 100%
    display: none
    
    &:hover
        cursor: pointer
    
     // Modal
     .modal
        //styling here
    
    
    #app/views/application/index.html.erb
    <%= link_to "test_ajax", ajax_path, rel: "LeanModal" %>
    
    #app/controllers/application_controller.rb
    layout Proc.new {|controller| controller.request.xhr? ? false : "application" }
    

    【讨论】:

    • 这是一个很好的答案,非常感谢。 $(document).on("ajax:success"... 我可以看到的一个问题是,如果我执行多个不同的 ajax 操作,我的应用程序对每个操作都会有相同的反应?
    • 谢谢!回复:$(document)——如果你委托给发起请求的元素,则不会——learn.jquery.com/events/event-delegation
    • 谢谢。现在我认为将 ruby​​ 代码与 JS 混合可能是一种不好的做法,尤其是在未来。我可能只使用 Javascript 并以经典的方式做事,通过好的 ol $.ajax
    • 这取决于你想要达到的目标。如果你想加载一个模态,我们实际上已经基于leanmodal 做了一个支持 Ajax 的模态。如果你愿意,我可以分享代码吗?它基本上允许您调用视图和插件处理其余部分
    • 我说的是一般的应用程序 ajaxifying,但是是的,很想看看你的插件并学习一些东西。
    猜你喜欢
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 2013-01-13
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多