如果Editortemplates项目从视图中删除,MVC表单提交返回null

本文关键字:MVC 表单提交 返回 null 删除 Editortemplates 项目 视图 如果 | 更新日期: 2023-09-27 18:04:29

我使用Editortemplates来显示与表单相关联的项目列表,如果不需要,我允许用户删除行但是,当用户提交表单后,删除任何行上的POST动作,我得到收集为空,如果用户没有做任何删除的项目,我得到完整的集合在POST动作修改值。这是我用模型控制器和视图尝试的代码

模型
public class Student
{
    public string StudName { get; set; }
    public int StudId { get; set; }
    public List<Assignment> Assignments { get; set; }
}
public class Assignment 
{
    public int Id{get;set;}
    public string Name{get;set;}
    public int Amount{get;set;}
    public string Remarks{get;set;}
}

控制器行动

public ActionResult Assign(int Id)
{
    Student model = new Student { StudId = Id, StudName = "Name +" + Id };
    List<Assignment> _assignments = new List<Assignment>();
    for(int j=0;j<3;j++)
    {
        Assignment itm = new Assignment { Id = j, Name = "Assign " + j, Remarks = "Remarks " + j, Amount = j * 33 };
        _assignments.Add(itm);
    }
    model.Assignments = _assignments;
    return View(model);
}
[HttpPost]
public ActionResult Assign(int Id,Student model)
{
    return Content("rxvd "+model.Assignments.Count);
    //count is correct if not removing anything from Assign page 
    //If i remove any items from assign page then count is null
}

分配视图

@model OpenXMLMvc3.Controllers.Student
@{
    ViewBag.Title = "Assign";
}
<h2>Assign</h2>
<script type="text/javascript">
$(function () {
//call from Editor template
    $("a.deleteRow").live("click", function () {
        $(this).parents("tr.editorRow:first").remove();
        return false;
    });
});
</script>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
        <div class="col-md-6">
        <div class="editor-label">
            @Html.LabelFor(model => model.StudName)
            @Html.EditorFor(model => model.StudName)
            @Html.ValidationMessageFor(model => model.StudName)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.StudId)
            @Html.EditorFor(model => model.StudId)
            @Html.ValidationMessageFor(model => model.StudId)
        </div>
        </div>
       <div class="col-md-6">
        <table  id="container">
            @for (int j = 0; j < Model.Assignments.Count; j++)
            {
            //using editor template to list the assignments 
                 @Html.EditorFor(model => Model.Assignments[j])
            } 
    @*This will [using foreach instead of for ] result a NULL at form submission even without editing or removing any rows 
        @foreach (OpenXMLMvc3.Controllers.Assignment assign in Model.Assignments)
        {
                @Html.EditorFor(model => assign)
        }*@
        </table>
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
}

编辑器模板视图

@model OpenXMLMvc3.Controllers.Assignment
<tr class="editorRow">
<td>
  @Html.HiddenFor(model => Model.Id, new {@class="iHidden" })
  sa
</td>
<td>
    @Html.EditorFor(model => Model.Name)
</td>
<td>
     @Html.EditorFor(model => Model.Amount)
</td>
    <td>
      @Html.EditorFor(model => Model.Remarks)
    </td>
    <td>
   <a href="#" class="deleteRow">delete</a>
   </td>
 </tr>  

那么我如何允许用户从集合中删除项目通过编辑模板在MVC3

如果Editortemplates项目从视图中删除,MVC表单提交返回null

默认情况下,DefaultModelBinder只绑定从零开始的连续集合。如果删除第一个项(index = 0),则不会绑定任何项。您需要在视图中包含DefaultModelBinder用来匹配非连续索引的特殊隐藏输入。不幸的是,在这种情况下,您将无法使用EditorTemplate,相反,您需要在主视图内使用for循环(但作为替代,您可以使用BeginCollectionItem helper作为使用for循环的选项)。

将主视图更改为

<table  id="container">
  @for (int j = 0; j < Model.Assignments.Count; j++)
  {
    <tr class="editorRow">
      <td>
        @Html.HiddenFor(m => m.Assignments[j].Id, new {@class="iHidden" })
        sa
        <input type="hidden" name="Assignments.Index" value="@j" /> // add this
      </td>
      <td>@Html.EditorFor(m => m.Assignments[j].Name)</td>
      <td>@Html.EditorFor(m => m.Assignments[j].Amount)</td>
      <td>@Html.EditorFor(m => m.Assignments[j].Remarks)</td>
      <td><a href="#" class="deleteRow">delete</a></td>
    </tr>
  }
</table>

旁注:EditorFor()接受IEnumerable<T>,所以在你之前的尝试中正确的用法应该只是

<table  id="container">
  @Html.EditorFor(model => Model.Assignments)
</table>

。不是在循环中- EditorFor()方法足够聪明,可以根据模板

为集合中的每个项目生成正确的html

另外,我建议不要使用model => Model.XXX(大写'M')。它可以在某些条件下抛出异常(在任何情况下,只使用m => m.XXX都更简单)

还请注意上面提到的BeginCollectionItem helper只是自动添加了这个隐藏的输入,并将基于0的索引器更改为Guid,因此生成的html是

<input type="hidden" name="Assignments[aaaef973-d8ce-4c92-95b4-3635bb2d42d5].ID" .... />
<input type="hidden" name="Assignments.Index" value="aaaef973-d8ce-4c92-95b4-3635bb2d42d5" />

但是如果你在视图中动态地向集合中添加新项

我使用编辑器模板添加和删除选项,对于每个操作,我只是使用Ajax将集合返回到服务器,添加/删除集合,使用编辑器模板重新呈现,然后替换HTML。

这种方法维护集合的索引,并确保模型绑定仍然有效。

只是上述答案的另一种选择,可能对某人有用。