2013-02-11 46 views
54

如果我想要一组输入的形式结合在MVC 4 List,我知道,inputname属性以下命名约定将工作:MVC 4列表模型绑定如何工作?

<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的List,是否为空值?或者它还会绑定到长度为3的List?或者它会完全窒息?

为什么我关心

我想实现一个动态的形式,其中用户可以添加行的形式,也可以从表格中删除行。因此,如果我的用户删除了总共8行中的第2行,我想知道是否需要重新编号所有后续输入。

+1

看看这个:http://stackoverflow.com/questions/ 7807127 /非顺序列表结合 - 不工作。该问题显示了非顺序绑定的语法(并且答案确认了它在MVC2及更高版本中的可用性)。我有时使用过它。至于你原来的问题:如果我记得正确的话,它会失败......但在打乱手动索引,非顺序绑定之前,尝试很容易。 – 2013-02-11 23:11:11

+1

@TimMedora,谢谢 - 非顺序绑定是我缺乏的有用的术语。 – Eric 2013-02-11 23:22:28

+4

这个话题令人惊讶的模糊。如果你四处搜索,有关于这个主题的一些好博客,本书将在后面的章节中详细介绍:http://www.amazon.com/Pro-ASP-NET-MVC-3-Framework/dp/1430234040 – 2013-02-11 23:29:14

回答

45

有用于收藏使用特定的有线格式。这是斯科特Hanselman的博客在这里讨论:

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

从菲尔哈克另一个博客条目关于此举行了会谈:

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/

+0

完美,谢谢 – Eric 2013-02-12 15:30:50

+4

@shashwat - 对于开放式问题,答案不可能是肯定答案或否定答案,如何给出肯定答案或否定答案? – 2014-02-27 06:03:52

+1

@AnimalsAreNotOursToEat'MVC 4列表模型绑定如何工作?**是** – Jonesopolis 2015-03-27 19:09:04

3

我有动态列表,看起来像这样:

<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参数一样

1

我在过去也面临类似的问题,我使用KnockoutJS来处理这种情况。

基本上,Knockout发送集合在一个JSON字符串中,并且我在我的控制器中将它们反序列化。

欲了解更多信息:http://learn.knockoutjs.com/#/?tutorial=collections

15

我跟着这个pproach链接到上面的博客中,并添加了一些可能对某些人有用的细节 - 特别是因为我想动态添加任意数量的行但不想使用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 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/

0

我在使用我的Chrome浏览器,然后单击后退按钮, 有小问题,我觉得有型输入= Chrome浏览器无法正确处理动态设置值时“隐藏”。

也许我们可以改变

<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 doesn't cache hidden form field values for use in browser history http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/