问题
I have models for Project and Ethic in my Rails 4 app.
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. 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:
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).
MIXAN'S SUGGESTION
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. 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?
ethics.js has:
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
<%= 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. The second menu does not populate with any options though.
回答1:
In provided example seems that you selecting wrong DOM elements. Just reference them by id, it will be more clear and it will be not so coupled with attributes naming. 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
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>
回答2:
Use this code, edit it for your #id's and urls
// 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.
** 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
来源:https://stackoverflow.com/questions/38930601/rails-4-dynamically-populate-2nd-select-menu-based-on-choice-in-first-select-m