ASP.NET Core MVC动态增删对象列表提交异常问题求助
动态增删ASP.NET Core MVC列表项并正常提交的解决方案
问题描述
在ASP.NET Core MVC中实现动态添加/删除ProductFeature列表项,输入框命名遵循Product.ProductFeatures[0].TitleName的格式,但删除中间行后(比如3行删第2行),提交表单时仅能提交索引0的项,索引2的项被忽略,无法完成正常提交。
现有代码
模型类
public class ProductFeature { public int Id { get; set; } public required string TitleName { get; set; } public required string Value { get; set; } }
HTML结构
<div class="accordion-body w-50"> <div id="features" class="form-group"> </div> <input id="cmdAdd1" class="btn btn-primary" type="button" value="افزودن ویژگی" /> </div>
原JavaScript代码
var itemCount = 0; const removedItems = []; $('#cmdAdd1').click(function () { addNewFeature(); }); function addNewFeature() { // Add new line with text field and button if (removedItems.length == 0) { var newItem = ' <div id="item' + itemCount + '" class="input-group mb-2">'; newItem += '<input id="title' + itemCount + '" name="Product.ProductFeatures[' + itemCount + '].TitleName" placeholder="عنوان" class="form-control" type="text"/>'; newItem += '<input id="value' + itemCount + '" name="Product.ProductFeatures[' + itemCount + '].Value" placeholder="مقدار" class="form-control" type="text"/>'; newItem += '<input id="cmdAdd' + itemCount + '" type="button" class="btn btn-danger" value="حذف ویژگی"></input>'; newItem += "</div>"; $('#features').append(newItem); var thisItem = itemCount; $('#cmdAdd' + itemCount).click(function () { removeItem(thisItem); }); itemCount++; } else { var id = removedItems[0]; var newItem = ' <div id="item' + id + '" class="input-group mb-2">'; newItem += '<input id="title' + id + '" name="Product.ProductFeatures[' + id + '].TitleName" placeholder="عنوان" class="form-control" type="text"/>'; newItem += '<input id="value' + id + '" name="Product.ProductFeatures[' + id + '].Value" placeholder="مقدار" class="form-control" type="text"/>'; newItem += '<input id="cmdAdd' + id + '" type="button" class="btn btn-danger" value="حذف ویژگی"></input>'; newItem += "</div>"; $('#features').append(newItem); thisItem = id; $('#cmdAdd' + id).click(function () { removeItem(thisItem); }); removedItems.splice(0, 1); } } function removeItem(i) { $('#item' + i).remove(); removedItems.push(i); }
问题原因
ASP.NET Core的模型绑定规则要求列表项的索引是连续的非负整数。如果索引出现断层(比如删除中间项后剩下0和2),模型绑定器会停止处理后续项,导致后面的输入无法被绑定到模型中。你之前的代码复用了删除的索引,导致索引序列不连续,这就是提交时丢失项的根本原因。
修复方案
核心思路是:删除项后立即重新整理所有剩余项的索引,保证索引从0开始连续递增。同时去掉原有的复用索引逻辑,直接基于当前DOM元素数量生成新索引。
修改后的JavaScript代码
$(document).ready(function() { $('#cmdAdd1').click(function () { addNewFeature(); }); }); function addNewFeature() { // 获取当前已有的特征项数量,作为新项的索引 const currentItemCount = $('#features .input-group').length; // 用模板字符串构建新项,简化代码 const newItem = ` <div class="input-group mb-2"> <input name="Product.ProductFeatures[${currentItemCount}].TitleName" placeholder="عنوان" class="form-control" type="text"/> <input name="Product.ProductFeatures[${currentItemCount}].Value" placeholder="مقدار" class="form-control" type="text"/> <button type="button" class="btn btn-danger remove-btn">حذف ویژگی</button> </div> `; $('#features').append(newItem); // 给新增的删除按钮绑定事件 $('#features .input-group:last .remove-btn').click(function() { // 删除当前行 $(this).closest('.input-group').remove(); // 重新整理所有项的索引 reindexFeatureItems(); }); } function reindexFeatureItems() { // 遍历所有剩余的特征项,重新设置索引 $('#features .input-group').each(function(index) { // 获取当前行的两个输入框 const titleInput = $(this).find('input[name*=".TitleName"]'); const valueInput = $(this).find('input[name*=".Value"]'); // 更新name属性中的索引,保证连续 titleInput.attr('name', `Product.ProductFeatures[${index}].TitleName`); valueInput.attr('name', `Product.ProductFeatures[${index}].Value`); }); }
修改说明
- 移除了全局
itemCount变量和removedItems数组,避免索引复用导致的断层问题 - 使用类选择器
.remove-btn绑定删除事件,无需依赖动态生成的ID,避免ID冲突 - 删除项后立即调用
reindexFeatureItems函数,重新为所有输入框设置连续索引 - 用ES6模板字符串构建DOM元素,代码更易读维护
控制器接收注意事项
确保你的主模型(比如Product)包含ProductFeatures列表属性:
public class Product { // 其他业务属性... public List<ProductFeature> ProductFeatures { get; set; } = new List<ProductFeature>(); }
在POST Action中直接接收模型即可:
[HttpPost] public IActionResult SaveProduct(Product product) { // product.ProductFeatures会包含所有提交的有效项 // 后续验证、保存逻辑... return RedirectToAction("Index"); }
如果是编辑场景(已有带Id的ProductFeature),可以在每个行中添加隐藏的Id输入框,模型绑定会自动识别:
<input type="hidden" name="Product.ProductFeatures[${index}].Id" value="原有Id值"/>
内容的提问来源于stack exchange,提问作者Ali Jebali
相关产品推荐
相关产品推荐

