MVC 4列表模型绑定是如何工作的
本文关键字:工作 何工作 列表 模型 绑定 MVC | 更新日期: 2023-09-27 17:58:47
如果我希望表单中的一组输入绑定到MVC 4中的List
,我知道input
name
属性的以下命名约定将起作用:
<input name="[0].Id" type="text" />
<input name="[1].Id" type="text" />
<input name="[2].Id" type="text" />
但我很好奇模型活页夹有多宽容。例如,以下内容如何:
<input name="[0].Id" type="text" />
<input name="[3].Id" type="text" />
<input name="[8].Id" type="text" />
模型活页夹将如何处理?它会绑定到长度为9且为null的List
吗?或者它还会与长度为3的List
结合吗?还是会完全窒息?
我为什么在乎
我想实现一个动态表单,在这个表单中,用户可以向表单中添加行,也可以从表单中删除行。因此,如果我是一个用户,删除了总共8行中的第2行,我想知道是否需要对所有后续输入重新编号。
有一种特定的有线格式可用于集合。Scott Hanselman的博客上对此进行了讨论:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
Phil Haack的另一篇博客文章在这里谈到了这一点:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
最后,一个博客条目,在这里做你想要的事情:
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
我遵循了上面博客中链接的方法,并添加了一些可能对某些人有帮助的细节,尤其是当我想动态添加任意数量的行,但不想使用AJAX时(我希望表单只在帖子中提交)。我也不想担心维护顺序id。我正在捕捉开始和结束日期的列表:
视图模型:
public class WhenViewModel : BaseViewModel {
public List<DateViewModel> Dates { get; set; }
//... Other properties
}
开始/结束日期视图模型:
public class DateViewModel {
public string DateID { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
然后在页面中使用它们(带日期选择器):
<div class="grid-8-12 clear" id="DatesBlock">
@{
foreach (DateViewModel d in Model.Dates) {
@:<div class="grid-5-12 left clear">
@Html.Hidden("Dates.Index", d.DateID)
@Html.Hidden("Dates[" + d.DateID + "].DateID", d.DateID) //ID again to populate the view model
@Html.TextBox("Dates[" + d.DateID + "].StartDate",
d.StartDate.Value.ToString("yyyy-MM-dd"))
@:</div>
@:<div class="grid-5-12">
@Html.TextBox("Dates[" + d.DateID + "].EndDate",
d.EndDate.Value.ToString("yyyy-MM-dd"))
@:</div>
<script type="text/javascript">
$('input[name="Dates[@d.DateID].StartDate"]')
.datepicker({ dateFormat: 'yy-mm-dd'});
$('input[name="Dates[@d.DateID].EndDate"]')
.datepicker({dateFormat: 'yy-mm-dd'});
</script>
}
}
</div>
<a href="#" onclick="AddDatesRow()">Add Dates</a>
正如上面@ErikTheVikings帖子中链接的博客文章所描述的,集合是由重复的隐藏元素创建的:页面上集合中的每个条目都有@Html.Hidden("Dates.Index", d.DateID)
。
我想在不使用AJAX将数据发布回服务器的情况下任意添加行,这是我通过创建一个隐藏的div来实现的,该div包含集合中一个"行"/项的模板:
隐藏的"模板"行:
<div id="RowTemplate" style="display: none">
<div class="grid-5-12 clear">
@Html.Hidden("Dates.Index", "REPLACE_ID")
@Html.Hidden("Dates[REPLACE_ID].DateID", "REPLACE_ID")
@Html.TextBox("Dates[REPLACE_ID].StartDate", "")
</div>
<div class="grid-5-12">
@Html.TextBox("Dates[REPLACE_ID].EndDate", "")
</div>
</div>
然后使用jQuery,它克隆模板,提供一个用于新行的随机id,并将现在可见的克隆行附加到上面包含的div:
jQuery完成流程:
<script type="text/javascript">
function AddDatesRow() {
var tempIndex = Math.random().toString(36).substr(2, 5);
var template = $('#RowTemplate');
var insertRow = template.clone(false);
insertRow.find('input').each(function(){ //Run replace on each input
this.id = this.id.replace('REPLACE_ID', tempIndex);
this.name = this.name.replace('REPLACE_ID', tempIndex);
this.value = this.value.replace('REPLACE_ID', tempIndex);
});
insertRow.show();
$('#DatesBlock').append(insertRow.contents());
//Attach datepicker to new elements
$('input[name="Dates['+tempIndex+'].StartDate"]')
.datepicker({dateFormat: 'yy-mm-dd' });
$('input[name="Dates['+tempIndex+'].EndDate"]')
.datepicker({dateFormat: 'yy-mm-dd' });
}
</script>
JSFiddle结果示例:http://jsfiddle.net/mdares/7JZh4/
我有一个动态列表,如下所示:
<ul id="okvedList" class="unstyled span8 editableList">
<li>
<input data-val="true" data-val-required="The Guid field is required." id="Okveds_0__Guid" name="Okveds[0].Guid" type="hidden" value="2627d99a-1fcd-438e-8109-5705dd0ac7bb">
--//--
</li>
所以当我添加或删除行(li元素)时,我必须重新排序项目
this.reorderItems = function () {
var li = this.el_list.find('li');
for (var i = 0; i < li.length; i++) {
var inputs = $(li[i]).find('input');
$.each(inputs, function () {
var input = $(this);
var name = input.attr('name');
input.attr('name', name.replace(new RegExp("''[.*'']", 'gi'), '[' + i + ']'));
var id = input.attr('id');
input.attr('id', id.replace(new RegExp('_.*__', 'i'), '_' + i + '__'));
});
}
};
该列表从客户端放入简单的Html.BeginFrom中,类似于服务器端上的list in action参数
我过去也遇到过类似的问题,我使用KnockoutJS来处理这种情况。
基本上,Knockout以JSON字符串发送集合,我在控制器中对它们进行反序列化。
有关更多信息:http://learn.knockoutjs.com/#/?tutorial=collections
当我使用Chrome浏览器并单击后退按钮时,我遇到了一个小问题,当Chrome浏览器没有正确处理动态设置的值时,我发现type="hidden"的输入。
也许我们可以改变
<input type="hidden" name="Detes.Index" value="2016/01/06" />
至
<div style="display: none">
<input type="text" name="Detes.Index" value="2016/01/06" />
</div>
表单详细信息:Chrome没有';t缓存隐藏的表单字段值以在浏览器历史记录中使用http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/