【问题标题】:Ajax Forms with Rails 3 - Best Practice?Rails 3 的 Ajax 表单 - 最佳实践?
【发布时间】:2012-01-01 08:10:19
【问题描述】:

什么是 Ajax 表单的 Rails 方式

直到今天,我还认为我使用 Rails 表单 + jQuery UJS 的方式是正确的,但升级到 jQuery 1.7 时“破坏”了我目前的做法。

如何做到这一点?

我想在我的表单中使用 Ajax。 ajax 响应应该再次呈现表单(例如,当发生错误时)或重定向到成功页面。 (它可能应该做更多的事情,比如显示模态,但我想让这个例子保持简单)。

1。使用 EJS 和 $('#formid').html(...)

这就是我迄今为止所做的。我的 ajax 响应是一个 ejs 模板,它返回 javascript 代码以再次呈现表单(有错误)或取决于是否是错误将用户重定向到成功页面:

<% unless @success_submit %>
$('#form_wrapper').html('<%= escape_javacsript( render :partial => 'form' ) %>'); 
<% else %>
document.location = '/success_thank_you';
<% endif %>

现在假设表单包含一个错误消息 div,例如

<div class="error_message">BlaBla</div>

为了添加一个很好的效果,我在 ajax complete 上绑定了一个通用的 jQuery.live 事件,该事件突出显示了错误。

$('form').live('ajax:complete', function() {
   // do stuff like highlighting all error messages in that form
}); 

这不再适用于 jQuery1.7 + jquery-ujs(可能有充分的理由)。所以我想我这样做的方式不对。

2。使用上述方式,但重复自己

我可以在 EJS 中执行“错误突出显示”,而不是绑定 ajax:complete 事件,例如

$('#form_wrapper').html('<%= escape_javascript( render :partial => 'form' ) %>');
$('#form_wrapper form .error_message').fadeIn();

但这意味着我必须在几乎每个呈现表单的 EJS 中重复第二行。当然,我想让它保持干燥。

3。 Ajax响应呈现纯html,ajax:complete事件处理显示

一个完全不同的解决方案是,ajax 响应将简单地呈现纯 html,而我的自定义 ajax:complete 处理程序将负责显示表单。处理程序看起来像

$('form').live('ajax:success', function(ev, data, status, xhr) {
  $(this).html(data);
  // and e.g. highlight stuff
  $(this).children('.error_message').fadeIn();
});

那会奏效。但是现在,如果我的服务器决定不再呈现表单(例如,在成功注册后)而是重定向到另一个 url 或显示模式表单,我该怎么办。服务器可以响应类似的东西

<script>
   document.location = '/success.blabla/';
</script>

但这是一个好的解决方案吗?

4。自定义 JSON 协议

可能一个好的解决方案是使用版本 3,但我们可以创建一些自定义 json 协议,而不是简单地用返回的 html 替换当前表单。这样我们甚至可以让服务器响应类似

  1. 首次显示模式(如“注册成功”)
  2. 重定向到登录页面

ajax:success 处理程序可以检查响应是否为纯 html,在这种情况下,它将用 html 代码替换当前表单。但是如果响应是一个 JSON 数组,它会处理它,例如服务器响应

{ html: '<%= render :partial => 'something' %>', 
  show_modal:  '<%= render :partial => 'modal_template' %>',
  redirect_after_modal: '/login_page'
}

ajax:success 处理程序会像处理它一样

$('form').live('ajax:success', function(ev, data, status, xhr) {
   // try parsing json
   if (data.json['show_modal') { // show modal code.... }; 
   if (data.json['redirect']) { document.location=data.json['redirect']);...
});

你是怎么做这些东西的

显然,您可以通过多种方式处理 ajax 表单。但是你是怎么做的,什么是 Rails 的最佳实践?

【问题讨论】:

    标签: ruby-on-rails ajax forms unobtrusive-javascript


    【解决方案1】:

    所以,我只能将您的问题归结为 jquery,果然是 works in jquery 1.6.4,但 not in jquery 1.7

    似乎如果你替换 DOM 中的一个元素,然后在从原始元素创建的 jquery 对象上触发一个事件,1.6.4 仍然会在元素原始位置触发事件并允许它向上传播DOM。但是,1.7 不会触发元素(这更有意义)。

    我刚刚通过 jquery 1.7 更新日志进行了搜索,果然,以下是纠正此行为的两张票:995110489

    要回答您关于完成此类事情的最佳实践是什么的问题,我想说,控制您的事件触发的顺序。 jQuery 会自动执行 ajax 响应中返回的 JS,这意味着您无法控制何时发生。

    修改代码最简单的方法是返回 HTML 部分本身,然后使用 jquery 将表单替换为 ajax:completeajax:success/ajax:error 处理程序中返回的 HTML。这样您就可以确保事情按照您想要的确切顺序发生。

    要了解具体如何做到这一点,请尝试阅读 [我的文章]:

    或查看the jquery-ujs wiki 获取这些链接及更多信息。

    【讨论】:

    • 嗨@jangosteve你能看看这个吗:stackoverflow.com/questions/19384720/…
    • EJS 中的setTimeout(function() { $('#formid').html(...) }); 怎么样? setTimeout 将替换到下次触发 ajax:* 事件之后发生。
    【解决方案2】:

    不确定您是否需要它,但这里我们为使用 AJAX 实现表单所做的工作

    假设我们有一个看起来像这样的动作

    def new
      @saved_search = SavedSearch.new
    new
    
    def create
      if @saved_search.save
        respond_to do |format|
          format.js { render :saved }
        end
      else
        respond_to do |format|
          format.js { render :new }
        end
      end
    end
    

    我们有一个看起来像这样的表单

    # app/views/saved_searches/new.html.erb
    <%= form_for @saved_search,  url: saved_searches_path(format: :js), remote: true do |f| %>
      <div class="form">
        <div class="content">
          <div class="field">
            <%= f.label(:name, t(".name_search"), class: "label") %>
            <%= f.text_field(:name, size: "25", autofocus: "autofocus") %>
          </div>
    
          <div class="clear"></div>
        </div>
    
        <footer class="clear">
          <div class="left">
            <%= f.button t(".save"), class: "button" %>
          </div>
          <div class="clear"></div>
        </footer>
      </div>
    <% end %>
    

    而且,显然,如果某些字段无效,我们希望返回错误。所以这里有一个技巧

    # app/views/saved_searches/new.js.erb
    <%- @saved_search.errors.keys.each do |field| %>
      $('#saved_search_<%= field %>').after("<span class=\"errors\">&nbsp;<%=   @saved_search.errors[field].join(',')  %></span>")
      $('#saved_search_<%= field %>').wrap('<div class="field_with_errors" />');;
    <% end %>
    

    这不会破坏 JQuery 绑定或回调,但仍会向您显示错误。

    我现在认为编写一些表单构建器可能是个好主意,它既能够呈现 HTML 表单,又能够为表单字段返回一堆 JQuery 指令,采用

    Rails.configuration.action_view.field_error_proc
    

    考虑

    【讨论】:

      猜你喜欢
      • 2021-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-29
      • 1970-01-01
      相关资源
      最近更新 更多