Cocoon 自动完成模态填充动态字段两次
Cocoon autocomplete Modal populating dynamic fields twice
我一直在开发一个 rails 跟踪基本事件的应用程序,我希望扩展它(这是我自己的生活数据跟踪应用程序)。我有一个 EventTemplate class,它存储 EventTemplateAttributes。创建新事件时,它使用 rails-jquery-autocomplete 来搜索现有模板并使用散列将其属性填充到表单中。这是该自动完成功能的代码:
def autocomplete_eventtemplate_name
respond_to do |format|
format.json {
@eventtemplates = Eventtemplate.where("name like ?", "%#{params[:term]}%")
render json: json_for_autocomplete_eventtemplates(@eventtemplates)
}
end
end
def json_for_autocomplete_eventtemplates(eventtemplates)
eventtemplates.collect do |eventtemplate|
attributes = Hash.new
unless eventtemplate.templateattributes.empty?
eventtemplate.templateattributes.each do |templateattribute|
attributes[templateattribute.id] = [templateattribute.name,templateattribute.value,templateattribute.unit]
end
end
hash = {"id" => eventtemplate.id.to_s, "value" => eventtemplate.name,"eventattributes" => attributes}
hash
end
end
这是我的表格:
<%= simple_form_for(@event) do |f| %>
<% if @event.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@event.errors.count, "error") %> prohibited this event from being saved:</h2>
<ul>
<% @event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<% if @event.new_record? %>
<% #,{:class=>"form-control"} %>
<%= f.autocomplete_field :name, autocomplete_eventtemplate_name_events_path,{:class => "form-control"} %>
<% else %>
<%= f.label :name %><br>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
</div>
<div id="#find-subj"></div>
<table class="table-striped table table-bordered">
<thead>
<td>Name</td>
<td>Value</td>
<td>Unit</td>
<td></td>
</thead>
<tbody id=eventattributes>
<tr>
<%= f.simple_fields_for(:eventattributes, :wrapper => false) do |tattribute| %>
<% if modal == false%>
<%= render 'eventattribute_fields', :f => tattribute %>
<% end %>
<% end %>
</tr>
</tbody>
</table>
<div class="links">
<%= link_to_add_association f, :eventattributes, :"data-association-insertion-node" => "tbody#eventattributes", :"data-association-insertion-method" => "append", class: 'btn btn-info' do %>
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
<% end %>
</div></br>
<div class="actions">
<%= f.submit class: 'btn btn-primary'%>
<%= link_to 'Cancel', events_path, class: 'btn btn-warning' %>
</div>
<% end %>
这里是 _eventattribute_fields:
<tr class='nested-fields table'>
<td><%= f.input_field :name ,class: 'form-control'%></td>
<td><%= f.input_field :value, class: 'form-control' %></td>
<td><%= f.input_field :unit, class: 'form-control' %></td>
<td><%= link_to_remove_association f, class: 'btn btn-danger' do %>
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
<% end %></td>
</tr>
如果我从 /events/new 添加事件,表单会正确填充
From New Page 但是,如果我通过模式 window 添加它们,它会复制字段:
Modal View
我已经确认进入两个页面的 JSON 没有重复,并且它显示相同的视图 (/events/new) 但不知何故字段被重复了。
编辑
通过进一步调试,我推断问题出在我必须填充表单的 cocoon 脚本中。这两种方法分别用于 /events/new 和模态 windows。如果可以使模式正常工作,我不需要保留新页面。检查控制台输出,我发现每个 cocoon:after-insert 函数只在它们各自的页面上被触发。它们每个属性也只触发一次。
$(function() {
var eventtemplate_array;
var modal = false;
$('#event_name').bind('railsAutocomplete.select', function(event, data){
//$('#event_name').bind('change', function(event, data){
console.debug("Template selected...");
attributes = data.item.eventattributes;
console.debug("Removing existing attributes...");
$('.event_eventattribute_destroy').click();
console.debug("Adding attributes...");
for(var id in attributes) {
eventtemplate_array = attributes[id];
$('.add_fields').click();
}
console.debug("Done adding all attribute...");
});
if(!modal){
$('#eventattributes').bind('cocoon:after-insert', function(e, eventattribute) {
console.debug(modal);
eventattribute[0].getElementsByTagName('input')[0].value = eventtemplate_array[0];
eventattribute[0].getElementsByTagName('input')[1].value = eventtemplate_array[1];
eventattribute[0].getElementsByTagName('input')[2].value = eventtemplate_array[2];
});}
$('#newevent-modal').on('shown.bs.modal', function () {
modal = true;
$('input#event_name').bind('railsAutocomplete.select', function(event, data){
attributes = data.item.eventattributes;
$('.event_eventattribute_destroy').click();
for(var id in attributes) {
console.debug(id);
eventtemplate_array = attributes[id];
$('.add_fields').click();
}
eventtemplate_array = ["","",""];
});
$('#eventattributes').bind('cocoon:after-insert', function(e, eventattribute) {
console.debug(modal);
eventattribute[0].getElementsByTagName('input')[0].value = eventtemplate_array[0];
eventattribute[0].getElementsByTagName('input')[1].value = eventtemplate_array[1];
eventattribute[0].getElementsByTagName('input')[2].value = eventtemplate_array[2];
});
});
});
真正复杂的问题要理解。只是为了让我理解正确:您正在使用 "autocomplete" gem 从模板中获取字段列表,对吗? (只使用一个简单的 ajax 调用?)然后你使用这个 json,在 javascript 中构建表单。所以在这个脚本中,你以某种方式创建了替身,对吧?这似乎是一种非常复杂的方式,为什么不直接在服务器端呈现表单呢?
无论如何,由于两个页面的 id 相同 (input#event_name
),您实际上在呈现模式时附加了两次事件,这就是它在模式页面上重复的原因。在处理模式的显示事件时,最好使用范围选择器,如 #newevent-modal input#event_name
和 #newevent-modal #eventattributes
。
我一直在开发一个 rails 跟踪基本事件的应用程序,我希望扩展它(这是我自己的生活数据跟踪应用程序)。我有一个 EventTemplate class,它存储 EventTemplateAttributes。创建新事件时,它使用 rails-jquery-autocomplete 来搜索现有模板并使用散列将其属性填充到表单中。这是该自动完成功能的代码:
def autocomplete_eventtemplate_name
respond_to do |format|
format.json {
@eventtemplates = Eventtemplate.where("name like ?", "%#{params[:term]}%")
render json: json_for_autocomplete_eventtemplates(@eventtemplates)
}
end
end
def json_for_autocomplete_eventtemplates(eventtemplates)
eventtemplates.collect do |eventtemplate|
attributes = Hash.new
unless eventtemplate.templateattributes.empty?
eventtemplate.templateattributes.each do |templateattribute|
attributes[templateattribute.id] = [templateattribute.name,templateattribute.value,templateattribute.unit]
end
end
hash = {"id" => eventtemplate.id.to_s, "value" => eventtemplate.name,"eventattributes" => attributes}
hash
end
end
这是我的表格:
<%= simple_form_for(@event) do |f| %>
<% if @event.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@event.errors.count, "error") %> prohibited this event from being saved:</h2>
<ul>
<% @event.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<% if @event.new_record? %>
<% #,{:class=>"form-control"} %>
<%= f.autocomplete_field :name, autocomplete_eventtemplate_name_events_path,{:class => "form-control"} %>
<% else %>
<%= f.label :name %><br>
<%= f.text_field :name, class: 'form-control' %>
<% end %>
</div>
<div id="#find-subj"></div>
<table class="table-striped table table-bordered">
<thead>
<td>Name</td>
<td>Value</td>
<td>Unit</td>
<td></td>
</thead>
<tbody id=eventattributes>
<tr>
<%= f.simple_fields_for(:eventattributes, :wrapper => false) do |tattribute| %>
<% if modal == false%>
<%= render 'eventattribute_fields', :f => tattribute %>
<% end %>
<% end %>
</tr>
</tbody>
</table>
<div class="links">
<%= link_to_add_association f, :eventattributes, :"data-association-insertion-node" => "tbody#eventattributes", :"data-association-insertion-method" => "append", class: 'btn btn-info' do %>
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
<% end %>
</div></br>
<div class="actions">
<%= f.submit class: 'btn btn-primary'%>
<%= link_to 'Cancel', events_path, class: 'btn btn-warning' %>
</div>
<% end %>
这里是 _eventattribute_fields:
<tr class='nested-fields table'>
<td><%= f.input_field :name ,class: 'form-control'%></td>
<td><%= f.input_field :value, class: 'form-control' %></td>
<td><%= f.input_field :unit, class: 'form-control' %></td>
<td><%= link_to_remove_association f, class: 'btn btn-danger' do %>
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
<% end %></td>
</tr>
如果我从 /events/new 添加事件,表单会正确填充 From New Page 但是,如果我通过模式 window 添加它们,它会复制字段: Modal View
我已经确认进入两个页面的 JSON 没有重复,并且它显示相同的视图 (/events/new) 但不知何故字段被重复了。
编辑 通过进一步调试,我推断问题出在我必须填充表单的 cocoon 脚本中。这两种方法分别用于 /events/new 和模态 windows。如果可以使模式正常工作,我不需要保留新页面。检查控制台输出,我发现每个 cocoon:after-insert 函数只在它们各自的页面上被触发。它们每个属性也只触发一次。
$(function() {
var eventtemplate_array;
var modal = false;
$('#event_name').bind('railsAutocomplete.select', function(event, data){
//$('#event_name').bind('change', function(event, data){
console.debug("Template selected...");
attributes = data.item.eventattributes;
console.debug("Removing existing attributes...");
$('.event_eventattribute_destroy').click();
console.debug("Adding attributes...");
for(var id in attributes) {
eventtemplate_array = attributes[id];
$('.add_fields').click();
}
console.debug("Done adding all attribute...");
});
if(!modal){
$('#eventattributes').bind('cocoon:after-insert', function(e, eventattribute) {
console.debug(modal);
eventattribute[0].getElementsByTagName('input')[0].value = eventtemplate_array[0];
eventattribute[0].getElementsByTagName('input')[1].value = eventtemplate_array[1];
eventattribute[0].getElementsByTagName('input')[2].value = eventtemplate_array[2];
});}
$('#newevent-modal').on('shown.bs.modal', function () {
modal = true;
$('input#event_name').bind('railsAutocomplete.select', function(event, data){
attributes = data.item.eventattributes;
$('.event_eventattribute_destroy').click();
for(var id in attributes) {
console.debug(id);
eventtemplate_array = attributes[id];
$('.add_fields').click();
}
eventtemplate_array = ["","",""];
});
$('#eventattributes').bind('cocoon:after-insert', function(e, eventattribute) {
console.debug(modal);
eventattribute[0].getElementsByTagName('input')[0].value = eventtemplate_array[0];
eventattribute[0].getElementsByTagName('input')[1].value = eventtemplate_array[1];
eventattribute[0].getElementsByTagName('input')[2].value = eventtemplate_array[2];
});
});
});
真正复杂的问题要理解。只是为了让我理解正确:您正在使用 "autocomplete" gem 从模板中获取字段列表,对吗? (只使用一个简单的 ajax 调用?)然后你使用这个 json,在 javascript 中构建表单。所以在这个脚本中,你以某种方式创建了替身,对吧?这似乎是一种非常复杂的方式,为什么不直接在服务器端呈现表单呢?
无论如何,由于两个页面的 id 相同 (input#event_name
),您实际上在呈现模式时附加了两次事件,这就是它在模式页面上重复的原因。在处理模式的显示事件时,最好使用范围选择器,如 #newevent-modal input#event_name
和 #newevent-modal #eventattributes
。