8

目标

我有一个包含项目列表的页面,来自 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?" }

编辑.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 方法?

重复

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

4

5 回答 5

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”的函数。它像“on”一样工作,但会跟踪 DOM 的变化。但是在当前版本的 jQuery 中,这个函数被弃用了,因为它很慢。

希望你能理解我糟糕的英语 =)

于 2013-05-17T17:32:48.333 回答
2

我得到这个工作的方式是为此使用内置的 Rails 功能:

  1. 在控制器的编辑操作中,将respond_to行添加到块中format.js。这允许您创建一个edit.js.erb文件,您可以使用该文件将编辑表单加载到您的 DOM 中。
  2. 然后在同一个控制器的更新操作中,再次添加format.jsrespond_to块中,并拥有一个update.js.erb文件,该文件通过 jQuery 执行必要的 DOM 操作。

我确信这在在线教程中得到了进一步的解释,但是我最终在CodeSchool.com上了解了它是如何工作而无需调用 jquery ajax 方法的。

于 2013-05-17T17:29:27.567 回答
2

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

发现 1

虽然让ajax:success被解雇似乎不是问题,但看起来表单处理并没有在$("#editor")选择器上 100% 正确工作。至少需要这样$("#editor form"),但如果我们从索引页开始,那可能行不通,它还没有包含表单。因此,@Jake Smith 建议的方法似乎是最可靠的方法。这导致:

编辑.html.haml

#editor
  = render :partial => "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行为,这是服务器不喜欢的,因为它期望 aPUT到达该update操作。Rails 通过生成一个_method带有 value 的隐藏字段来做到这一点PUT。我发现 rails在部分的最顶部而不是在标签内生成这个字段(以及其他几个关键的隐藏字段)!所以我把表格移到了部分的顶部,它起作用了!_edit.html.hamlform

_edit.html.haml(工作!)

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

谁会猜到...

于 2013-05-17T22:41:17.553 回答
0

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

如何使用 $(document).on("click.. on <a 标签?

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

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

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

于 2015-05-07T14:08:41.157 回答
-1

我有同样的问题,终于明白了原因。您的 html 源代码必须如下构成。

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

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

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

于 2015-09-30T16:09:07.347 回答