克隆输入框的OnChange事件失效,AJAX无法传值问题
问题分析与解决方案
核心问题
- 重复ID冲突:原代码里的
#brand、#model、#serialNo、#deviceLevel这些ID被克隆到新行,DOM中ID必须唯一,jQuery用ID选择器只会匹配第一个元素,导致新行的AJAX永远只操作第一行的输入框。 - 事件与逻辑不匹配:内联
onchange虽然能被克隆,但checkDeviceStatus函数里的取值/赋值都是全局找ID,没有定位到触发事件的当前行。
修改步骤
1. 修正HTML:用类名替代重复ID,移除内联事件
只修改SLA表格的行内容(非SLA部分无需改动):
<tr> <td> <select class="form-control form-select brand" data-bs-placeholder="Select" name="brand[]" required> <!-- 原PHP循环内容不变 --> </select> </td> <td> <select class="form-control form-select model" data-bs-placeholder="Select" name="model[]" required> <!-- 原PHP循环内容不变 --> </select> </td> <td><input type="text" name="serialNo[]" class="form-control serialNo"></td> <td><input type="text" name="deviceLevel[]" class="form-control deviceLevel" readonly></td> <input type="text" name="client[]" class="client" value="<?= $clientID ?>" hidden> <td><button type="button" class=" btn text-danger" data-name="del"><i class="fe fe-minus-circle" style="font-size:1.6em;"></i></button></td> </tr>
- 移除所有重复ID,改用类名(
.brand、.model、.serialNo、.deviceLevel、.client) - 移除内联
onchange事件 - 把
name属性改成数组形式(比如brand[]),方便表单提交时获取所有行的数据
2. 重构JS:事件委托+行内逻辑定位
替换原JS中的AJAX部分和事件绑定:
function restrictAlphabets(e) { var x = e.which || e.keyCode; return (x >= 48 && x <= 57); } // 克隆表格行逻辑不变,无需修改 document.querySelector('button[data-name="add"]').addEventListener('click', e => { let tbody = e.target.closest('table').querySelector('tbody'); let clone = tbody.firstElementChild.cloneNode(true); clone.querySelector('button[data-name="del"]').hidden = false; clone.querySelectorAll('input, select').forEach(n => { n.value = ''; }); tbody.appendChild(clone); }); document.querySelector('form table#dyntbl').addEventListener('click', e => { e.stopPropagation(); if (e.target != e.currentTarget && (e.target.dataset.name == 'del' || e.target.parentNode.dataset.name == 'del')) { let tbody = e.target.closest('table').querySelector('tbody'); if (tbody.childNodes.length > 3) tbody.removeChild(e.target.closest('tr')); } }); // 事件委托:绑定change事件到tbody,覆盖动态新增的行 document.querySelector('#dyntbl tbody').addEventListener('change', function(e) { // 只处理目标是品牌、型号、序列号的情况 if (e.target.classList.contains('brand') || e.target.classList.contains('model') || e.target.classList.contains('serialNo')) { let currentRow = e.target.closest('tr'); checkDeviceStatus(currentRow); } }); // 重构AJAX函数:接收当前行作为参数,只操作该行的元素 function checkDeviceStatus(row) { var dModel = row.querySelector('.model').value; var dBrand = row.querySelector('.brand').value; var dserial = row.querySelector('.serialNo').value; var client = row.querySelector('.client').value; // 确保必填项都有值再发AJAX if (!dModel || !dBrand || !dserial) return; $.ajax({ url: "./handlers/slaChecker.php", type: "POST", data: { dModel: dModel, dserial: dserial, client: client, dBrand: dBrand }, success: function(result) { row.querySelector('.deviceLevel').value = result; console.log(result); } }); }
- 用事件委托绑定
change事件到表格tbody,动态新增的行自动继承事件 checkDeviceStatus函数接收当前行作为参数,通过行来定位该行的所有元素,确保取值和赋值都只针对当前行- 增加必填项判断,避免空值发送AJAX请求
内容的提问来源于stack exchange,提问作者Cephas Armah
相关产品推荐
相关产品推荐

