Rails:无法提交通过Ajax加载的远程表单

时间:2013-05-17 16:33:52

标签: jquery ruby-on-rails ujs

目标

我有一个包含Rails后端的项目列表的页面。我希望能够通过Rails UJS使用Ajax调用来编辑该列表中的一行。

方法

我在每行的末尾添加了一个编辑按钮。编辑按钮是一个 link_to ... :remote => true。单击它会再次加载列表,但是会选中 在编辑模式下行。可编辑行嵌入form ... :remote => true中。 该行中的保存按钮是submit按钮。

index.html.haml

#editor
  %table
    - @items.each do |item|
      %tr
        = render :partial => 'row', :locals => { :item => item }

_row.html.haml

... 
%td // a number of columns with attributes
...
%td
  = link_to t("actions.edit"), edit_item_path(item), :remote => true
  = link_to t("actions.delete"), item_path(item), :remote => true, :method => :delete, :data => { :confirm => "Are you sure?" }

edit.html.haml

#editor
  %table
    - @items.each do |item|
      %tr
        - if item == @item
          = form_for @item, :url => item_path(@item), :remote => true, do |f|
            = render :partial => "row_form", :locals => { :f => f }
        - else
          = render :partial => 'row', :locals => { :item => item }

_row_form.html.haml

... 
%td // a number of columns with editable attributes
...
%td
  %button{ :type => "submit" }=t("actions.save")
  = link_to t("actions.cancel"), items_path, :remote => true

Ajax响应处理

$("#editor").on("ajax:success", function(event, data, status, xhr) {
  $("#editor").html($(data).find("#editor").html());
});

问题

当我在编辑模式/items/12/edit中加载列表页面时,项目12的行是 编辑。单击保存按钮正确地通过Ajax提交表单并加载 /items索引部分,用jQuery替换可编辑列表。点击 再次编辑按钮,再次加载编辑页面(例如/items/12/edit) 嵌入式表格。只有这一次,表单不再提交了 单击保存按钮。似乎提交事件处理程序没有附加到 动态加载的远程表单。

问题

如何通过Ajax提交加载的远程表单,最好使用Rails UJS方法?

重复

我知道这个问题有重复,但没有一个得到回答。我希望有人最终得出一个明确的答案。

5 个答案:

答案 0 :(得分:3)

问题是DOM是由javascript修改的,并且回调(在你的例子中是ajax成功)只在DOM init上初始化。所以当DOM改变时(在#editor的一部分中)回调没有用。

因此,每次使用javascript

更改DOM时,都应重新初始化此回调
$("#editor").on("ajax:success", function(event, data, status, xhr) {
  $("#editor").html($(data).find("#editor").html());
});

前段时间jQuery的功能称为“live”。它像“开启”一样工作,但跟踪了DOM的变化。但是在当前版本的jQuery中,这个函数已被弃用,因为它很慢。

希望你能理解我的英语不好=)

答案 1 :(得分:2)

我使用它的方法是使用内置的Rails功能:

  1. 在控制器的编辑操作中,将respond_to块添加到行format.js。这允许您创建一个 edit.js.erb 文件,您可以使用该文件将编辑表单加载到DOM中。
  2. 然后在同一控制器的更新操作中,再次将format.js添加到respond_to块,并拥有执行必要DOM的 update.js.erb 文件通过jQuery进行操作。
  3. 我确信这在网上教程中得到了进一步的解释,但是我终于明白了它如何工作而不必调用jquery ajax方法是在CodeSchool.com

答案 2 :(得分:2)

我发现了问题!感谢@Jake Smith和@Parandroid的答案提示。这是我分两步找到的。

发现1

虽然获得ajax:success被解雇似乎不是问题,但看起来表单处理在$("#editor")选择器上只能100%正确工作。至少需要$("#editor form"),但如果我们从索引页面开始,它可能不起作用,索引页面还没有包含表单。所以@Jake Smith提出的方法似乎是最有力的方法。这导致:

<强> edit.html.haml

#editor
  = render :partial => "edit"

<强> edit.js.erb

$('#editor').html('<%= escape_javascript render("edit") %>');

_edit.html.haml(仍无效)

%table
  - @items.each do |item|
    %tr
      - if item == @item
        = form_for @item, :url => item_path(@item), :remote => true, do |f|
          = render :partial => "row_form", :locals => { :f => f }
      - else
        = render :partial => 'row', :locals => { :item => item }

但是这仍然没有导致工作提交按钮。直到我发现出了什么问题...

发现2

上面的解决方案确实为提交按钮提供了旧的POST行为,服务器不喜欢这种行为,因为它期望PUT达到update行为。 Rails通过生成值为_method的隐藏PUT字段来实现此目的。我发现rails生成了这个字段(以及其他几个关键的隐藏字段){strong>位于_edit.html.haml部分的 1}}标签!所以我把表单移到了部分的顶部,它运作了!

_edit.html.haml(工作!)

form

谁会猜到......

答案 3 :(得分:0)

我有一个与此类似的问题,即通过ajax加载的表单未提交,这是由于Turbolinks,我发现解决方案是将我的事件绑定到正文而不是元素,相关答案在这个帖子中找到:

How to use $(document).on("click.. on <a tag?

对我来说,问题在于点击标签,所以我不得不改变

$('label').click(function...

$('body').on('click', 'label', function

答案 4 :(得分:-1)

我有同样的问题,最后了解原因。 您的html源必须由以下内容组成。

<tr>
  <form>
    <td><input type="text"></td>
    <td><input type="submit"></td>
  </form>
</tr>

似乎某些浏览器(包括Chrome和Firefox)无法正确处理此类嵌套代码。

在用其他类似ul / li替换table / tr / td标签后,我可以成功提交重新呈现的表单。