asp.net mvc 4 - ventana - ¿Enviar la misma vista parcial llamada datos múltiples veces al controlador?
vista parcial en modal mvc (1)
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
duplicados) donde deben ser
<input name="[0].productTotalQuantity" ..>
,
<input name="[1].productTotalQuantity" ..>
etc. para enlazar a una colección en la publicación posterior.
DefaultModelBinder
requiere que el indexador para los elementos de la colección comience en cero y sea consecutivo, o que los valores del formulario incluyan 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
. El uso del 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 para 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
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());
}
La ventaja de la opción 1 es que está escribiendo fuertemente la vista en su modelo, pero significa hacer una llamada al servidor cada vez que agrega un nuevo elemento. La ventaja de la opción 2 es que todo está hecho del lado del cliente, pero si realiza algún cambio en su modelo (por ejemplo, agrega un atributo de validación a una propiedad), también necesita actualizar manualmente el html, lo que hace que el mantenimiento sea 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, debe cambiar su método POST para aceptar una colección
[HttpPost]
public ActionResult AddDetail(IEnumerable<AdminProductDetailModel> model)
{
....
}
He agregado un botón en mi vista. Cuando se hace clic en este botón, se agrega una vista parcial. En mi forma, puedo agregar 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 para 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 vista
<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>