我正在尝试克服Rails中动态表单字段的障碍-
这似乎是框架无法很好地处理的。我也在我的项目中使用jQuery。我已经安装了jRails,但是我更愿意在可能的情况下毫不干扰地编写AJAX代码。
我的表单相当复杂,嵌套的两个或三个级别并不罕见。我遇到的问题是生成正确的表单ID,因为它们是如此依赖于表单构建器上下文。我需要能够动态添加新字段或删除has_many
关系中的现有记录,而我完全不知所措。
到目前为止,我所看到的每个示例都以一种或另一种方式丑陋。Ryan
Bates的教程要求使用RJS,这会导致标记中出现一些难看的JavaScript,而且似乎是在嵌套属性之前编写的。我已经看到了使用不引人注目的jQuery的该示例的分支,但是我只是不了解它在做什么,并且无法使其在我的项目中正常工作。
有人可以提供一个简单的示例说明如何完成此操作吗?在遵守控制器的RESTful约定的情况下,这甚至可能吗?
安迪发布了删除现有记录的绝佳示例,有人可以提供创建具有正确属性的新字段的示例吗?我还无法弄清楚如何使用嵌套表单。
由于没有人对此提供答案,即使是悬赏,我终于设法自己解决了这个问题。这不应该是一个树桩!希望这将在Rails 3.0中更容易实现。
Andy的示例是直接删除记录的好方法,而无需向服务器提交表单。在这种情况下,我真正想要的是一种在对嵌套表单进行更新之前动态添加/删除字段的方法。这是一种稍微不同的情况,因为随着字段的删除,在提交表单之前,它们实际上并未删除。我可能最终会根据情况同时使用两者。
我已经基于Tim Riley在github上的complex-forms-
examples
分支实现了我的实现。
首先设置模型,并确保它们支持嵌套属性:
class Person < ActiveRecord::Base
has_many :phone_numbers, :dependent => :destroy
accepts_nested_attributes_for :phone_numbers, :reject_if => lambda { |p| p.values.all?(&:blank?) }, :allow_destroy => true
end
class PhoneNumber < ActiveRecord::Base
belongs_to :person
end
为PhoneNumber的表单字段创建局部视图:
<div class="fields">
<%= f.text_field :description %>
<%= f.text_field :number %>
</div>
接下来为Person模型编写一个基本的编辑视图:
<% form_for @person, :builder => LabeledFormBuilder do |f| -%>
<%= f.text_field :name %>
<%= f.text_field :email %>
<% f.fields_for :phone_numbers do |ph| -%>
<%= render :partial => 'phone_number', :locals => { :f => ph } %>
<% end -%>
<%= f.submit "Save" %>
<% end -%>
这将通过为PhoneNumber模型创建一组模板字段来实现,我们可以使用javascript复制这些模板字段。我们将app/helpers/application_helper.rb
为此创建辅助方法:
def new_child_fields_template(form_builder, association, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(association).klass.new
options[:partial] ||= association.to_s.singularize
options[:form_builder_local] ||= :f
content_tag(:div, :id => "#{association}_fields_template", :style => "display: none") do
form_builder.fields_for(association, options[:object], :child_index => "new_#{association}") do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
end
def add_child_link(name, association)
link_to(name, "javascript:void(0)", :class => "add_child", :"data-association" => association)
end
def remove_child_link(name, f)
f.hidden_field(:_destroy) + link_to(name, "javascript:void(0)", :class => "remove_child")
end
现在,将这些帮助程序方法添加到edit部分:
<% form_for @person, :builder => LabeledFormBuilder do |f| -%>
<%= f.text_field :name %>
<%= f.text_field :email %>
<% f.fields_for :phone_numbers do |ph| -%>
<%= render :partial => 'phone_number', :locals => { :f => ph } %>
<% end -%>
<p><%= add_child_link "New Phone Number", :phone_numbers %></p>
<%= new_child_fields_template f, :phone_numbers %>
<%= f.submit "Save" %>
<% end -%>
您现在已经完成了js模板。它将为每个关联提交一个空白模板,但是:reject_if
模型中的子句将丢弃它们,仅保留用户创建的字段。 更新:
我已经重新考虑了这种设计,请参见下文。
这并不是真正的AJAX,因为除了页面加载和表单提交之外,没有任何通信可以进行到服务器,但是老实说,我实在找不到一种方法。
实际上,这可以提供比AJAX更好的用户体验,因为您无需等待服务器对每个其他字段的响应就可以完成。
最后,我们需要使用javascript将其连接起来。将以下内容添加到您的“ public / javascripts /
application.js”文件中:
$(function() {
$('form a.add_child').click(function() {
var association = $(this).attr('data-association');
var template = $('#' + association + '_fields_template').html();
var regexp = new RegExp('new_' + association, 'g');
var new_id = new Date().getTime();
$(this).parent().before(template.replace(regexp, new_id));
return false;
});
$('form a.remove_child').live('click', function() {
var hidden_field = $(this).prev('input[type=hidden]')[0];
if(hidden_field) {
hidden_field.value = '1';
}
$(this).parents('.fields').hide();
return false;
});
});
到此时,您应该拥有准系统的动态表单!这里的javascript非常简单,可以很容易地用其他框架完成。例如,您可以轻松地application.js
用原型+
lowpro
替换我的代码。其基本思想是,您无需将巨大的javascript函数嵌入到标记中,也不必phone_numbers=()
在模型中编写繁琐的函数。一切正常。万岁!
经过一些进一步的测试,我得出结论,需要将模板移出<form>
字段。将它们保留在此处意味着它们将与表单的其余部分一起发送回服务器,这只会在以后造成麻烦。
我将其添加到布局的底部:
<div id="jstemplates">
<%= yield :jstemplates %>
</div
并修改了new_child_fields_template
助手:
def new_child_fields_template(form_builder, association, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(association).klass.new
options[:partial] ||= association.to_s.singularize
options[:form_builder_local] ||= :f
content_for :jstemplates do
content_tag(:div, :id => "#{association}_fields_template", :style => "display: none") do
form_builder.fields_for(association, options[:object], :child_index => "new_#{association}") do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
end
end
现在,您可以:reject_if
从模型中删除这些子句,而不必担心模板被发回。
问题内容: 尝试将指令添加到具有动态ID的输入时,链接方法未正确绑定到该对象。给定以下jsfiddle或html: 和js: 我在控制台调试器上看到的是,当链接被调用时,其ID实际上显示为“ datepicker-{{{id}}””而不是“ datepicker-7”。 有办法强迫这种情况发生吗?实施此方法的更好方法? 更新 :应该已经澄清。单击日期选择器会显示出来,但是单击日期不起作用。我收到错
问题内容: 我有一个带有jquery验证的表单。提交表单后,我通过Ajax加载相同的表单。我的问题是jquery验证不适用于ajax加载的表单。我已经尝试了一些有关堆栈溢出的答案,但是不幸的是它没有用。 谢谢阿兹 问题答案: 在 功能上使用 。。 例:
问题内容: 我的要求是,当用户在可能也会动态添加的输入字段之一中输入一些字符(最少3个)时,显示几个选项。 由于数据量巨大,我一开始无法在页面加载时加载数据。有一个ajax调用来获取经过过滤的数据。 我得到的问题是第2行的页面加载错误。那么,请问以下代码有什么问题吗? 问题答案: 如何使用另一种方法:创建输入时初始化自动完成功能: jsFiddle与AJAX
问题内容: 我正在从事类似在线商店的工作。我正在制作一个表格,客户在其中购买商品,她可以选择要购买的商品数量。但是,在她购买的每件商品上,她都需要选择其颜色。因此,字段的数量是不固定的:如果客户购买3件商品,她应该得到3个用于选择颜色的盒子,如果她购买7件商品,则应该得到7个这样的盒子。 我将使用JavaScript使HTML表单字段显示和消失。但是我该如何在Django表单类上处理呢?我看到表单
问题内容: 在我的网站上,我正在创建发票功能。发票具有静态信息:公司信息和收件人信息。但是它也具有动态信息:小时数,描述,总金额等。客户可以使用上面的动态信息添加多行。 现在我的问题是,如何将其实现到数据库中? 目前,我有一个名为“发票”的表,其中的列将包含上面的所有信息。但是通过这种方式,行将具有不必要的信息,例如公司和收货人信息,而实际上每个发票只需要插入一次即可。 你们认为我将如何解决这个问
问题内容: 我有一个使用ajax动态创建的表单(因为表单元素的数据必须来自数据库),我想序列化表单元素以由ajax提交。我目前正在使用jQuery网站上的代码测试我的理论,以查看是否可以拾取表单元素,这就是问题所在: 我需要在提交之前对数据进行一些更改,并且尚未编写此代码,但是我发现,页面加载时存在的页面上的所有输入元素均被正确拾取,可以正确拾取使用Javascript填充的内容,但是将忽略使用A