使用JS的Cascade下拉菜单不起作用 [英] Cascade dropdown using JS not working
问题描述
我想要做的是:
案例1:如果用户从下拉列表#1中选择一个值,则下拉列表#2的值取决于下拉列表#1,下拉列表#3的值取决于下拉列表#2。例如。状态 - 城市 - 大道
案例2:用户可以从3个下拉列表中选择。
案例3和4 :如果用户从下拉列表#2中选择,则下拉菜单#3的值取决于下拉菜单#2(但是如果下拉菜单#2已经选择,则在下拉菜单#3中选择一个值是可选的)
表单
< form action =''method ='post 'id ='loc'>
< select name =stateid =filter_regionclass =state>
< option name =defaultclass =defaultvalue =Statereadonly> State< / option>
<?php
foreach($ result_state as $ option){
if(isset($ _ POST ['state'])&& $ _POST ['state'] == $ option-> state)
echo'< option name =stateclass =filter_byselected value ='。$ option-> state。'>'。 $ option-> state。'< / option>';
else
echo'< option name =stateclass =filter_byvalue ='。$ option-> state。'>'。 $ option-> state。'< / option>';
};
?>
< / select>
< select name =cityid =filter_cityclass =city>
< option name =defaultclass =defaultvalue =Cityreadonly> City< / option>
<?php
foreach($ result_city as $ option){
if(isset($ _ POST ['city'])&&_ $ _POST ['city'] == $ option-> city)
echo'< option name =cityclass =filter_byselected value ='。$ option-> city。'>'。 $ option-> city。'< / option>';
else
echo'< option name =cityclass =filter_byvalue ='。$ option-> city。'>'。 $ option-> city。'< / option>';
};
?>
< / select>
< select name =avenueid =filter_mallclass =avenue>
< option name =defaultclass =defaultvalue =Avenuereadonly> Avenue< / option>
<?php
foreach($ result_avenue as $ option){
if(isset($ _ POST ['avenue'])& $ _POST ['avenue'] == $ option-> avenue)
echo'< option name =avenueclass =defaultselected value ='。$ option-> avenue。'>'。 $ option-> avenue。'< / option>';
else
echo'< option name =avenueclass =filter_byvalue ='。$ option-> avenue。'>'。 $ option-> avenue。'< / option>';
};
?>
< / select>
< input type =submitvalue =submitclass =submit/>
< / form>
JS:
函数cascadeSelect(parent,child){
var childOptions = child.find('option:not(.default)');
child.data('options',childOptions);
parent.change(function(){
childOptions.remove();
child
.append(child.data('options')。filter .filter_by'+ this.value))
.change();
})
childOptions.not(',默认,.filter_by'+ parent.val()) 。去掉();
}
$(function(){
cascadeForm = $('。loc');
state = cascadeForm.find('。state');
city = cascadeForm.find('。city');
avenue = cascadeForm.find('。avenue');
cascadeSelect(state,city);
cascadeSelect(city,avenue);
});
我创建了级联父子选择框<使用AngularJS的href =https://stackoverflow.com/questions/38824196/cascading-parent-child-select-boxes-from-dynamic-json-data/38845614?noredirect=1#comment65414713_38845614但是由于您使用NativeJS,我尝试使用JS重新创建。我的解决方案的先决条件是一个定义良好的JSON,将创建选择框。您必须在服务器端创建JSON,或者手动创建JSON或创建选择框数据。以下是JSON格式:
每个选择框都是一个具有以下属性的命名对象:
- 父属性:作为此选择对象的父对象的对象的名称。
-
选项:选项对象的数组,其中每个对象包含: a)选项值(b)父选项值 - 映射当前值的父选择框值。 (c)选项ID。
-
所选选项:具有两个属性的对象:(a)当前选定的值(b)当前选定值的ID。 p>
这是解决方案的工作Plunker 。希望它有帮助。
-----编辑:-----
根据@ User014019
这里是这个下拉式解决方案的另一个版本,其中所有选择框中的所有选项最初都可见,并且在用户选择特定值时设置父子关系。
以下是代码:
//读取数据并创建DOM元素(选择框及其相关选项)
函数initSelect(data){
var select,option,input,filteredOptions;
for(var key in data){
select = document.createElement(select);
select.name = key;
container.appendChild(select);
filteredOptions = optionFilter(data [key] .availableOptions,data [data [key] .parent],data [key]);
input = document.querySelector('select [name ='+ key +');
input.setAttribute(onchange,updateSelect(this)); (var i = 0; i< filteredOptions.length; i ++){
option = document.createElement(option);
option.value = filteredOptions [i] .value;
option.innerHTML = filteredOptions [i] .value;
input.appendChild(option);
}
input.options.selectedIndex = getSelectedIndex(filteredOptions,data [key]);
input.setAttribute('model',data [key] .selectedOption.value);
}
}
//此功能将在更改选择框时调用
function updateSelect(element){
var输入,选项;
setSelectedOption(element);
for(var key in data){
filteredOptions = optionFilter(data [key] .availableOptions,data [data [key] .parent],data [key]);
input = document.querySelector('select [name ='+ key +');
while(input.firstChild){
input.removeChild(input.firstChild);
}
for(var i = 0; i< filteredOptions.length; i ++){
option = document.createElement(option);
option.value = filteredOptions [i] .value;
option.innerHTML = filteredOptions [i] .value;
input.appendChild(option);
}
input.options.selectedIndex = getSelectedIndex(filteredOptions,data [key]);
input.setAttribute('model',data [key] .selectedOption.value);
}
}
//设置选择框的选择对象在更改时
函数setSelectedOption(element){
var inputName = element .getAttribute( 名称);
var inputValue = getSelectedText(element);
var inputItem = data [inputName];
var selectedOption,filteredOptions;
//设置所选择的更改选择框的选项
for(var i = 0; i< inputItem.availableOptions.length; i ++){
if(inputValue == = inputItem.availableOptions [i] .value){
inputItem.selectedOption = inputItem.availableOptions [i];
break;
}
}
//设置子对象选择选项现在
(数据中的var键){
if(data [key] .parent === inputName ){
filteredOptions = optionFilter(data [key] .availableOptions,data [data [key] .parent],data [key]);
data [key] .selectedOption = filteredOptions [0];
}
}
}
//获取选择框的文本
function getSelectedText(element){
if(element。 selectedIndex == -1){
return null;
}
return element.options [element.selectedIndex] .text;
}
函数getSelectedIndex(options,self){
var index;
for(var i = 0; i< options.length; i ++){
if(self.selectedOption.value === options [i] .value){
index = i ;
break;
}
}
返回索引;
}
//根据父选择的值获取过滤的选项
function optionFilter(items,parent,self){
var result = [];
if(typeof parent!==undefined){
for(var i = 0; i< items.length; i ++){
if(typeof parent.selectedOption! undefined){
if(parent.selectedOption!== null&& items [i] .parentValue === parent.selectedOption.value){
result.push(items [i] );
}
}
}
if(typeof self.selectedOption ===undefined){
self.selectedOption = null;
}
if(self.selectedOption === null){
self.selectedOption = result [0];
}
返回结果;
} else {
return items;
}
}
I have 3 dropdown, the values filled dynamically with mysql. Now, I'm trying to cascade the 3 dropdown, but JS script is not working.
What I'm trying to do's:
Case 1: If the user choose a value from dropdown #1, the value of dropdown #2 depends on dropdown #1, the value of dropdown #3 depends on dropdown #2. E.g. State - City - Avenue
Case 2: The user can choose from 3 dropdown.
Case 3 and 4: If the user choose from dropdown #2, the values of dropdown #3 depends in dropdown #2 (but choosing a value in dropdown #3 is optional, if the dropdown #2 have already)
Form:
<form action='' method='post' id='loc'>
<select name="state" id="filter_region" class="state">
<option name="default" class="default" value="State" readonly>State</option>
<?php
foreach($result_state as $option){
if(isset($_POST['state']) && $_POST['state'] == $option->state)
echo '<option name="state" class="filter_by" selected value="'. $option->state .'">'. $option->state .'</option>';
else
echo '<option name="state" class="filter_by" value="'. $option->state .'">'. $option->state .'</option>';
};
?>
</select>
<select name="city" id="filter_city" class="city">
<option name="default" class="default" value="City" readonly>City</option>
<?php
foreach($result_city as $option){
if(isset($_POST['city']) && $_POST['city'] == $option->city)
echo '<option name="city" class="filter_by" selected value="'. $option->city .'">'. $option->city .'</option>';
else
echo '<option name="city" class="filter_by" value="'. $option->city .'">'. $option->city .'</option>';
};
?>
</select>
<select name="avenue" id="filter_mall" class="avenue">
<option name="default" class="default" value="Avenue" readonly>Avenue</option>
<?php
foreach($result_avenue as $option){
if(isset($_POST['avenue']) && $_POST['avenue'] == $option->avenue)
echo '<option name="avenue" class="default" selected value="'. $option->avenue .'">'. $option->avenue .'</option>';
else
echo '<option name="avenue" class="filter_by" value="'. $option->avenue .'">'. $option->avenue .'</option>';
};
?>
</select>
<input type="submit" value="submit" class="submit"/>
</form>
JS:
function cascadeSelect(parent, child){
var childOptions = child.find('option:not(.default)');
child.data('options',childOptions);
parent.change(function(){
childOptions.remove();
child
.append(child.data('options').filter('.filter_by' + this.value))
.change();
})
childOptions.not('.default, .filter_by' + parent.val()).remove();
}
$(function(){
cascadeForm = $('.loc');
state= cascadeForm.find('.state');
city= cascadeForm.find('.city');
avenue= cascadeForm.find('.avenue');
cascadeSelect(state, city);
cascadeSelect(city, avenue);
});
I had created cascading parent-child select-boxes using AngularJS, but since you are using NativeJS, I tried to re-create using JS. The pre-requisite of my solution is a well-defined JSON based on which the select-boxes will be created. You'll have to create the JSON on server side or manually or wherever you are creating the select-box data. Below is the JSON format.:
Every select-box is a named object with following properties:
- Parent Attribute: Name of object which is the parent of this select-box object.
Options: Array of option objects, where each object contains: (a) Option Value (b) Parent Option Value - The parent select-box value with which the current value is mapped. (c) Option ID.
Selected Option: An object with two properties: (a) Currently selected value (b) ID of currently selected value.
Here is the working Plunker of the solution. Hope it helps.
----- EDIT: -----
On request of @User014019
Here is the another version of this drop-down solution where all the options in all select-boxes are visible initially, and parent-child relationships are set when user select a particular value.
Below is the code:
// reads the data and creates the DOM elements (select-boxes and their relevant options)
function initSelect(data) {
var select, option, input, filteredOptions;
for (var key in data) {
select = document.createElement("select");
select.name = key;
container.appendChild(select);
filteredOptions = optionFilter(data[key].availableOptions, data[data[key].parent], data[key]);
input = document.querySelector('select[name="' + key + '"');
input.setAttribute("onchange", "updateSelect(this)");
for (var i = 0; i < filteredOptions.length; i++) {
option = document.createElement("option");
option.value = filteredOptions[i].value;
option.innerHTML = filteredOptions[i].value;
input.appendChild(option);
}
input.options.selectedIndex = getSelectedIndex(filteredOptions, data[key]);
input.setAttribute('model', data[key].selectedOption.value);
}
}
// this function will be called on change of select-box
function updateSelect(element) {
var input, option;
setSelectedOption(element);
for (var key in data) {
filteredOptions = optionFilter(data[key].availableOptions, data[data[key].parent], data[key]);
input = document.querySelector('select[name="' + key + '"');
while (input.firstChild) {
input.removeChild(input.firstChild);
}
for (var i = 0; i < filteredOptions.length; i++) {
option = document.createElement("option");
option.value = filteredOptions[i].value;
option.innerHTML = filteredOptions[i].value;
input.appendChild(option);
}
input.options.selectedIndex = getSelectedIndex(filteredOptions, data[key]);
input.setAttribute('model', data[key].selectedOption.value);
}
}
// set the selected-option of select-box when it's changed
function setSelectedOption(element) {
var inputName = element.getAttribute("name");
var inputValue = getSelectedText(element);
var inputItem = data[inputName];
var selectedOption, filteredOptions;
// setting selected option of changed select-box
for (var i = 0; i < inputItem.availableOptions.length; i++) {
if (inputValue === inputItem.availableOptions[i].value) {
inputItem.selectedOption = inputItem.availableOptions[i];
break;
}
}
// setting child object selected option now
for (var key in data) {
if (data[key].parent === inputName) {
filteredOptions = optionFilter(data[key].availableOptions, data[data[key].parent], data[key]);
data[key].selectedOption = filteredOptions[0];
}
}
}
// get the text of select-box
function getSelectedText(element) {
if (element.selectedIndex == -1) {
return null;
}
return element.options[element.selectedIndex].text;
}
function getSelectedIndex(options, self) {
var index;
for (var i = 0; i < options.length; i++) {
if (self.selectedOption.value === options[i].value) {
index = i;
break;
}
}
return index;
}
// get filtered options based on parent's selected value
function optionFilter(items, parent, self) {
var result = [];
if (typeof parent !== "undefined") {
for (var i = 0; i < items.length; i++) {
if (typeof parent.selectedOption !== "undefined") {
if (parent.selectedOption !== null && items[i].parentValue === parent.selectedOption.value) {
result.push(items[i]);
}
}
}
if (typeof self.selectedOption === "undefined") {
self.selectedOption = null;
}
if (self.selectedOption === null) {
self.selectedOption = result[0];
}
return result;
} else {
return items;
}
}
这篇关于使用JS的Cascade下拉菜单不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!