基于MySQL+PHP+JS的级联下拉动态添加行功能实现求助
批量硬件变更记录录入联动下拉故障排查
我正使用MySQL、PHP、JavaScript搭建设备日志系统,已自学相关技术3个月,现有代码多来自技术论坛。已实现单条硬件变更记录录入功能:Subsystem下拉从数据库拉取子系统列表,Component下拉根据选中的Subsystem动态填充,提交入库逻辑正常,提交后可返回页面新增下一条记录。
改造为单页可批量添加多条修改记录的功能时,动态新增行的Subsystem下拉能正常拉取表数据,但对应的Component下拉无法填充。参考的单表适配教程适配双表结构时函数逻辑出错,不确定问题位置,需要排查方向指引。
表结构
- lu_subsystem表
| id | subsystem_name |
|---|---|
| 子系统ID | 子系统名称 |
- lu_component表
| component_id | subsystem_id | component_name |
|---|---|---|
| 组件ID | 关联子系统ID | 组件名称 |
现有代码
index.php
<?php //index.php include('database_connection.php'); ?> <!DOCTYPE html> <html> <head> <title>动态联动下拉批量录入工具</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" /> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </head> <body> <br /> <div class="container"> <h3 align="center">动态联动下拉批量录入工具</h3> <br /> <h4 align="center">填写变更记录</h4> <br /> <form method="post" id="insert_form"> <div class="table-responsive"> <span id="error"></span> <table class="table table-bordered" id="item_table"> <thead> <tr> <th>变更内容</th> <th>所属子系统</th> <th>关联组件</th> <th><button type="button" name="add" class="btn btn-success btn-xs add"><span class="glyphicon glyphicon-plus"></span></button></th> </tr> </thead> <tbody></tbody> </table> <div align="center"> <input type="submit" name="submit" class="btn btn-info" value="批量提交" /> </div> </div> </form> </div> </body> </html> <script> $(document).ready(function(){ var count = 0; $(document).on('click', '.add', function(){ count++; var html = ''; html += '<tr>'; html += '<td><input type="text" name="item_name[]" class="form-control item_name" /></td>'; html += '<td><select name="subsystem_id[]" class="form-control subsystem_id" data-subsystem_id="'+count+'"><option value="">选择子系统</option><?php echo fill_select_box($connect, "0"); ?></select></td>'; html += '<td><select name="item_component_id[]" class="form-control item_component_id" id="item_component_id'+count+'"><option value="">选择组件</option></select></td>'; html += '<td><button type="button" name="remove" class="btn btn-danger btn-xs remove"><span class="glyphicon glyphicon-minus"></span></button></td>'; $('tbody').append(html); }); $(document).on('click', '.remove', function(){ $(this).closest('tr').remove(); }); $(document).on('change', '.subsystem_id', function(){ var id = $(this).val(); var component_id = $(this).data('component_id'); $.ajax({ url:"fill_sub_category.php", method:"POST", data:{subsystem_id:subsystem_id}, success:function(data) { var html = '<option value="">选择组件</option>'; html += data; $('#item_component_id'+component_id).html(html); } }) }); $('#insert_form').on('submit', function(event){ event.preventDefault(); var error = ''; $('.item_name').each(function(){ var count = 1; if($(this).val() == '') { error += '<p>第'+count+'行未填写变更内容</p>'; return false; } count = count + 1; }); $('.item_category').each(function(){ var count = 1; if($(this).val() == '') { error += '<p>第'+count+'行未选择子系统</p>'; return false; } count = count + 1; }); $('.item_component_id').each(function(){ var count = 1; if($(this).val() == '') { error += '<p>第'+count+'行未选择组件</p> '; return false; } count = count + 1; }); var form_data = $(this).serialize(); if(error == '') { $.ajax({ url:"insert.php", method:"POST", data:form_data, success:function(data) { if(data == 'ok') { $('#item_table').find('tr:gt(0)').remove(); $('#error').html('<div class="alert alert-success">变更记录保存成功</div>'); } } }); } else { $('#error').html('<div class="alert alert-danger">'+error+'</div>'); } }); }); </script>
database_connection.php
<?php //database_connection.php $connect = new PDO("mysql:host=localhost; dbname=bunker_logs;", "root", ""); function fill_select_box($connect, $id) { $query = "SELECT * FROM lu_subsystem"; $statement = $connect->prepare($query); $statement->execute(); $result = $statement->fetchAll(); $output = ''; foreach($result as $row) { $output .= '<option value="'.$row["id"].'">'.$row["subsystem_name"].'</option>'; } return $output; } function fill_component_box($connect, $component_id) { $query = "SELECT * FROM lu_component WHERE component_id ='" .$id."'"; $statement = $connect->prepare($query); $statement->execute(); $result = $statement->fetchAll(); $output = ''; foreach($result as $row) { $output .= '<option value="'.$row["component_id"].'">'.$row["component_name"].'</option>'; } return $output; } ?>
fill_component.php
<?php //fill_component.php include('database_connection.php'); echo fill_component_box($connect, $_POST["subsystem_id"]); ?>
故障修复方案
- 修复自定义属性取值错误:subsystem下拉的自定义属性为
data-subsystem_id,change事件中取值逻辑要改为var row_index = $(this).data('subsystem_id'),才能匹配对应行Component下拉的ID后缀。 - 修复Ajax参数错误:change事件中已将选中的子系统ID存入
id变量,传参要改为data:{subsystem_id:id},避免变量未定义报错。 - 修复接口地址错误:Ajax请求地址改为
fill_component.php,和后端文件名一致。 - 修复SQL查询逻辑错误:
fill_component_box函数的查询条件要改为WHERE subsystem_id = " .$id,按子系统外键查询对应组件,而非按组件ID查询。 - 修复表单校验错误:删除
$('.item_category')对应的冗余校验逻辑,该选择器在代码中不存在,会导致校验逻辑异常。
学习路径建议
- 优先掌握浏览器开发者工具用法:调试时先看控制台JS报错、网络请求的参数和返回值,可快速定位绝大多数前后端交互问题。
- 夯实SQL基础:搞清楚多表关联的外键对应关系,避免查询条件字段混淆。
- 学习jQuery基础用法:重点掌握动态元素的事件委托、自定义属性操作、选择器匹配规则。
内容的提问来源于stack exchange,提问作者Delnoth
相关产品推荐
相关产品推荐

