使用jQuery动态添加INPUT和SELECT字段的问题排查
问题解决:动态添加带SELECT的表格行并正确提交数据
问题根源
- 你使用了固定名称的
DropDownList("Status", ...),没有像其他表单字段那样采用带索引的强类型命名格式(如a[j].Project),导致克隆后的下拉框名称始终为Status,无法和数组模型绑定,提交时数据无法被后端正确识别。 - 隐藏字段赋值时用
$("#id")和$("#email")按ID选择元素,但动态生成的行中这些元素ID重复,会导致赋值错误。 - 克隆下拉框后未重置选中状态,新增行会继承最后一行的选中值,不符合新增空白行的需求。
解决方案
1. 修改Razor代码,改用强类型DropDownListFor
将固定名称的下拉框替换为强类型绑定的DropDownListFor,确保下拉框的name属性带有索引,和其他字段命名规则一致:
@if (Model != null && Model.Count > 0) { int j = 0; foreach (var i in Model) { <tr style="border:1px solid black"> <td>@Html.TextBoxFor(a => a[j].Project, new { @required = "required" })</td> <td>@Html.TextBoxFor(a => a[j].Task, new { @required = "required" })</td> <td></td> <!-- 改用DropDownListFor绑定模型的Status属性,自动生成带索引的name --> <td>@Html.DropDownListFor(a => a[j].Status, ViewBag.EnumList as SelectList, "请选择状态", new { @required = "required" })</td> <td>@Html.TextBoxFor(a => a[j].UserId, new { @class = "id", @type = "hidden" })</td> <td>@Html.TextBoxFor(a => a[j].Email, new { @class = "email", @type = "hidden" })</td> <td>@Html.TextBoxFor(a => a[j].Date, new { @type = "hidden" })</td> <td></td> <td> @if (j > 0) { <!-- 移除重复ID,改用类选择器绑定事件 --> <button class="remove btn btn-warning">Remove</button> } </td> </tr> j++; } }
2. 修改jQuery代码,完善克隆逻辑
修复下拉框名称替换、隐藏字段赋值、表单元素状态重置等问题:
$("#addNew").click(function (e) { e.preventDefault(); var $tableBody = $("#dataTable"); var $trLast = $tableBody.find("tr:last"); // 从最后一行获取隐藏字段值,避免全局选择冲突 var email = $trLast.find(".email").val(); var userId = $trLast.find(".id").val(); var $trNew = $trLast.clone(); // 提取当前行的索引后缀 var suffix = $trNew.find(':input:first').attr('name').match(/\d+/)[0]; var newSuffix = parseInt(suffix) + 1; // 更新移除按钮,去掉重复ID $trNew.find("td:last").html('<button class="remove btn btn-warning">Remove</button>'); // 遍历所有表单元素,修改名称并重置状态 $trNew.find(':input').each(function () { var $this = $(this); // 修改name属性的索引值 var oldName = $this.attr('name'); var newName = oldName.replace('[' + suffix + ']', '[' + newSuffix + ']'); $this.attr('name', newName); // 移除重复的ID属性 $this.removeAttr('id'); // 根据元素类型处理值或状态 var type = $this.attr('type'); if (type) { switch (type.toLowerCase()) { case "text": case "hidden": // 隐藏字段赋值对应值,普通文本框清空 if ($this.hasClass('id')) { $this.val(userId); } else if ($this.hasClass('email')) { $this.val(email); } else { $this.val(''); } break; } } else if ($this.is('select')) { // 重置下拉框为默认选中项 $this.prop('selectedIndex', 0); } // 移除验证错误样式 $this.removeClass("input-validation-error"); }); $trLast.after($trNew); // 重新解析表单验证规则 var form = $("form") .removeData("validator") .removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse(form); }); // 用类选择器绑定移除事件,避免ID冲突 $(document).on('click', '.remove', function () { $(this).closest('tr').remove(); });
关键修改说明
- 强类型下拉框绑定:通过
DropDownListFor生成带索引的name(如a[1].Status),确保提交时能正确绑定到后端数组模型。 - 避免重复ID:移除按钮和表单元素不再使用重复ID,改用类选择器操作,避免DOM选择冲突。
- 精准赋值隐藏字段:从最后一行的元素中获取隐藏字段值,确保每个新增行的隐藏字段值正确。
- 重置表单状态:清空文本框内容、重置下拉框选中状态,避免克隆后继承旧数据。
- 重新验证表单:新增行后重新解析验证规则,确保新增的必填字段能被正确校验。
内容的提问来源于stack exchange,提问作者Rezo
相关产品推荐
相关产品推荐

