将多次调用的同一局部视图提交给控制器?

时间:2015-01-19 07:29:54

标签: asp.net-mvc-4

我在视图中添加了一个按钮。单击此按钮时,将添加部分视图。在我的表单中,我可以添加尽可能多的局部视图。提交此表单数据时,我无法将所有部分视图数据发送到控制器。 我创建了一个具有所有属性的不同模型,并且我已经将该模型的列表添加到我的主模型中。任何人都可以给我一些技巧,以便我可以将所有部分视图内容发送给我的控制器吗?

在我的视图中

<div id="CSQGroup">   
</div>
<div>
  <input type="button" value="Add Field" id="addField" onclick="addFieldss()" />
</div>

function addFieldss()
{    
  $.ajax({
    url: '@Url.Content("~/AdminProduct/GetColorSizeQty")',
    type: 'GET',
    success:function(result) {
      var newDiv = $(document.createElement("div")).attr("id", 'CSQ' + myCounter);  
      newDiv.html(result);
      newDiv.appendTo("#CSQGroup");
      myCounter++;
    },
    error: function(result) {
      alert("Failure");
    }
  });
}

在我的控制器中

public ActionResult GetColorSizeQty()
{
  var data = new AdminProductDetailModel();
  data.colorList = commonCore.getallTypeofList("color");
  data.sizeList = commonCore.getallTypeofList("size");
  return PartialView(data);
}

[HttpPost]
public ActionResult AddDetail(AdminProductDetailModel model)
{
  ....
}

在我的部分视图中

@model IKLE.Model.ProductModel.AdminProductDetailModel
<div class="editor-field">
  @Html.LabelFor(model => model.fkConfigChoiceCategorySizeId)
  @Html.DropDownListFor(model => model.fkConfigChoiceCategorySizeId, Model.sizeList, "--Select Size--")
  @Html.ValidationMessageFor(model => model.fkConfigChoiceCategorySizeId)
</div>
<div class="editor-field">
  @Html.LabelFor(model => model.fkConfigChoiceCategoryColorId)
  @Html.DropDownListFor(model => model.fkConfigChoiceCategoryColorId, Model.colorList, "--Select Color--")
  @Html.ValidationMessageFor(model => model.fkConfigChoiceCategoryColorId)
</div>   
<div class="editor-field">
  @Html.LabelFor(model => model.productTotalQuantity)
  @Html.TextBoxFor(model => model.productTotalQuantity)
  @Html.ValidationMessageFor(model => model.productTotalQuantity)
</div>

1 个答案:

答案 0 :(得分:51)

你的问题是部分呈现基于单个AdminProductDetailModel对象的html,但你试图回发一个集合。当您动态添加新对象时,您将继续添加看起来像<input name="productTotalQuantity" ..>的重复控件(由于重复的id属性,这也会创建无效的html),因为它们需要<input name="[0].productTotalQuantity" ..><input name="[1].productTotalQuantity" ..>等,以便在回发后绑定到一个集合。

DefaultModelBinder要求集合项的索引器从零开始并且是连续的,或者表单值包含Index=someValue,其中索引器为someValue(例如{{1} Phil Haack的文章Model Binding To A List对此进行了详细解释。使用索引方法通常更好,因为它还允许您从列表中删除项目(否则有必要重命名所有现有的项目)控制因此索引器是连续的。)

解决问题的两种方法。

选项1

使用BeginItemCollection帮助程序进行部分查看。此帮助程序将根据GUID为<input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC">值呈现隐藏的输入。您需要在局部视图和渲染现有项目的循环中使用它。你的部分看起来像

Index

选项2

使用&#39;假冒&#39;手动创建表示新对象的html元素。 indexer,将它们放在一个隐藏的容器中,然后在Add按钮事件中,克隆html,更新索引器和Index值,并将克隆的元素附加到DOM。要确保html正确,请在@model IKLE.Model.ProductModel.AdminProductDetailModel @using(Html.BeginCollectionItem()) { <div class="editor-field"> @Html.LabelFor(model => model.fkConfigChoiceCategorySizeId) @Html.DropDownListFor(model => model.fkConfigChoiceCategorySizeId, Model.sizeList, "--Select Size--") @Html.ValidationMessageFor(model => model.fkConfigChoiceCategorySizeId) </div> .... } 循环中创建一个默认对象并检查它生成的html。 this answer

中显示了此方法的一个示例
for

请注意使用假冒的&#39;索引器,以防止这一个绑定在回发上(&#39;#&#39;和&#39;%&#39;不会匹配,因此<div id="newItem" style="display:none"> <div class="editor-field"> <label for="_#__productTotalQuantity">Quantity</label> <input type="text" id="_#__productTotalQuantity" name="[#].productTotalQuantity" value /> .... </div> // more properties of your model </div> 会忽略它们)

DefaultModelBinder

选项1的优点是您可以在模型中强烈键入视图,但这意味着每次添加新项目时都会调用服务器。选项2的优点是它全部完成客户端,但如果你对模型进行任何更改(例如向属性添加验证属性),那么你还需要手动更新html,使维护更加困难。

最后,如果您正在使用客户端验证(jquery-validate-unobtrusive.js),那么每次向DOM添加新元素时都需要重新解析验证器,如this answer中所述。

$('#addField').click(function() {
  var index = (new Date()).getTime(); 
  var clone = $('#NewItem').clone();
  // Update the indexer and Index value of the clone
  clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']'));
  clone.html($(clone).html().replace(/"%"/g, '"' + index  + '"'));
  $('#yourContainer').append(clone.html());
}

当然,您需要更改POST方法以接受集合

$('form').data('validator', null);
$.validator.unobtrusive.parse($('form'));