如何解决多行表单中相同ID下拉框的同行联动异常问题?
问题描述

我开发了这个页面,此处所有下拉列表的ID都设置为相同值。现在的问题是:当我选择第一行的下拉列表时,需要在同行的下一个下拉列表中加载数据;但当我选择最后一行的下拉列表时,数据却加载到了第一行的对应控件中。我需要实现选择某行下拉列表时,仅在该行的对应控件中加载数据,有没有人能帮我解决这个问题?
<tr> <%-- <td class="td1">${row.index+1}</td> --%> <td class="td1"><input readonly class="sno" name="sno" id="sno" value="1" size="1"></td> <td class="td1"> <select name="UserType[]" disabled id="UserType[]" onchange="showUserRole(this.value);" style="width: 130px;"> <option value="CD5306">Doctor</option> </select> </td> <td class="td1"> <select name="UserRole[]" id="UserRole[]" onchange="fetchUsers(this.value);" style="width: 150px;"> <option value="-1">------Select------</option> <c:forEach var="x" items="${UserRole1}"> <option ${UserRole eq x.ID ? 'selected':''} value="${ x.ID }">${x.VALUE }</option> </c:forEach> </select> </td> <td class="td1"> <select name="Name[]" id="Name[]" onchange="fetchCfms(this.value);" style="width: 150px;" onblur="getIndexValue(this)"> <option value="-1">------Select------</option> <c:forEach var="x" items="${Name}"> </c:forEach> </select> </td> <td class="td1"> <input type="text" readonly name="cfmsid[]" id="cfmsid[]" value="${cfmsid }" size="10"> </td> <td class="td1"> <img src="/ASRI/ASRI-images/add1.png" height="30" width="30" onclick="addField(this)" title="Click here to addmore"> <img src="/ASRI/ASRI-images/remove1.png" height="30" width="30" onclick="removeManpower(this)" title="Click here to remove"> </td> </tr> <tr> <%-- <td class="td1">${row.index+1}</td> --%> <td class="td1"><input readonly class="sno" name="sno" id="sno" value="2" size="1"></td> <td class="td1"> <select name="UserType[]" id="UserType[]" disabled onchange="showUserRole(this.value);" style="width: 130px;"> <option value="CD5307">Staff Nurse</option> </select> </td> <td class="td1"> <select name="UserRole[]" id="UserRole[]" onchange="fetchUsers(this.value);" style="width: 150px;"> <option value="-1">------Select------</option> <c:forEach var="x" items="${UserRole2}"> <option ${UserRole eq x.ID ? 'selected':''} value="${ x.ID }">${x.VALUE }</option> </c:forEach> </select> </td> <td class="td1"> <select name="Name[]" id="Name[]" onchange="fetchCfms(this.value);" style="width: 150px;" onblur="getIndexValue(this)"> <option value="-1">------Select------</option> <c:forEach var="x" items="${Name}"> </c:forEach> </select> </td> <td class="td1"> <input type="text" readonly name="cfmsid[]" id="cfmsid" value="${cfmsid }" size="10"> </td> <td class="td1"> <img src="/ASRI/ASRI-images/add1.png" height="30" width="30" onclick="addField(this)" title="Click here to addmore"> <img src="/ASRI/ASRI-images/remove1.png" height="30" width="30" onclick="removeManpower(this)" title="Click here to remove"> </td> </tr> <tr> <td class="td1"><input readonly class="sno" name="sno" id="sno" value="3" size="1"></td> <td class="td1"> <select name="UserType[]" id="UserType[]" disabled onchange="showUserRole(this.value);" style="width: 130px;"> <option value="CD5308">Class IV</option> </select> </td> <td class="td1"> <select name="UserRole[]" id="UserRole[]" onchange="fetchUsers(this.value);" style="width: 150px;"> <option value="-1">------Select------</option> <c:forEach var="x" items="${UserRole3}"> <option ${UserRole eq x.ID ? 'selected':''} value="${ x.ID }">${x.VALUE }</option> </c:forEach> </select> </td> <td class="td1"> <select name="Name[]" id="Name[]" onchange="fetchCfms(this.value);" style="width: 150px;" onblur="getIndexValue(this)"> <option value="-1">------Select------</option> <c:forEach var="x" items="${Name}"> </c:forEach> </select> </td> <td class="td1"> <input type="text" readonly name="cfmsid" id="cfmsid" value="${cfmsid }" size="10"> </td> <td class="td1"> <img src="/ASRI/ASRI-images/add1.png" height="30" width="30" onclick="addField(this)" title="Click here to addmore"> <img src="/ASRI/ASRI-images/remove1.png" height="30" width="30" onclick="removeManpower(this)" title="Click here to remove"> </td> </tr> <tr> <%-- <td class="td1">${row.index+1}</td> --%> <td class="td1"><input class="sno" readonly name="sno" id="sno" value="4" size="1"></td> <td class="td1"> <select name="UserType[]" id="UserType[]" disabled onchange="showUserRole(this.value);" style="width: 130px;"> <option value="CD5309">Lab Technician</option> </select> </td> <td class="td1"> <select name="UserRole[]" id="UserRole[]" onchange="fetchUsers(this.value);" style="width: 150px;"> <option value="-1">------Select------</option> <c:forEach var="x" items="${UserRole4}"> <option ${UserRole eq x.ID ? 'selected':''} value="${ x.ID }">${x.VALUE }</option> </c:forEach> </select> </td> <td class="td1"> <select name="Name[]" id="Name[]" onchange="fetchCfms(this.value);" style="width: 150px;" onblur="getIndexValue(this)"> <option value="-1">------Select------</option> <c:forEach var="x" items="${Name}"> </c:forEach> </select> </td> <td class="td1"> <input type="text" readonly name="cfmsid" id="cfmsid" value="${cfmsid }" size="10"> </td> <td class="td1"> <img src="/ASRI/ASRI-images/add1.png" height="30" width="30" onclick="addField(this)" title="Click here to addmore"> <img src="/ASRI/ASRI-images/remove1.png" height="30" width="30" onclick="removeManpower(this)" title="Click here to remove"> </td> </tr>
有没有人能提供解决思路?
解决思路与方案
核心问题原因
HTML中ID属性必须全局唯一,当你给多行的下拉框设置相同ID时,通过document.getElementById()获取元素只会返回第一个匹配的元素,这就是为什么选择最后一行下拉框时数据会加载到第一行控件的原因。
具体解决步骤
移除重复ID,改用类名标记控件
删除所有重复的ID(比如UserType[]、UserRole[]等),替换为对应的类名,比如user-type、user-role、user-name、cfms-id。保留name="xxx[]"的设置,不影响表单提交时的数组参数收集。修改事件绑定,传递当前元素并定位同行控件
在下拉框的onchange事件中,除了传递选中值,还要传递当前元素本身(this),然后通过DOM遍历找到当前行对应的目标控件,而非通过ID查找。
修改后的代码示例(以第一行为例)
<tr> <%-- <td class="td1">${row.index+1}</td> --%> <td class="td1"><input readonly class="sno" name="sno" value="1" size="1"></td> <td class="td1"> <select name="UserType[]" disabled class="user-type" onchange="showUserRole(this, this.value);" style="width: 130px;"> <option value="CD5306">Doctor</option> </select> </td> <td class="td1"> <select name="UserRole[]" class="user-role" onchange="fetchUsers(this, this.value);" style="width: 150px;"> <option value="-1">------Select------</option> <c:forEach var="x" items="${UserRole1}"> <option ${UserRole eq x.ID ? 'selected':''} value="${ x.ID }">${x.VALUE }</option> </c:forEach> </select> </td> <td class="td1"> <select name="Name[]" class="user-name" onchange="fetchCfms(this, this.value);" style="width: 150px;" onblur="getIndexValue(this)"> <option value="-1">------Select------</option> <c:forEach var="x" items="${Name}"> </c:forEach> </select> </td> <td class="td1"> <input type="text" readonly name="cfmsid[]" class="cfms-id" value="${cfmsid }" size="10"> </td> <td class="td1"> <img src="/ASRI/ASRI-images/add1.png" height="30" width="30" onclick="addField(this)" title="Click here to addmore"> <img src="/ASRI/ASRI-images/remove1.png" height="30" width="30" onclick="removeManpower(this)" title="Click here to remove"> </td> </tr>
修改对应的JavaScript函数
以fetchUsers为例,调整函数逻辑,通过当前元素定位同行目标控件:
function fetchUsers(elem, selectedValue) { // 获取当前元素所在的<tr>行 const row = elem.closest('tr'); // 找到该行内的user-name下拉框 const targetSelect = row.querySelector('.user-name'); // 后续加载逻辑,将数据填充到targetSelect中 // 示例: // targetSelect.innerHTML = '<option value="-1">------Select------</option>'; // 循环数据添加option选项 }
同理,showUserRole和fetchCfms函数都需要做类似修改,通过elem.closest('tr')定位当前行,再用querySelector找到该行内的目标控件,确保数据只加载到当前行的对应控件中。
额外注意点
- 动态添加行的
addField函数中,要确保新生成的行使用类名而非重复ID; name="xxx[]"的设置依然有效,后端可以正常接收数组形式的参数。
内容的提问来源于stack exchange,提问作者mano
相关产品推荐
相关产品推荐

