同一表单中的多个动态嵌套表单字段

问题描述

我有一个注册表单,让锦标赛主管可以选择当参与者注册锦标赛时他们将请求哪些字段。我关注了 Go Rails 上的视频,使用刺激 JS 将动态嵌套表单字段添加到表单中,效果很好。

我正在尝试在表单的另一部分添加第二组字段。表单分为部分、基本信息、联系信息、比赛信息等,我希望能够为每个部分添加自定义字段

在基本部分它工作得很好。我可以添加删除自定义字段,但是当我将它添加到联系人部分时,即使将嵌套表单更改为嵌套联系人,它也只会在我在基本部分创建的字段中脉动。我可以从任一部分添加删除,但它只会在两个部分中显示所有内容

这是我现在的表格。我仍然需要添加其他部分,但在添加表单的其余部分之前,我试图让基本和联系人自定义字段工作:

<h4>Athlete information</h4>
<%= form_with(model: @event,class: "shadow p-3 mb-3 rounded text-dark",local: true) do |f| %>
  <%= f.hidden_field :athlete_info_complete,value: 1 %>
  <%= f.hidden_field :next,value: 6 %>
  <div class="row club_container">
    <div class="col-12">
      <legend>
        Check all the Boxes next to the information you would like to
        request from your tournament participants.  Each area will have an option 
        to add custom fields.
      </legend>
      <br><br>
      <h4>Basic information</h4>
      <div class="form-group row">
        <div class="col-md-9 col-sm-12">
          <label class="main">First Name
            <%= f.check_Box :first_name %>
            <span class="w3docs"></span>
          </label>
          <label class="main">Last Name
            <%= f.check_Box :last_name %>
            <span class="w3docs"></span>
          </label>
          <label class="main">Date of birth
            <%= f.check_Box :dob %>
            <span class="w3docs"></span>
          </label>
        </div>
      </div>
      <h4>Custom Fields</h4>
      <small>
        Enter the name of your custom field you plan to offer.
      </small>
      <br><br>
      
      <div data-controller="nested-form">
        <template data-target="nested-form.template">
          <%= f.fields_for :fields,Field.new,child_index: 'NEW_RECORD' do |field| %>
            <%= render 'events/forms/custom_fields_basic',f: field %>
          <% end %>
        </template>
        
        <%= f.fields_for :fields do |field| %>
          <%= render 'events/forms/custom_fields_basic',f: field %>
        <% end %>
        <div class="mb-3" data-target="nested-form.links">
          <%= link_to 'Add Custom Field',"#",class: "btn btn-outline-dark",data: { action: "click->nested-form#add_association" } %>
        </div>
      </div>

      <h4>Contact information</h4>
      <div class="form-group row">
        <div class="col-md-9 col-sm-12">
          <label class="main">Address 1
            <%= f.check_Box :address1 %>
            <span class="w3docs"></span>
          </label>
          <label class="main">Address 2
            <%= f.check_Box :address2 %>
            <span class="w3docs"></span>
          </label>
          <label class="main">City
            <%= f.check_Box :city %>
            <span class="w3docs"></span>
          </label>
        </div>
      </div>

      <div data-controller="nested-contacts">
        <template data-target="nested-contacts.template">
          <%= f.fields_for :fields,child_index: 'NEW_RECORD' do |field| %>
            <%= render 'events/forms/custom_fields_contact',f: field %>
          <% end %>
        </template>
        
        <%= f.fields_for :fields do |field| %>
          <%= render 'events/forms/custom_fields_contact',f: field %>
        <% end %>
        <div class="mb-3" data-target="nested-contacts.links">
          <%= link_to 'Add Custom Field',data: { action: "click->nested-contacts#add_association" } %>
        </div>
      </div>
      
      <div class="form-group row">
        <div class="col-md-9 col-sm-12"></div>
        <div class="col-md-3 col-sm-12">
          <button id="button_next" class="profile_btn align-middle" style="width:180px;">Finalize <span style="margin-top: 5px; font-size: 18px;"><i class="fas fa-long-arrow-alt-right"></i></span></button>
        </div>
      </div>
    </div>
  </div>
<% end %>

这是_custom_fields_basic.html.erb

<%= content_tag :div,class: 'nested-fields',data: { new_record: f.object.new_record? }  do %>
  <div class="form-group row">
    <div class="col-md-3 col-sm-12 col-form-label">
      <%= f.label :field_name %>
    </div>
    <div class="col-md-9 col-sm-12">
      <%= f.text_field :name,class: 'form-control' %>
      <small><%= link_to 'Remove','#',data: { action: 'click->nested-form#remove_association' } %></small>
    </div>
  </div>
  <%= f.hidden_field :field_type,value: 'basic' %>
  <%= f.hidden_field :_destroy %>
<% end %>

这是 custom_fields_contact.html.erb 文件

<%= content_tag :div,class: 'nested-contacts',data: { action: 'click->nested-contacts#remove_association' } %></small>
    </div>
  </div>
  <%= f.hidden_field :field_type,value: 'contact' %>
  <%= f.hidden_field :_destroy %>
<% end %>

这里是 nexted_form_controller.js

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "links","template" ]

  connect() {
    
  }

  add_association(event) {
    event.preventDefault()

    var content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g,new Date().getTime())
    this.linksTarget.insertAdjacentHTML('beforebegin',content)
  }
  
  remove_association(event) {
    event.preventDefault()

    let wrapper = event.target.closest(".nested-fields")
    if (wrapper.dataset.newRecord == "true") {
      wrapper.remove()
    } else {
      wrapper.querySelector("input[name*='_destroy']").value = 1
      wrapper.style.display = 'none'
    } 
  }
}

以及nested_contacts_controller.js:

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "links",content)
  }
  
  remove_association(event) {
    event.preventDefault()

    let wrapper = event.target.closest(".nested-contacts")
    if (wrapper.dataset.newRecord == "true") {
      wrapper.remove()
    } else {
      wrapper.querySelector("input[name*='_destroy']").value = 1
      wrapper.style.display = 'none'
    } 
  }
}

如果有办法用单个控制器来做到这一点会很棒,但如果需要,我可以为每个部分设置单独的控制器。

谢谢

解决方法

您的问题不在于 Stimulus 控制器,而在于您如何定义这些字段。不过要注意的一件事是,Stimulus 是模块化的,因此您只需要一个控制器,并且可以在同一页面上根据需要多次实现它。 data-controller 的目的是定义控制器可以影响 DOM 的哪个部分。

# form
<div data-controller="nested-form">
  Affects only things in here
</div>

<div data-controller="nested-form">
  Affects only things in here
</div>

问题在于您在两个地方使用了相同的关联模型。呈现编辑页面时,表单将显示每个部分中的所有字段,因为您要求使用这些行

<%= f.fields_for :fields do |field| %> #specifically this one
  <%= render 'events/forms/custom_fields_basic',f: field %>
<% end %>

调用与事件关联的所有关联模型并显示它们的字段。

您有 field_type 的隐藏字段,所以现在您只需要在 Event 模型中定义一些方法。

# model
def basic_fields
  self.fields.where('field_type = ?','basic')
end

现在,您可以执行 <%= f.fields_for :fields do |field| %> 等操作,而不是 <%= f.fields_for :basic_fields do |field| %>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...