简体   繁体   English

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

[英]Rails 4 - dynamically populate 2nd select menu based on choice in first select menu in a nested form

I have models for Project and Ethic in my Rails 4 app. 我的Rails 4应用程序中有Project和Ethic模型。

The ethics view has a nested fields form (using simple form simple fields for) contained in it. 道德视图包含一个嵌套的字段表单(使用简单的表单简单字段)。 The ethic form fields are nested in the projects form. 道德表单字段嵌套在项目表单中。

The ethic form fields has 2 select menus. 道德形式字段有2个选择菜单。 The first menu offers a set of options for a category. 第一个菜单为一个类别提供了一组选项。 The 2nd select option is a list of subcategories. 第二个选择选项是子类别列表。

I'm trying to figure out how to populate the 2nd select menu with the right options, based on the choice made in the 1st select menu. 我正在尝试根据第一个选择菜单中的选择,弄清楚如何使用正确的选项填充第二个选择菜单。

In my project.js file, I have: 在我的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]);
   //  }


});

I can't figure out what Im doing wrong. 我无法弄清楚我做错了什么。 Regardless of the choice I make in the 1st option, the 2nd select menu is populated with options that belong to the last category. 无论我在第一个选项中做出何种选择,第二个选择菜单都会填充属于最后一个类别的选项。

My projects form has: 我的项目形式有:

 <%= 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' %>

My ethic form fields has: 我的道德形式领域有:

<%= 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" %>

My ethic view helper has: 我的道德观助手有:

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  

Can anyone see what i need to do to populate the second select menu with the right options based on the choice made in the 1st select menu. 任何人都可以看到我需要做什么来根据第一个选择菜单中的选择使用正确的选项填充第二个选择菜单。 I'm wondering if I'm not supposed to write the jQuery in the project.js file, given the form fields are contained within an ethic view partial (rendered in the projects form). 我想知道我是不是应该在project.js文件中编写jQuery,因为表单字段包含在ethic视图partial(在项目表单中呈现)中。

MIXAN'S SUGGESTION MIXAN的建议

My form now has: 我的表格现在有:

<%= 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' %>

I had to change the form a bit because I use simple form with rails. 我不得不稍微更改表单,因为我使用带有rails的简单表单。 I'm not sure if I have added the 'disabled selected value' and 'disabled' options to the form inputs correctly. 我不确定是否已将“禁用选定值”和“禁用”选项正确添加到表单输入中。

At the moment, the form renders- but the second menu is not populated with any content. 目前,表单呈现 - 但第二个菜单没有填充任何内容。 I wonder if that has something to do with the use of the option tags in the js file? 我想知道这是否与在js文件中使用选项标签有关?

ethics.js has: 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'S AMENDED SUGGESTION 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 %>

When I try this, the formatting of the menu drop down for the first category is changed, but the functionality is the same as when I use f.input. 当我尝试这个时,第一个类别的菜单下拉列表的格式被更改,但功能与我使用f.input时的功能相同。 The second menu does not populate with any options though. 第二个菜单不会填充任何选项。

Use this code, edit it for your #id 's and urls 使用此代码,为#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
});

Repeat it as needed for the other select menus 根据需要对其他选择菜单重复此操作


Requires you to create an action in your controller that returns a JSON with the values you want. 需要您在控制器中创建一个操作,该操作返回包含所需值的JSON。

** Routes.rb ** ** Routes.rb **

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

Controller Code: 控制器代码:

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

It will then go though them and add them as options to the slave select menu 然后它将通过它们并将它们作为选项添加到从属选择菜单

In provided example seems that you selecting wrong DOM elements. 在提供的示例中,您似乎选择了错误的DOM元素。 Just reference them by id, it will be more clear and it will be not so coupled with attributes naming. 只需通过id引用它们,它就会更清晰,并且不会与属性命名相结合。 I suggesting the next approach for your task. 我建议你的下一个方法来完成你的任务。 First build the map of selects on client side: 首先在客户端构建选择映射:

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'
    ]
  };

Then just listen for changes of main select and rebuild options for sub select. 然后只需监听主选择的更改和子选择的重建选项。

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));
  });
})

Here an example how it looks like with plain html form 这里是一个简单的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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM