Presentar la misma vista parcial llamada datos de múltiples veces al controlador

asp.net-mvc-4


He añadido un botón en mi vista.Cuando se hace clic en este botón se añade una vista parcial.En mi formulario puedo añadir tanta vista parcial como pueda.Al enviar los datos de este formulario no puedo enviar todos los datos de la vista parcial al controlador.He hecho un modelo diferente que tiene todos los atributos y he hecho una lista de ese modelo a mi modelo principal.¿Alguien puede darme algún truco para que pueda enviar todo el contenido de la vista parcial a mi controlador?

En mi opinión

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

En mi controlador

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

En mi vista parcial

@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


Su problema es que el html de renderizado parcial se basa en un solo objeto AdminProductDetailModel , pero está intentando publicar una colección. Cuando agrega dinámicamente un nuevo objeto, continúa agregando controles duplicados que se parecen a <input name="productTotalQuantity" ..> (esto también está creando html no válido debido a los atributos de id entificación duplicados ) donde, como deben ser, <input name="[0].productTotalQuantity" ..> , <input name="[1].productTotalQuantity" ..> etc. para enlazar a una colección en la publicación posterior.

El DefaultModelBinder requiere que el indexador para los artículos de colección se inicia en cero y ser consecutivos, o que los valores del formulario incluye un Index=someValue donde el indexador es someValue (por ejemplo, <input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC"> . Esto se explica en detalle en el artículo de Phil Haack Enlace de modelo a una lista . Usar el enfoque de índice es generalmente mejor porque también le permite eliminar elementos de la lista (de lo contrario, sería necesario cambiar el nombre de todos los controles existentes para que el indexador sea consecutivo).

Dos posibles enfoques de su problema.

Opción 1

Use el ayudante BeginItemCollection para su vista parcial. Este asistente representará una entrada oculta para el valor del Index función de un GUID. Necesita esto tanto en la vista parcial como en el bucle donde representa los elementos existentes. Tu parcial se vería algo así

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

opcion 2

Cree manualmente los elementos html que representan un nuevo objeto con un indexador 'falso', colóquelos en un contenedor oculto, luego en el evento Agregar botón, clone el html, actualice los indexadores y el valor del índice y agregue los elementos clonados al DOM. Para asegurarse de que el html es correcto, cree un objeto predeterminado en un bucle for e inspeccione el html que genera. Un ejemplo de este enfoque se muestra en esta respuesta

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

Tenga en cuenta el uso de un indexador 'falso' para evitar que este se vincule en la publicación posterior ('#' y '%' no coincidirán, por lo que DefaultModelBinder los ignorará )

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

La ventaja de la opción 1 es que estás tecleando fuertemente la vista a tu modelo,pero significa hacer una llamada al servidor cada vez que añades un nuevo elemento.La ventaja de la opción 2 es que ya está todo hecho en el lado del cliente,pero si haces algún cambio en tu modelo (por ejemplo,añadir un atributo de validación a una propiedad)entonces también necesitas actualizar manualmente el html,haciendo el mantenimiento un poco más difícil.

Finalmente, si está utilizando la validación del lado del cliente (jquery-validate-unobtrusive.js), entonces debe volver a analizar el validador cada vez que agregue nuevos elementos al DOM como se explica en esta respuesta .

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

Y por supuesto tienes que cambiar tu método POST para aceptar una colección

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