提交相同的部分视图多次调用数据给控制器

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>



Answer 1 Community


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

所述 DefaultModelBinder 要求用于集合项索引从零开始并且是连续的,或者说,表格值包括 Index=someValue ,其中该索引是 someValue 中(例如 <input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC"> 。这在Phil Haack的文章Model Binding to A List中有详细说明。使用Index方法通常更好,因为它还允许您从列表中删除项目(否则可以需要重命名所有现有控件,以便索引器是连续的)。

对于你的问题,有两种可能的方法。

选项1

对您的局部视图使用BeginItemCollection帮助器。该帮助程序将基于GUID 为 Index 值呈现隐藏的输入。在局部视图和渲染现有项目的循环中都需要使用它。您的部分看起来像

@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>
  ....
}

选项2

使用“假”索引器手动创建表示新对象的html元素,将它们放置在隐藏的容器中,然后在“添加”按钮事件中克隆html,更新索引器和Index值,并将克隆的元素附加到DOM。为确保html正确,请在 for 循环中创建一个默认对象,然后检查它生成的html。此答案显示了此方法的一个示例

<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 会忽略它们)

$('#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());
}

选项1的优点是,你可以将视图输入到模型中,但这意味着每次添加一个新的项目时都要调用服务器。选项2的好处是,它是在客户端完成的,但如果你对模型做了任何修改(例如,在属性中添加一个验证属性),那么你还需要手动更新html,这使得维护起来有点困难。

最后,如果您正在使用客户端验证(jquery-validate-unobtrusive.js),则每次将新元素添加到DOM时都需要重新解析验证器,如本答案所述

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

当然,你还需要改变你的POST方法来接受一个集合。

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