ASP.NET Core 带下拉列表的多行插入无法新增行问题
问题原因
新增行功能失效的核心触发点是JS运行时报错中断,连带还有几个逻辑和语法问题:
- 下拉框是
<select>元素,本身没有type属性,原有代码在遍历输入元素时直接取type属性后调用toLowerCase(),对select元素来说取到的type是undefined,执行方法直接抛类型错误,整个新增行的逻辑直接终止,这就是加了下拉框之后点按钮没反应的直接原因。 - 动态新增的删除按钮没有用事件委托绑定事件,新增出来的行点删除无响应。
- 视图里的Razor语法漏写
@前缀,Html.BeginForm、AntiForgeryToken、ValidationSummary这些辅助方法会被直接当普通文本输出,表单根本不会正常渲染。 - 克隆行时没有重置下拉框的选中状态,新增行会直接复制上一行的选中值,不符合初始空选的预期。
- 行内多个div写了固定id,重复id会导致DOM查询、表单验证出现异常。
修复方案
1. 修正JS新增行逻辑
把原来只处理text输入框的逻辑改成兼容select,加上空值判断避免报错,同时重置下拉框选中状态,把删除按钮的事件改成委托形式:
$(document).ready(function () { // 新增行 $("#addNew").click(function (e) { e.preventDefault(); var $tableBody = $("#dataTable"); var $trLast = $tableBody.find("tr:has(:input)").last(); // 排除表头行 var $trNew = $trLast.clone(true); // 取当前行索引 var suffix = $trNew.find(':input:first').attr('name').match(/\d+/)[0]; var newIndex = parseInt(suffix) + 1; $trNew.find("td:last").html('<a href="#" class="remove">Remove</a>'); $.each($trNew.find(':input'), function (i, val) { // 更新name属性的索引 var oldN = $(this).attr('name'); var newN = oldN.replace('[' + suffix + ']', '[' + newIndex + ']'); $(this).attr('name', newN); // 更新id属性避免重复 var oldId = $(this).attr('id'); if(oldId){ $(this).attr('id', oldId.replace('_' + suffix + '__', '_' + newIndex + '__')); } // 重置值,兼容text和select if ($(this).is('input[type="text"]')) { $(this).val(''); } if ($(this).is('select')) { $(this).prop('selectedIndex', 0); // 重置为第一个选项,需要空选可以加默认空选项 } // 清除验证错误样式 $(this).removeClass("input-validation-error"); $(this).nextAll('.field-validation-error').remove(); }); $trLast.after($trNew); // 重新绑定表单验证 var form = $("form") .removeData("validator") .removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse(form); }); // 删除行,用事件委托兼容动态新增元素 $(document).on("click", 'a.remove', function (e) { e.preventDefault(); $(this).closest('tr').remove(); }); });
2. 修正视图Razor语法错误
把漏写的@前缀补上,去掉重复的固定id,下拉框可加默认空选项提升使用体验:
@model List<EFCore.Models.ContactInfoNew> @{ ViewBag.Title = "Insert Bulk Data"; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/json2/20160511/json2.js" integrity="sha512-h3RrO+eudpiPUYFkwORXD2ppuy9jOXQ+MzVEIo7k+OuA7y9Ze5jsQ5WN/ZSgI+ZSIngT6pDSaqpgmnam2HPe1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <div style="width:700px; padding:5px; background-color:white;"> @* 补@前缀修正Razor语法 *@ @using (Html.BeginForm("BulkData","Home", FormMethod.Post)) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) if (ViewBag.Message != null) { <div style="border:solid 1px green"> @ViewBag.Message </div> } <div><a href="#" id="addNew">Add New</a></div> <table id="dataTable" border="0" cellpadding="0" cellspacing="0"> <tr> <th>Contact Name</th> <th>Contact No</th> <th>Test</th> <th></th> </tr> @if (Model != null && Model.Count > 0) { int j = 0; foreach (var i in Model) { <tr style="border:1px solid black"> <td> @* 移除重复固定id *@ @Html.TextBoxFor(a=>a[j].ContactName) </td> <td> @Html.TextBoxFor(a=>a[j].ContactNo) </td> <td> @* 增加默认空选项 *@ @Html.DropDownListFor(a=>a[j].TestId, (IEnumerable<SelectListItem>)ViewBag.New, "--请选择--") </td> <td> @if (j > 0) { <a href="#" class="remove">Remove</a> } </td> </tr> j++; } } </table> <input type="submit" value="Save Bulk Data" /> } </div>
3. 可选优化
ASP.NET Core的模型绑定默认支持非连续索引,如果删除中间行后担心绑定失败,可以在删除行后重新遍历所有数据行,更新输入框name属性的索引值保持连续,或者为每个条目添加对应索引的隐藏字段即可。
内容的提问来源于stack exchange,提问作者ShannonNW
相关产品推荐
相关产品推荐

