同じパーシャルビューを複数回呼び出してコントローラにデータを送信する

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" ..> (これもあるため、重複の無効なHTMLを作成している id 、彼らがする必要があるとして、どこ属性) <input name="[0].productTotalQuantity" ..><input name="[1].productTotalQuantity" ..> など。ポストバック時にコレクションにバインドします。

DefaultModelBinder は、コレクションアイテムのインデクサがゼロで開始し、連続して、またはフォームの値が含まれていることことが必要 Index=someValue インデクサは someValue の(例えば <input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC"> 。これは、Phil Haackの記事「リストへのモデルのバインド」で詳細に説明されています。リストから項目を削除することもできるので、インデックスアプローチを使用する方が一般に優れています(そうしないと、インデクサーが連続するように、すべての既存のコントロールの名前を変更する必要があります)。

あなたの問題に対する2つの可能なアプローチ。

オプション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を複製し、インデクサーとインデックス値を更新して、複製した要素をDOMに追加します。htmlが正しいことを確認するには、 for ループで1つのデフォルトオブジェクトを作成し、それが生成する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 にバインドされるのを防ぐために「偽の」インデクサーを使用していることに注意してください(「#」と「%」は一致しないため、これらは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)
{
  ....
}