【问题标题】:MVC Form Submission returns null if Editortemplates Item deleted from view如果 Editortemplates 项目从视图中删除,MVC 表单提交返回 null
【发布时间】:2015-10-14 14:49:39
【问题描述】:

我正在使用 Editortemplates 显示与表单关联的项目列表,如果不需要,我允许用户删除行 但是,当用户在删除 POST 操作中的任何行后提交表单时,我将集合设为 null,如果用户没有删除任何项目,我将在 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 从集合中删除项目

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-3 mvc-editor-templates


    【解决方案1】:

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

    将主视图更改为

    <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&lt;T&gt;,因此您之前尝试的正确用法应该只是

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

    即不在循环中 - EditorFor() 方法足够聪明,可以根据模板为集合中的每个项目生成正确的 html

    另外,我建议不要使用model =&gt; Model.XXX(大写“M”)。它可以在某些情况下抛出异常(并且在任何情况下使用起来更简单 m =&gt; m.XXX

    还要注意上面提到的 BeginCollectionItem 帮助器只是自动添加这个隐藏的输入并将基于零的索引器更改为 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" />
    

    但是,如果您还动态地将新项目添加到视图中的集合中,它就会出现

    【讨论】:

    • 是的,我也必须支持添加新项目的选项 :) 所以建议使用 BeginCollectionItem 助手?
    • 使用BeginCollectionItem 意味着每次你想添加一个新项目时,你需要使用ajax 来调用一个返回部分视图(即以前的编辑器模板)的方法,这意味着一个次要的性能打。一个纯客户端选项显示在答案herehere
    • 客户端选项显然提供了更好的性能,但维护起来有点困难(如果您更改了属性名称,或者添加了一个甚至更改了验证属性,您还需要更新 html 模板中的查看)
    • 另请参阅this article 以了解BeginCollectionItem() 方法的用法
    • 基于所有这些博客文章的完整教程对理解和解决 pblm 有很大帮助justmycode.blogspot.in/2012/07/…
    【解决方案2】:

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

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

    只是上述答案的替代方案,可能对某人有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-21
      • 2016-09-12
      • 1970-01-01
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多