【发布时间】:2017-04-02 13:51:54
【问题描述】:
根据 Scott Hanselman 关于ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries 的复杂性的开创性文章:
我们通过查找
parameterName[index].PropertyName
来读取属性 索引必须从零开始且完整
所以这个 HTML:
<input type="text" name="People[0].FirstName" value="George" />
<input type="text" name="People[1].FirstName" value="Abraham" />
<input type="text" name="People[2].FirstName" value="Thomas" />
会像这样发布:
但是,如果我通过 AJAX 将一个新人加载到我的模型中,我会丢失将该人构建到模型中的上下文并获得以下输出:
<input type="text" name="FirstName" value="New" />
模型绑定器不会拾取它。
问:如何在通过 AJAX 动态添加新元素时保留表达式树?
这是一个 MVCE
型号:/Model/Person.cs
public class PersonViewModel
{
public List<Person> People { get; set; }
}
public class Person
{
public String FirstName { get; set; }
public String LastName { get; set; }
}
控制器:Controllers/PersonController.cs
[HttpGet]
public ActionResult Index()
{
List<Person> people = new List<Person> {
new Person { FirstName = "George" , LastName = "Washington"},
new Person { FirstName = "Abraham" , LastName = "Lincoln"},
new Person { FirstName = "Thomas" , LastName = "Jefferson"},
};
PersonViewModel model = new PersonViewModel() {People = people};
return View(model);
}
[HttpPost]
public ActionResult Index(PersonViewModel model)
{
return View(model);
}
public ActionResult AddPerson(String first, String last)
{
Person newPerson = new Person { FirstName = first, LastName = last };
return PartialView("~/Views/Person/EditorTemplates/Person.cshtml", newPerson);
}
查看:Views/Person/Index.cshtml
@model PersonViewModel
@using (Html.BeginForm()) {
<table id="table">
<thead>
<tr>
<th>@Html.DisplayNameFor(model => model.People.First().FirstName)</th>
<th>@Html.DisplayNameFor(model => model.People.First().LastName)</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.People.Count; i++)
{
@Html.EditorFor(model => model.People[i])
}
</tbody>
</table>
<input type="button" value="Add Person" id="add"/>
<input type="submit" value="Save" />
}
<script type="text/javascript">
$("#add").click(function() {
var url = "@Url.Action("AddPerson")?" + $.param({ first: "", last: "" });
$.ajax({
type: "GET",
url: url,
success: function(data) {
$("#table tbody").append(data);
}
});
});
</script>
查看:Views/Person/EditorTemplates/Person.cshtml
@model Person
<tr>
<td>@Html.EditorFor(model => model.FirstName)</td>
<td>@Html.EditorFor(model => model.LastName)</td>
</tr>
注意:删除我不希望在此处解决的项目时还有其他复杂性。我只想添加一个元素并知道它与其他属性一起属于嵌套上下文。
【问题讨论】:
-
MVC 的助手非常棒,直到您开始使用集合做更高级的事情 - 一旦达到这一点,您最好自己控制标记生成。在 DOM 中的某处粘贴一个计数并在您的 JS 中获取它,然后您可以在添加新项目时手动构建(模型绑定)标记。
-
如果您想在视图中动态添加(和删除)集合项,请参阅this answer 了解一些选项。旁注-在这种情况下您不能使用
EditorFor(),但正确的用法应该只是@Html.EditorFor(m => model.People)-不在循环内-该方法接受IEnumerable<T>,并将为集合中的每个项目生成正确的html跨度> -
对于使用客户端模板方法的实现,请参阅this DotNetFiddle。有关
BeginCollectionItem()实现的示例,请参阅this answer
标签: c# asp.net asp.net-mvc collections model-binding