你的问题是部分基于单个渲染htmlAdminProductDetailModel
对象,但您正在尝试回发集合。当您动态添加新对象时,您会继续添加看起来像这样的重复控件<input name="productTotalQuantity" ..>
(这也会创建无效的 html,因为重复的id
属性)在需要的地方<input name="[0].productTotalQuantity" ..>
, <input name="[1].productTotalQuantity" ..>
等等,以便在回发时绑定到集合。
The DefaultModelBinder
要求集合项的索引器从零开始并且是连续的,或者表单值包含Index=someValue
索引器在哪里someValue
(例如<input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC">
。 Phil Haack 的文章对此进行了详细解释模型绑定到列表。使用索引方法通常更好,因为它还允许您从列表中删除项目(否则有必要重命名所有现有控件,以便索引器是连续的)。
解决您的问题的两种可能的方法。
Option 1
Use the 开始项目集合您的部分视图的帮手。这个助手将为Index
基于 GUID 的值。您在局部视图和渲染现有项目的循环中都需要它。你的部分看起来像
@model IKLE.Model.ProductModel.AdminProductDetailModel
@using(Html.BeginCollectionItem())
{
<div class="editor-field">
@Html.LabelFor(model => model.fkConfigChoiceCategorySizeId)
@Html.DropDownListFor(model => model.fkConfigChoiceCategorySizeId, Model.sizeList, "--Select Size--")
@Html.ValidationMessageFor(model => model.fkConfigChoiceCategorySizeId)
</div>
....
}
Option 2
使用“假”索引器手动创建表示新对象的 html 元素,将它们放置在隐藏容器中,然后在“添加”按钮事件中克隆 html,更新索引器和索引值并将克隆的元素附加到 DOM。为了确保 html 正确,请在 a 中创建一个默认对象for
循环并检查它生成的 html。这种方法的一个例子显示在这个答案
<div id="newItem" style="display:none">
<div class="editor-field">
<label for="_#__productTotalQuantity">Quantity</label>
<input type="text" id="_#__productTotalQuantity" name="[#].productTotalQuantity" value />
....
</div>
// more properties of your model
</div>
请注意,使用“假”索引器来防止回发时绑定该索引器(“#”和“%”不会匹配,因此它们会被DefaultModelBinder
)
$('#addField').click(function() {
var index = (new Date()).getTime();
var clone = $('#NewItem').clone();
// Update the indexer and Index value of the clone
clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']'));
clone.html($(clone).html().replace(/"%"/g, '"' + index + '"'));
$('#yourContainer').append(clone.html());
}
选项 1 的优点是您可以在模型中强类型化视图,但这意味着每次添加新项目时都会调用服务器。选项 2 的优点是它全部在客户端完成,但是如果您对模型进行任何更改(例如向属性添加验证属性),那么您还需要手动更新 html,这使得维护变得更加困难。
最后,如果您使用客户端验证(jquery-validate-unobtrusive.js),那么每次向 DOM 添加新元素时都需要重新解析验证器,如下所述这个答案.
$('form').data('validator', null);
$.validator.unobtrusive.parse($('form'));
当然,您需要更改 POST 方法以接受集合
[HttpPost]
public ActionResult AddDetail(IEnumerable<AdminProductDetailModel> model)
{
....
}