使用 JS 的级联下拉菜单不起作用
Cascade dropdown using JS not working
我有 3 个下拉菜单,值动态填充 mysql。现在,我正在尝试级联 3 个下拉菜单,但 JS 脚本不起作用。
我想做的是:
情况 1:如果用户从下拉列表 #1 中选择一个值,则下拉列表 #2 的值取决于下拉列表 #1,下拉列表 #3 的值取决于下拉列表 #2。例如。州 - 市 - 大道
情况 2:用户可以从 3 个下拉列表中进行选择。
情况 3 和 4:如果用户从下拉菜单 #2 中选择,则下拉菜单 #3 的值取决于下拉菜单 #2(但如果下拉菜单 #2 已经存在,则在下拉菜单 #3 中选择一个值是可选的)
形式:
<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);
});
我创建了级联父子 select-boxes ,但由于您使用的是 NativeJS,我尝试使用 JS 重新创建。我的解决方案的先决条件是定义明确的 JSON,select-boxes 将基于此创建。您必须在服务器端创建 JSON 或手动创建 select-box 数据。以下是 JSON 格式:
每个 select-box 都是一个具有以下属性的命名对象:
- 父属性:作为此 select-box 对象的父对象的名称。
Options:选项对象数组,其中每个对象包含:(a) Option Value (b) Parent Option Value - 当前值与之对应的父select-box值映射。 (c) 选项 ID.
选定选项:具有两个属性的对象:(a) 当前 selected 值 (b) 当前 selected 值的 ID。
这是解决方案的working Plunker。希望对你有帮助。
----- 编辑:-----
根据@User014019 的要求
Here 是此下拉解决方案的另一个版本,其中所有 select 框中的所有选项最初都是可见的,并且在用户 [=47= 时设置父子关系] 一个特定的值。
代码如下:
// 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;
}
}
我有 3 个下拉菜单,值动态填充 mysql。现在,我正在尝试级联 3 个下拉菜单,但 JS 脚本不起作用。
我想做的是:
情况 1:如果用户从下拉列表 #1 中选择一个值,则下拉列表 #2 的值取决于下拉列表 #1,下拉列表 #3 的值取决于下拉列表 #2。例如。州 - 市 - 大道
情况 2:用户可以从 3 个下拉列表中进行选择。
情况 3 和 4:如果用户从下拉菜单 #2 中选择,则下拉菜单 #3 的值取决于下拉菜单 #2(但如果下拉菜单 #2 已经存在,则在下拉菜单 #3 中选择一个值是可选的)
形式:
<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);
});
我创建了级联父子 select-boxes
每个 select-box 都是一个具有以下属性的命名对象:
- 父属性:作为此 select-box 对象的父对象的名称。
Options:选项对象数组,其中每个对象包含:(a) Option Value (b) Parent Option Value - 当前值与之对应的父select-box值映射。 (c) 选项 ID.
选定选项:具有两个属性的对象:(a) 当前 selected 值 (b) 当前 selected 值的 ID。
这是解决方案的working Plunker。希望对你有帮助。
----- 编辑:-----
根据@User014019 的要求
Here 是此下拉解决方案的另一个版本,其中所有 select 框中的所有选项最初都是可见的,并且在用户 [=47= 时设置父子关系] 一个特定的值。
代码如下:
// 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;
}
}