Cocoon 自动完成模态填充动态字段两次

Posted

技术标签:

【中文标题】Cocoon 自动完成模态填充动态字段两次【英文标题】:Cocoon autocomplete Modal populating dynamic fields twice 【发布时间】:2016-11-16 07:02:33 【问题描述】:

我一直在开发一个跟踪基本事件的 Rails 应用程序,我希望扩展它(它是我自己的生活数据跟踪应用程序)。我有一个 EventTemplate 类,它存储 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 但是,如果我通过模式窗口添加它们,它会复制这些字段: Modal View

我已经验证了进入两个页面的 JSON 没有重复,并且它显示了相同的视图 (/events/new) 但不知何故这些字段被重复了。

编辑 通过进一步调试,我推断问题发生在我必须填充表单的茧脚本中。这两种方法分别用于 /events/new 和模态窗口。如果可以使模式正常工作,我不需要保留新页面。检查控制台输出,我发现每个 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];
    );
);


);

【问题讨论】:

【参考方案1】:

真正复杂的问题要理解。只是我理解正确:您正在使用“自动完成”gem从模板中获取字段列表,对吗? (只使用一个简单的 ajax 调用?)然后你使用这个 json,在 javascript 中构建表单。所以在这个脚本中,你以某种方式创建了双打,对吧?这似乎是一种非常复杂的方式,为什么不直接在服务器端渲染表单呢?

无论如何,由于两个页面的 id 相同 (input#event_name),因此您实际上在呈现模式时附加了两次事件,这就是它在模式页面上重复的原因。在处理模式的显示事件时,最好使用#newevent-modal input#event_name#newevent-modal #eventattributes 等范围选择器。

【讨论】:

谢谢!即使在注释掉模态 JS 位的前半部分后,我仍然会得到那个副本,所以我最终以一种 hacky 的方式完成它,让它打开和关闭一个布尔变量,并且每隔一个将实际数据放入表中时间。然后在控制器中,我让它删除所有空白的孩子。

以上是关于Cocoon 自动完成模态填充动态字段两次的主要内容,如果未能解决你的问题,请参考以下文章

WebView(Android App)中弹出的模态对话框中的自动填充文本字段

使用自动完成填充表单时,Javascript 不启用按钮

通过选择一个字段自动完成(自动填充)多个字段

为啥动态值没有填充在自动完成组合框中?

如果表单有超过 200 个输入字段,则自动填充/自动完成不起作用

HTML - 防止自动填充或自动完成字段(FF、IE、iPad)