Rails 4 - 根据嵌套形式的第一个选择菜单中的选择动态填充第二个选择菜单

Posted

技术标签:

【中文标题】Rails 4 - 根据嵌套形式的第一个选择菜单中的选择动态填充第二个选择菜单【英文标题】:Rails 4 - dynamically populate 2nd select menu based on choice in first select menu in a nested form 【发布时间】:2016-12-20 05:07:53 【问题描述】:

我的 Rails 4 应用中有项目和道德模型。

道德视图包含一个嵌套字段表单(使用简单表单简单字段)。道德表单字段嵌套在项目表单中。

道德表单字段有 2 个选择菜单。第一个菜单为一个类别提供了一组选项。第二个选择选项是子类别列表。

我正在尝试根据第一个选择菜单中的选择,找出如何使用正确的选项填充第二个选择菜单。

在我的 project.js 文件中,我有:

jQuery(document).ready(function() 

   jQuery("#project_ethic_attributes.main_category").change(function() 
      var category = $("#project_ethic_attributes.main_category").val(),
        sub_category = $("#project_ethic_attributes.sub_category"),
        options = [],
        str = "";
      sub_category.find('option').remove();
      if(category == 'Risk of harm')
      options = ["Physical Harm", "Psychological distress or discomfort", "Social disadvantage", "Harm to participants", "Financial status", "Privacy"]
    

   );

   // jQuery(".main_category").change(function() 
   //  var category = $(".main_category").val(),
   //      sub_category = $(".sub_category"),
   //      options = [],
   //      str = "";
   //  sub_category.find('option').remove();

   //  if(category == 'Risk of harm')
   //    options = ["Physical Harm", "Psychological distress or discomfort", "Social disadvantage", "Harm to participants", "Financial status", "Privacy"]
   //  
   //  else if(category == 'Informed consent')
   //    options = ["Explanation of research", "Explanation of participant's role in research"]   
   //  
   //  else if(category == 'Anonymity and Confidentiality')
   //    options = ["Remove identifiers", "Use proxies", "Disclosure for limited purposes"]
   //  
   //  else if(category == 'Deceptive practices')
   //    options = ["Feasibility"]
   //  
   //  else if(category == 'Right to withdraw')
   //    options = ["Right to withdraw from participation in the project"]  
   //  
   //  if(options.length > 0)
   //    for(i=0;i<options.length;i++)
   //      str = '<option value="' + options[i] + '">' + options[i] + '</option>'
   //      sub_category.append(str);
   //    
   //    sub_category.val(options[0]);
   //  


);

我不知道我做错了什么。无论我在第一个选项中做出何种选择,第二个选择菜单都会填充属于最后一个类别的选项。

我的项目表格有:

 <%= f.simple_fields_for :ethics do |f| %>
        <%= render 'ethics/ethic_fields', f: f %>
 <% end %>
 <%= link_to_add_association 'Add an ethics consideration', f, :ethics, partial: 'ethics/ethic_fields' %>

我的道德表单字段有:

<%= f.input :category, collection: [ "Risk of harm", "Informed consent", "Anonymity and Confidentiality", "Deceptive practices", "Right to withdraw"], :label => "Principle",  prompt: 'select', id: "main_category" %>


            <%= f.input :subcategory,  collection: text_for_subcategory(@category), :label => "Subcategory", prompt: 'select', id: "sub_category" %>

我的道德观助手有:

def text_for_subcategory(category)
      if category == 'Risk of harm'
            [ "Physical Harm", "Psychological distress or discomfort", "Social disadvantage", "Harm to participants", "Financial status", "Privacy"]
        elsif category == 'Informed consent'
            ["Explanation of research", "Explanation of participant's role in research"]
        elsif category == 'Anonymity and Confidentiality'
            ["Remove identifiers", "Use proxies", "Disclosure for limited purposes"]
        elsif category == 'Deceptive practices' 
            ["Feasibility"] 
        else category == 'Right to withdraw'    
            ["Right to withdraw from participation in the project"] 
       end
    end  

任何人都可以看到我需要做什么才能根据在第一个选择菜单中做出的选择来使用正确的选项填充第二个选择菜单。我想知道我是否不应该在 project.js 文件中编写 jQuery,因为表单字段包含在部分道德视图中(呈现在项目表单中)。

MIXAN 的建议

我的表单现在有:

<%= f.input :category, collection: [ "Risk of harm", "Informed consent", "Anonymity and Confidentiality", "Deceptive practices", "Right to withdraw"], option:'disabled selected value', :label => "Principle",  prompt: 'select', id: "main_category" %>


        <%= f.input :subcategory,  :label => "Subcategory", prompt: 'select', id: "sub_category", option:'disabled' %>

我不得不稍微改变一下表格,因为我使用带有导轨的简单表格。我不确定我是否在表单输入中正确添加了“禁用选定值”和“禁用”选项。

目前,表单呈现 - 但第二个菜单未填充任何内容。不知道是不是和js文件中使用option标签有关系?

ethics.js 有:

jQuery(document).ready(function() 
  var optionsMap = 
      'Risk of harm': [
        'Physical Harm', 
        'Psychological distress or discomfort', 
        'Social disadvantage', 
        'Harm to participants', 
        'Financial status', 
        'Privacy'
      ],
      'Informed consent': [
        'Explanation of research', 
        "Explanation of participant's role in research"
      ],
      'Anonymity and Confidentiality': [
        'Remove identifiers', 'Use proxies', 'Disclosure for limited purposes'
      ],
      'Deceptive practices': [
        'Feasibility'
      ],
      'Right to withdraw': [
        'Right to withdraw from participation in the project'
      ]
    ;

  jQuery('#main_category').change(function() 
    var category = jQuery(this).val(),
        $subCategory = jQuery('#sub_category'),
        newOptions = optionsMap[category];
    $subCategory.attr('disabled', false)
    $subCategory.empty();
    $.each(newOptions, function() 
      $subCategory.append(jQuery("<option></option>").text(this));
    );
  )
);

MIXAN 的修正建议

<%= f.select :category, collection: [ "Risk of harm", "Informed consent", "Anonymity and Confidentiality", "Deceptive practices", "Right to withdraw"], option:'disabled selected value', :label => "Principle", prompt: 'select', html:  id: "main_category"  %>


<%= f.select :subcategory, [], , id: "sub_category", disabled: true %>

当我尝试这个时,第一个类别的菜单下拉菜单的格式发生了变化,但功能与我使用 f.input 时相同。但是,第二个菜单没有填充任何选项。

【问题讨论】:

我会在这种情况下使用 ajax。 Rails Ajax,仍然使用您的 jquery 来检测第一个选择列表中的更改,然后通过 ajax 触发控制器操作以重新加载第二个列表 如果第二个字段的数据没有被某种形式的管理面板更改,那么您可以轻松地在您的 JS 中实现这一点。否则,一旦用户选择了第一个字段,您需要使用 AJAX 获取第二个字段的选项。 @JagjotSingh - 每个类别的子类别在我的助手中定义。 @Mel 这意味着它们将是相当静态的,不会发生太大变化,对吧? 没错——他们不太可能改变 【参考方案1】:

在提供的示例中,您似乎选择了错误的 DOM 元素。直接通过id引用就可以了,这样会更清晰,不会跟属性命名那么耦合。 我建议您的任务的下一个方法。 首先在客户端构建选择地图:

var optionsMap = 
    'Risk of harm': [
      'Physical Harm', 
      'Psychological distress or discomfort', 
      'Social disadvantage', 
      'Harm to participants', 
      'Financial status', 
      'Privacy'
    ],
    'Informed consent': [
      'Explanation of research', 
      "Explanation of participant's role in research"
    ],
    'Anonymity and Confidentiality': [
      'Remove identifiers', 'Use proxies', 'Disclosure for limited purposes'
    ],
    'Deceptive practices': [
      'Feasibility'
    ],
    'Right to withdraw': [
      'Right to withdraw from participation in the project'
    ]
  ;

然后只听主选择的变化和子选择的重建选项。

jQuery('#main_category').change(function() 
  var category = jQuery(this).val(),
      $subCategory = jQuery('#sub_category'),
      newOptions = optionsMap[category];

  $subCategory.empty();
  $.each(newOptions, function(key,value) 
    $subCategory.append(jQuery("<option></option>").attr("value", value).text(key));
  );
)

这里是一个简单的html表单的例子

jQuery(document).ready(function() 
  var optionsMap = 
      'Risk of harm': [
        'Physical Harm', 
        'Psychological distress or discomfort', 
        'Social disadvantage', 
        'Harm to participants', 
        'Financial status', 
        'Privacy'
      ],
      'Informed consent': [
        'Explanation of research', 
        "Explanation of participant's role in research"
      ],
      'Anonymity and Confidentiality': [
        'Remove identifiers', 'Use proxies', 'Disclosure for limited purposes'
      ],
      'Deceptive practices': [
        'Feasibility'
      ],
      'Right to withdraw': [
        'Right to withdraw from participation in the project'
      ]
    ;

  jQuery('#main_category').change(function() 
    var category = jQuery(this).val(),
        $subCategory = jQuery('#sub_category'),
        newOptions = optionsMap[category];
    $subCategory.attr('disabled', false)
    $subCategory.empty();
    $.each(newOptions, function() 
      $subCategory.append(jQuery("<option></option>").text(this));
    );
  )
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <select id='main_category'>
    <option disabled selected value> -- select an option -- </option>
    <option>Risk of harm</option>
    <option>Informed consent</option>
    <option>Anonymity and Confidentiality</option>
    <option>Deceptive practices</option>
    <option>Right to withdraw</option>
  </select>
  <select id='sub_category' disabled>
  </select>
</form>

【讨论】:

谢谢。我可以看到您的代码 sn-p 在此示例中效果很好。不过,我正在努力将其插入我的代码中。这可能与简单的表单集合结构有关。我更新了我的帖子以显示代码中的内容。我无法按照您在示例中显示的方式替换表单元素。 表单呈现没有任何错误 - 但第二个菜单是空的。 @Mel 我读了你的新例子。这对我来说似乎不正确&lt;%= f.input :subcategory, :label =&gt; "Subcategory", prompt: 'select', id: "sub_category", option:'disabled' %&gt; 使用 select 而不是 &lt;%= f.select :subcategory, [], , id: "sub_category", disabled: true %&gt; 这是此输入的完整文档api.rubyonrails.org/classes/ActionView/Helpers/… 我试过这样。它呈现页面,第二个输入字段的选择菜单为空。 它最初应该是空的,在第一次选择值后应该激活它。你的情况总是空的吗?【参考方案2】:

使用此代码,为您的#idurls 编辑它

// Dynamic Search Model Loader
$(function()
    var saved = ;
    var options, value;
    $("#selectOne").change(function()
        options = '<option value="" selected="selected">Loading...</option>';
        $("#selectTwo").html(options);
        value = $(this).val();

        if (saved[value].length > 0) 
           $("#selectTwo").html(saved[value]);
         else 
          $.ajax(
            url: '/api/get-json-values/?category=' + value, // Set the category as the value or whatever you want it to be
            type: 'GET',
            dataType: 'json',
            async: true
        ).done(function(data)
            options = '<option value="" selected="selected">Please Pick...</option>';
            // Parse through the values
            $.each(data, function(text)
                options += '<option value="' + text + '">' + text + '</option>';
            );
            // Populate the second select menu
            $("#selectTwo").html(options);
            saved[value] = options;
          ).fail(function(data)
            options = '<option value="" selected="selected">Empty...</option>';
            $("#selectTwo").html(options);
          ); // End Ajax
         ;
    ); // End Change
);

根据需要对其他选择菜单重复此操作


要求您在控制器中创建一个操作,该操作返回包含所需值的 JSON。

** Routes.rb **

namespace :api do
    get 'get-json-values', to: 'queries#category_search'
end

控制器代码:

class API::Queries < ApplicationController

  def category_search
    category = params[:category]

    if category == 'Risk of harm'
      @json = [ "Physical Harm", "Psychological distress or discomfort", "Social disadvantage", "Harm to participants", "Financial status", "Privacy"]
    elsif category == 'Informed consent'
      @json = ["Explanation of research", "Explanation of participant's role in research"]
    elsif category == 'Anonymity and Confidentiality'
      @json = ["Remove identifiers", "Use proxies", "Disclosure for limited purposes"]
    elsif category == 'Deceptive practices' 
      @json = ["Feasibility"] 
    elsif category == 'Right to withdraw'    
      @json = ["Right to withdraw from participation in the project"] 
    else
      @json = nil
    end

    if @json
      render json: @json.to_json, status: 200
    else
      render json: message: 'Not Found', status: 404
    end
  end
end

然后它会遍历它们并将它们作为选项添加到 slave 选择菜单

【讨论】:

感谢您的建议。我不明白如何按照您的 js 代码中的说明进行操作。你有一个如何通过值设置类别/解析的例子吗?或者对我在哪里可以找到有关如何执行此操作的信息有任何想法?另外,当我使用 jqeury 时,我可以在我的项目中使用它吗? 这个ajax调用绝对是多余的,这个if else语句可以在客户端解决 @mixan946 是的,这有点矫枉过正,有一天他可能想从数据库中查询数据 @blnc 即使他想从数据库中提取数据,也没有理由在每次选择更改时查询这些数据。

以上是关于Rails 4 - 根据嵌套形式的第一个选择菜单中的选择动态填充第二个选择菜单的主要内容,如果未能解决你的问题,请参考以下文章

如何在sql中创建嵌套表

从rails的下拉菜单中选择项目时如何更新数据库字段?

如果对象在 Rails 6 中以嵌套形式不存在,如何创建对象?

带有 jQ​​uery 的 Rails 中的动态下拉(选择框)菜单不可逆

嵌套 Rails 表单中的动态值未更新

Active Admin - 根据第一个下拉菜单刷新第二个下拉菜单,Ruby on Rails