提交相同的局部视图多次调用数据控制器? [英] Submit same Partial View called multiple times data to controller?

查看:102
本文介绍了提交相同的局部视图多次调用数据控制器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在视图中添加一个按钮。当点击这个按钮的局部视图加。在我的形式,我可以,我可以添加尽可能多的局部视图。当提交此表的数据我不能所有的局部视图数据发送到控制器。
我已经由具有所有属性不同的模式,我已经提出,模型的列表,我的主要模式。任何人都可以请给我一些诀窍,这样我可以把所有的局部视图内容,我的控制器?

在我看来

 < D​​IV ID =CSQGroup>
< / DIV>
< D​​IV>
  <输入类型=按钮值=添加域ID =激活addField的onclick =addFieldss()/>
< / DIV>功能addFieldss()
{
  $阿贾克斯({
    网址:'@ Url.Content(〜/ AdminProduct / GetColorSizeQty)',
    输入:GET,
    成功:函数(结果){
      VAR newDiv = $(使用document.createElement(格))ATTR(ID,CSQ'+ myCounter)。
      newDiv.html(结果);
      newDiv.appendTo(#CSQGroup);
      myCounter ++;
    },
    错误:功能(结果){
      警报(失败);
    }
  });
}

在我的控制器

 公众的ActionResult GetColorSizeQty()
{
  VAR数据=新AdminProductDetailModel();
  data.colorList = commonCore.getallTypeofList(颜色);
  data.sizeList = commonCore.getallTypeofList(大小);
  返回PartialView(数据);
}[HttpPost]
公众的ActionResult AddDetail(AdminProductDetailModel模型)
{
  ....
}

在我的局部视图

  @model IKLE.Model.ProductModel.AdminProductDetailModel
< D​​IV CLASS =主编场>
  @ Html.LabelFor(型号=> model.fkConfigChoiceCategorySizeId)
  @ Html.DropDownListFor(型号=> model.fkConfigChoiceCategorySizeId,Model.sizeList - 选择Size--)
  @ Html.ValidationMessageFor(型号=> model.fkConfigChoiceCategorySizeId)
< / DIV>
< D​​IV CLASS =主编场>
  @ Html.LabelFor(型号=> model.fkConfigChoiceCategoryColorId)
  @ Html.DropDownListFor(型号=> model.fkConfigChoiceCategoryColorId,Model.colorList - 选择Color--)
  @ Html.ValidationMessageFor(型号=> model.fkConfigChoiceCategoryColorId)
< / DIV>
< D​​IV CLASS =主编场>
  @ Html.LabelFor(型号=> model.productTotalQuantity)
  @ Html.TextBoxFor(型号=> model.productTotalQuantity)
  @ Html.ValidationMessageFor(型号=> model.productTotalQuantity)
< / DIV>


解决方案

您的问题是,基于一个 AdminProductDetailModel 对象的部分呈现HTML,但你想回来后集合。当您动态地添加一个新的对象,你继续增加,看起来像重复控制<输入名称=productTotalQuantity..> (这也创造因为无效的HTML重复 ID 属性)在那里,因为他们需要为<输入名称=[0] .productTotalQuantity..> <输入名称=[1] .productTotalQuantity..方式> 等,以绑定到一个集合上回发

DefaultModelBinder 要求收集项目索引从零开始,并是连续的,或者表单值包括指数= someValue中其中,索引为 someValue中(例如<输入名称=[ABC] .productTotalQuantity..><输入名字=索引值=ABC方式> 这是中详细菲尔哈克的文章介绍的Model绑定到一个列表。使用索引方法通常更好,因为它也可以让你从列表中删除项目(否则有必要重命名所有现有的控件,以便索引是一些连续的)。

两种可能的方法,以您的问题。

选项1

使用 BeginItemCollection 帮手您的局部视图。该助手将基于一个GUID呈现为指数隐藏输入值。您需要这两个局部视图并在您呈现现有项目的循环。你的局部看起来像

  @model IKLE.Model.ProductModel.AdminProductDetailModel
@using(Html.BeginCollectionItem())
{
  < D​​IV CLASS =主编场>
    @ Html.LabelFor(型号=> model.fkConfigChoiceCategorySizeId)
    @ Html.DropDownListFor(型号=> model.fkConfigChoiceCategorySizeId,Model.sizeList - 选择Size--)
    @ Html.ValidationMessageFor(型号=> model.fkConfigChoiceCategorySizeId)
  < / DIV>
  ....
}

选项2

手动创建HTML元素重新presenting一个新的对象以'假'索引,将它们放置在一个隐藏的容器,然后在添加按钮事件,克隆HTML,更新索引和索引值,并追加克隆元素到DOM。为了确保HTML是正确的,创建循环在一个默认对象,并检查其生成的HTML。这种方法的一个例子在<一个示href=\"http://stackoverflow.com/questions/24026374/adding-another-pet-to-a-model-form/24027152#24027152\">this回答

 &LT; D​​IV ID =的newitem的风格=显示:无&GT;  &LT; D​​IV CLASS =主编场&GT;
    &LT;标签=_#__ productTotalQuantity&GT;及数量LT; /标签&gt;
    &LT;输入类型=文本ID =_#__ productTotalQuantityNAME =[#] productTotalQuantity值/&GT;
    ....
  &LT; / DIV&GT;
  //更多模型的性能
&LT; / DIV&GT;

请注意使用了假索引器prevent上后这一个被绑定背部('#'和'%'的不会匹配,使他们由 DefaultModelBinder

  $('#激活addField')。点击(函数(){
  。VAR指数=(新的Date())的getTime();
  。VAR克隆= $('#的newitem')的clone();
  //更新克隆的索引和索引值
  clone.html($(克隆)的.html()取代(/ \\ [#\\] /克,'['+指数+']'));
  clone.html($(克隆)的.html()代替(/%/克,'+指数+''));
  $('#您的容器')追加(clone.html())。
}

选项1的优势在于,我们强烈键入视图模型,但它意味着使每次添加新项目时对服务器的呼叫。选项​​2的优势是它的全部完成客户端,但如果你对你的模型的任何更改(例如,添加一个验证属性的属性),那么你还需要手动更新HTML,使得维护有点困难。

最后,如果您使用的是客户端验证(jQuery的 - 验证 - unobtrusive.js),那么你需要重新解析每次添加新的元素到DOM时间验证作为解释<一个href=\"http://stackoverflow.com/questions/26542509/validate-dynamically-added-fields/26542591#26542591\">this回答。

  $('形式')的数据('验证',NULL);
$ .validator.unobtrusive.parse($('形式'));

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

  [HttpPost]
公众的ActionResult AddDetail(IEnumerable的&LT; AdminProductDetailModel&GT;模型)
{
  ....
}

I have added a button in my view. When this button is clicked partial view is added. In my form I can add as much partial view as I can. When Submitting this form data I am unable to send all the partial view data to controller. I have made a different model having all the attributes and I have made a list of that model to my main model. Can anyone please give me some trick so that I can send all the partial view content to my controller?

In My View

<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");
    }
  });
}

In My controller

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)
{
  ....
}

In my Partial View

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

解决方案

Your problem is that the partial renders html based on a single AdminProductDetailModel object, yet you are trying to post back a collection. When you dynamically add a new object you continue to add duplicate controls that look like <input name="productTotalQuantity" ..> (this is also creating invalid html because of the duplicate id attributes) where as they need to be <input name="[0].productTotalQuantity" ..>, <input name="[1].productTotalQuantity" ..> etc. in order to bind to a collection on post back.

The DefaultModelBinder required that the indexer for collection items start at zero and be consecutive, or that the form values include a Index=someValue where the indexer is someValue (for example <input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC">. This is explained in detail in Phil Haack's article Model Binding To A List. Using the Index approach is generally better because it also allows you to delete items from the list (otherwise it would be necessary to rename all existing controls so the indexer is consecutive).

Two possible approaches to your issue.

Option 1

Use the BeginItemCollection helper for your partial view. This helper will render a hidden input for the Index value based on a GUID. You need this in both the partial view and the loop where you render existing items. Your partial would look something like

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

Option 2

Manually create the html elements representing a new object with a 'fake' indexer, place them in a hidden container, then in the Add button event, clone the html, update the indexers and Index value and append the cloned elements to the DOM. To make sure the html is correct, create one default object in a for loop and inspect the html it generates. An example of this approach is shown in this answer

<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>

Note the use of a 'fake' indexer to prevent this one being bound on post back ('#' and '%' wont match up so they are ignored by the 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());
}

The advantage of option 1 is that you are strongly typing the view to your model, but it means making a call to the server each time you add a new item. The advantage of option 2 is that its all done client side, but if you make any changes to you model (e.g. add a validation attribute to a property) then you also need to manually update the html, making maintenance a bit harder.

Finally, if you are using client side validation (jquery-validate-unobtrusive.js), then you need re-parse the validator each time you add new elements to the DOM as explained in this answer.

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

And of course you need to change you POST method to accept a collection

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

这篇关于提交相同的局部视图多次调用数据控制器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆