如何实现父子关系Select Box的动态绑定
动态绑定父子关系下拉框问题
需求说明
- 页面加载时显示「Program Type」下拉框,选项为Type A和Type B
- 选择Type A后,生成其子选项对应的下拉框(No of Days、color of the car),以此类推完成层级展开
- 页面末尾的按钮需在所有子下拉框都选择到无后代的选项后激活
现有数据源
var jsonData = [{ "id": 1, "title": "Program Type", "field_value": "Select program type", "type_id": "1", "width": "500", "height": "500", "children": [{ "id": "2", "title": "Type A", "field_value": "Type A", "type_id": "1", "width": "500", "height": "500", "children": [{ "id": "4", "title": "No of Days", "field_value": "No of Days", "type_id": "1", "width": "500", "height": "500", "children": [{ "id": "6", "title": "3 Days", "field_value": "3 Days", "type_id": "1", "width": "500", "height": "500", "children": [] }, { "id": "7", "title": "2 Days", "field_value": "2 Days", "type_id": "1", "width": "500", "height": "500", "children": [] }] }, { "id": "5", "title": "color of the car", "field_value": "color of the car", "type_id": "1", "width": "500", "height": "500", "children": [{ "id": "8", "title": "Red", "field_value": "Red", "type_id": "1", "width": "500", "height": "500", "children": [] }, { "id": "9", "title": "Black", "field_value": "Black", "type_id": "1", "width": "500", "height": "500", "children": [] }] }] }, { "id": "3", "title": "Type B", "field_value": "Type B", "type_id": "1", "width": "500", "height": "500", "children": [{ "id": "10", "title": "typ b child a", "field_value": "typ b child a", "type_id": "1", "width": "500", "height": "500", "children": [] }, { "id": "11", "title": "typ b child b", "field_value": "typ b child b", "type_id": "1", "width": "500", "height": "500", "children": [] }] }] }];
尝试的代码(存在问题)
var jsonData = <?php echo json_encode($allData); ?>;
let displayObj = ''; jsonData.forEach(function (rootObject) { displayObj += '<div class="row">'; displayObj += '<div class="col-md-6">'; displayObj += '<label for="inputEmail4" class="form-label"> '+rootObject.title+' </label>'; displayObj += '<select id="'+rootObject.title.toLowerCase().replace(' ', '_')+'" class="form-select" onchange="handleSelectChange(this)">'; displayObj += '<option value="0"> '+rootObject.field_value+' </option>'; rootObject.children.forEach(function (childObj){ displayObj += '<option value="'+childObj.field_value+'"> '+childObj.field_value+' </option>'; }); displayObj += '</select>'; displayObj += '</div>'; displayObj += '</div>'; }); $('#select-container').html(displayObj);
function renderOptions(options, parentId) { var select = $('<select>', { id: parentId, class: 'form-select', onchange: 'handleSelectChange(this)' }); select.append('<option value="">Select an option</option>'); options.forEach(function (option) { select.append('<option value="' + option.id + '"> ' + option.title + '</option>'); }); $('#select-container').append(select); }
function handleSelectChange(select) { var selectedValue = $(select).val(); console.log('Selected value:', selectedValue); // Remove existing child select boxes $(select).nextAll('select').remove(); // Check if the selected option has children var selectedOption = jsonData.find(obj => obj.id == selectedValue); if (selectedOption && selectedOption.children && selectedOption.children.length > 0) { // Create and append a new select box for each child renderOptions(selectedOption.children, selectedOption.title.toLowerCase().replace(' ', '_')); } }
问题分析与修正方案
原代码核心问题:
- 无法查找嵌套子节点:
jsonData.find仅能遍历顶层节点,无法定位深层子节点 - 渲染逻辑错误:选中Type A后需同时渲染两个子下拉框,原代码仅生成一个
- 缺少按钮激活判断逻辑:未实现检查所有层级是否选择完成的逻辑
修正后的完整代码
<div id="select-container"></div> <button id="submit-btn" disabled>提交</button>
// 递归查找对应ID的节点 function findNodeById(nodes, id) { for (let node of nodes) { if (node.id == id) return node; if (node.children && node.children.length > 0) { let found = findNodeById(node.children, id); if (found) return found; } } return null; } // 渲染单个下拉框组(包含label和布局结构) function renderSelectGroup(node, container) { const row = $('<div class="row mb-3"></div>'); const col = $('<div class="col-md-6"></div>'); const label = $(`<label class="form-label">${node.title}</label>`); const selectId = node.title.toLowerCase().replace(' ', '_'); const select = $(`<select id="${selectId}" class="form-select"></select>`); // 添加默认提示选项 select.append(`<option value="">${node.field_value}</option>`); // 添加子选项 node.children.forEach(child => { select.append(`<option value="${child.id}">${child.title}</option>`); }); // 绑定选择事件 select.on('change', function() { handleSelectChange(this, container); }); col.append(label).append(select); row.append(col); container.append(row); } // 处理下拉框选择事件 function handleSelectChange(select, container) { const selectedId = $(select).val(); const $selectRow = $(select).closest('.row'); // 移除当前下拉框之后的所有层级下拉框 $selectRow.nextAll('.row').remove(); if (!selectedId) { checkSubmitStatus(); return; } // 查找选中的节点 const selectedNode = findNodeById(jsonData, selectedId); if (!selectedNode) return; // 渲染所有子下拉框组 if (selectedNode.children && selectedNode.children.length > 0) { selectedNode.children.forEach(child => { renderSelectGroup(child, container); }); } checkSubmitStatus(); } // 检查是否所有下拉框都选择到无后代的选项,控制按钮状态 function checkSubmitStatus() { const selects = $('#select-container .form-select'); let allCompleted = true; for (let i = 0; i < selects.length; i++) { const select = selects[i]; const selectedId = $(select).val(); if (!selectedId) { allCompleted = false; break; } const node = findNodeById(jsonData, selectedId); if (node.children && node.children.length > 0) { allCompleted = false; break; } } $('#submit-btn').prop('disabled', !allCompleted); } // 页面初始化 $(document).ready(function() { const container = $('#select-container'); jsonData.forEach(root => { renderSelectGroup(root, container); }); checkSubmitStatus(); });
修正要点说明
- 递归节点查找:新增
findNodeById函数,遍历所有层级节点定位目标项 - 结构化渲染:每个下拉框包含label和标准布局结构,保持页面样式统一
- 层级清理:选中选项后移除当前下拉框之后的所有层级,避免残留旧组件
- 按钮激活逻辑:
checkSubmitStatus函数检查所有下拉框是否都选择到无后代的选项,满足条件则启用提交按钮
内容的提问来源于stack exchange,提问作者Randheer Singh Chouhan
相关产品推荐
相关产品推荐

