C# MVC 4 列表模型绑定如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14822615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does MVC 4 List Model Binding work?
提问by Eric
If I want a set of inputs in a form to bind to a List
in MVC 4, I know that the following naming convention for input
name
attributes will work:
如果我希望表单中的一组输入绑定到List
MVC 4 中的 a,我知道以下input
name
属性命名约定将起作用:
<input name="[0].Id" type="text" />
<input name="[1].Id" type="text" />
<input name="[2].Id" type="text" />
But I am curious about how forgiving the model binder is. For example, what about the following:
但我很好奇模型活页夹的宽容度。例如,以下情况如何:
<input name="[0].Id" type="text" />
<input name="[3].Id" type="text" />
<input name="[8].Id" type="text" />
How would the model binder handle this? Would it bind to a List
of length 9 with nulls? Or would it still bind to a List
of length 3? Or would it choke altogether?
模型活页夹将如何处理这个问题?它会绑定到List
长度为 9 的空值吗?或者它仍然会绑定到List
长度为 3 的 a 吗?还是会完全窒息?
Why I care
我为什么关心
I want to implement a dynamic form in which the user may add rows to the form, and also may delete rows from the form. So if I a user deletes row 2 out of 8 total rows, I want to know if I'll need to renumber all of the subsequent inputs.
我想实现一个动态表单,用户可以在其中向表单添加行,也可以从表单中删除行。因此,如果我的用户删除了 8 行中的第 2 行,我想知道是否需要对所有后续输入重新编号。
采纳答案by Erik Funkenbusch
There is a specific wire format for use with collections. This is discussed on Scott Hanselman's blog here:
有一种用于集合的特定连线格式。这在 Scott Hanselman 的博客上有讨论:
Another blog entry from Phil Haack talks about this here:
Phil Haack 的另一篇博客文章在这里谈到了这一点:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Finally, a blog entry that does exactly what you want here:
最后,一个博客条目完全符合您的要求:
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
回答by Evgeny Popov
I have dynamic list that looks like this:
我有如下所示的动态列表:
<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>
so when I add or remove the row (li element) i have to reorder items
所以当我添加或删除行(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 + '__'));
});
}
};
this list placed into simple Html.BeginFrom from clientside and like List in action parameter on serverside
这个列表从客户端放入简单的 Html.BeginFrom 中,就像服务器端的动作参数列表一样
回答by andri
I also facing similar problem in the past, and I use KnockoutJS to handle such scenario.
我过去也遇到过类似的问题,我使用 KnockoutJS 来处理这种情况。
Basically, Knockout send the collection in a JSON string, and I deserialized them in my controller.
基本上,Knockout 以 JSON 字符串形式发送集合,然后我在控制器中对它们进行反序列化。
For more info : http://learn.knockoutjs.com/#/?tutorial=collections
欲了解更多信息:http: //learn.knockoutjs.com/#/?tutorial=collections
回答by Matthew
I followed this approach linked in the blogs above and added a few details that might be helpful to some - especially as I wanted to dynamically add any number of rows but did not want to use AJAX to do so (I wanted the form to only submit in the post). I also did not want to worry about maintaining sequential ids. I was capturing a list of start and end dates:
我遵循了上面博客中链接的这种方法,并添加了一些可能对某些人有用的细节 - 特别是当我想动态添加任意数量的行但不想使用 AJAX 这样做时(我希望表单只提交在文中)。我也不想担心维护顺序 ID。我正在捕获开始和结束日期的列表:
View Model:
查看型号:
public class WhenViewModel : BaseViewModel {
public List<DateViewModel> Dates { get; set; }
//... Other properties
}
Start / End Date View Model:
开始/结束日期视图模型:
public class DateViewModel {
public string DateID { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
Then using them in the page (with datepicker):
然后在页面中使用它们(使用日期选择器):
<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>
As the blog post linked in the @ErikTheVikings post above describe, the collection is created by the repeated hidden element: @Html.Hidden("Dates.Index", d.DateID)
for each entry in the collection on the page.
正如上面@ErikTheVikings 帖子中链接的博客文章所述,集合是由重复的隐藏元素创建的:@Html.Hidden("Dates.Index", d.DateID)
对于页面上集合中的每个条目。
I wanted to arbitrarily add rows without using AJAX to post data back to the server which I did by creating a hidden div containing a template of one "row" / item in the collection:
我想在不使用 AJAX 的情况下任意添加行将数据发回服务器,我通过创建一个隐藏的 div 来完成,该 div 包含集合中一个“行”/项目的模板:
Hidden "Template" row:
隐藏的“模板”行:
<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>
Then used jQuery which clones the template, provides a random id to use for a new row and appends the now visible cloned row to the containing div above:
然后使用 jQuery 克隆模板,提供一个随机 id 用于新行并将现在可见的克隆行附加到上面的包含 div:
jQuery to complete the process:
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 example of the result: http://jsfiddle.net/mdares/7JZh4/
结果的 JSFiddle 示例:http: //jsfiddle.net/mdares/7JZh4/
回答by thomas wu
I got little problem, when i using Chrome Browser and click the back button, and i find the input with type="hidden" when dynamically set values didn't handled properly by the Chrome Browser.
我没有遇到什么问题,当我使用 Chrome 浏览器并单击后退按钮时,当动态设置的值没有被 Chrome 浏览器正确处理时,我找到 type="hidden" 的输入。
maybe we can change
也许我们可以改变
<input type="hidden" name="Detes.Index" value="2016/01/06" />
to
到
<div style="display: none">
<input type="text" name="Detes.Index" value="2016/01/06" />
</div>
Form more info: Chrome doesn't cache hidden form field values for use in browser historyhttp://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
表单更多信息: Chrome 不会缓存隐藏的表单字段值以用于浏览器历史记录http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/