我有一张桌子:
<% using(Html.BeginForm("View2","Order"))
{ %>
<table id="Products" class="Products">
<tr>
<th>ProductId</th>
<th>Productname</th>
<th>Quantity</th>
<th>UnitPrice</th>
</tr>
<% for(int i=0; i < Model.NorthOrderDetails.Count; i++)
{ %>
<tr>
<td><%: Html.Label(Model.NorthOrderDetails[i].ProductID.ToString()) %></td>
<td><%: Html.Label(Model.NorthOrderDetails[i].ProductName) %> </td>
<td><%: Html.TextBoxFor(m => m.NorthOrderDetails[i].Quantity) %></td>
<td><%: Html.TextBoxFor(m => m.NorthOrderDetails[i].UnitPrice) %></td>
<td><button type="button" class="delete" data-id="<%:Model.NorthOrderDetails[i].ProductID %>">Delete</button><td>
<td><input type="hidden" name="<%:Model.NorthOrderDetails[i].ProductName %>" value="<%:i %>" /><td>
<tr>
<% } %>
</table>
<input type="submit" name="button" value="Add" />
<input type="submit" name="button" value="Save" />
<% } %>
当我点击删除按钮时,我正在调用此脚本:
<script type="text/javascript">
var url = '<%:Url.Action("Delete", "Order")%>';
$('.delete').click(function () {
var id = $(this).data('id'); // Get the product ID
var row = $(this).closest('tr');// Get the table row
$.post(url, { ID: id }, function () {
row.remove(); // remove the row from the table
});
});
</script>
脚本在Controller中调用此方法
[HttpPost]
public JsonResult Delete(int ID)
{
NorthOrder forOrderDetail = (NorthOrder)Session["Order"];
forOrderDetail.NorthOrderDetails.RemoveAll(z => z.ProductID == ID);
Session["Order"] = forOrderDetail;
return Json(null);
}
在UI中,当我单击提交按钮时,行会正确删除。但是在控制器方法中,当我删除第一行时,集合的计数等于null,当我删除最后一行时,它的等于1 例如,表加载页面时包含两行
public ActionResult View2(NorthOrder q, string button)
{
}
为什么?
答案 0 :(得分:1)
由于您要删除某些行,但在Save
提交操作中回发整个集合,因此您的索引器要么不是从零开始,要么是非连续的。在删除第1行的情况下,发布的值为
NorthOrderDetails[1].Quantity=SomeValue&NorthOrderDetails[1].UnitPrice=SomeOtherValue
NorthOrderDetails[0]...
没有值,因此绑定失败,集合为空。
默认情况下,DefaultModelBinder
要求集合索引器从零开始并且不连续。删除项目并从DOM中删除其控件时,无法正确绑定集合。要完成这项工作,您需要添加DefaultModelBinder
用于匹配集合属性的额外隐藏输入。将视图代码更改为
% for(int i=0; i < Model.NorthOrderDetails.Count; i++)
{%>
<tr>
<td><%: Html.DisplayFor(m => m.NorthOrderDetails[i].ProductID) %></td> // Remove the .ToString()
<td><%: Html.DisplayFor(m => m.NorthOrderDetails[i].ProductName) %></td>
<td>
<input type="hidden" name="NorthOrderDetails.Index" value="<%: i %>" /> // add this
<%: Html.TextBoxFor(m => m.NorthOrderDetails[i].Quantity) %>
</td>
<td><%: Html.TextBoxFor(m => m.NorthOrderDetails[i].UnitPrice) %></td>
<td><button type="button" class="delete" data-id="<%:Model.NorthOrderDetails[i].ProductID %>">Delete</button><td>
<td><input type="hidden" name="<%:Model.NorthOrderDetails[i].ProductName %>" value="<%:i %>" /><td>
<tr>
<% } %>
注意:我早就忘记了aspx,但隐藏输入的剃刀代码是<input type="hidden" name="NorthOrderDetails.Index" value="@i" />
,所以你可能想检查我的语法。
附注:
Delete
中
方法,您要删除该项目。当你终于保存了
集合,你需要从中获取原始集合
数据库并比较它们以确定要删除的项目
数据库。相反,你Delete()
方法应该调用
数据库删除项目(请参阅我对previous
question的答案)Add
按钮不应该是,提交并发布到
View2()
方法。