c# - net - Formulario MVC no puede publicar Lista de objetos
mvc send model list to controller (2)
Por favor, lea esto: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Debería establecer indicios para los atributos de "nombre" de elementos html como planCompareViewModel[0].PlanId
, planCompareViewModel[1].PlanId
para hacer que el planCompareViewModel[1].PlanId
pueda analizarlos en IEnumerable.
En lugar de @foreach (var planVM in Model)
use for
bucle y represente nombres con índices.
entonces tengo una aplicación MVC Asp.net que está teniendo problemas. Esencialmente, tengo una vista que contiene un formulario y sus contenidos están vinculados a una lista de objetos. Dentro de este ciclo, carga PartialView con los elementos sobre los que se realiza el bucle. Ahora todo funciona hasta la presentación del formulario. Cuando se envía, el controlador recibe una lista nula de objetos. El código a continuación demuestra los problemas.
Vista de padres:
@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new { id = "compareForm" }))
{
<div>
@foreach (var planVM in Model)
{
@Html.Partial("_partialView", planVM)
}
</div>
}
_vista parcial:
@model PlanCompareViewModel
<div>
@Html.HiddenFor(p => p.PlanID)
@Html.HiddenFor(p => p.CurrentPlan)
@Html.CheckBoxFor(p => p.ShouldCompare)
<input type="submit" value="Compare"/>
</div>
Y estas son las clases para el código anterior:
PlanViewModel:
public class PlansCompareViewModel
{
public int PlanID { get; set; }
public Plan CurrentPlan { get; set; }
public bool ShouldCompare { get; set; }
public PlansCompareViewModel(Plan plan)
{
ShouldCompare = false;
PlanID = plan.PlanId;
CurrentPlan = plan;
}
public PlansCompareViewModel()
{
// TODO: Complete member initialization
}
public static IEnumerable<PlansCompareViewModel> CreatePlansVM(IEnumerable<Plan> plans)
{
return plans.Select(p => new PlansCompareViewModel(p)).AsEnumerable();
}
}
Controlador:
public class PlansController : MyBaseController
{
[HttpPost]
public ActionResult ComparePlans(IEnumerable<PlanCompareViewModel> model)
{
//the model passed into here is NULL
}
}
Y el problema está en la acción del controlador. Hasta donde yo sé, debería publicar una lista enumerable de PlanCompareViewModels, pero es nulo. Cuando se inspeccionan los datos de la publicación que se envían, se envían los parámetros correctos. Y si tuviera que cambiar ''IEnumerable'' a ''FormCollection'', contiene los valores correctos. ¿Alguien puede ver por qué la carpeta no está creando el objeto correcto? Puedo evitar esto usando javascript, ¡pero eso frustra el propósito! ¡Cualquier ayuda sería muy apreciada!
Su modelo es null
porque la forma en que está suministrando las entradas a su formulario significa que el encuadernador modelo no tiene manera de distinguir entre los elementos. En este momento, este código:
@foreach (var planVM in Model)
{
@Html.Partial("_partialView", planVM)
}
no está suministrando ningún tipo de índice a esos artículos. Por lo tanto, genera repetidamente resultados HTML como este:
<input type="hidden" name="yourmodelprefix.PlanID" />
<input type="hidden" name="yourmodelprefix.CurrentPlan" />
<input type="checkbox" name="yourmodelprefix.ShouldCompare" />
Sin embargo, como quiere enlazar a una colección, necesita que los elementos de su formulario se nombren con un índice, como por ejemplo:
<input type="hidden" name="yourmodelprefix[0].PlanID" />
<input type="hidden" name="yourmodelprefix[0].CurrentPlan" />
<input type="checkbox" name="yourmodelprefix[0].ShouldCompare" />
<input type="hidden" name="yourmodelprefix[1].PlanID" />
<input type="hidden" name="yourmodelprefix[1].CurrentPlan" />
<input type="checkbox" name="yourmodelprefix[1].ShouldCompare" />
Ese índice es lo que permite que el archivador de modelos asocie las piezas de datos por separado, lo que le permite construir el modelo correcto. Así que esto es lo que sugiero que hagas para solucionarlo. En lugar de pasar por encima de su colección, utilizando una vista parcial, aproveche el poder de las plantillas en su lugar. Estos son los pasos que debe seguir:
- Cree una carpeta
EditorTemplates
dentro de la carpeta actual de su vista (por ejemplo, si su vista esHome/Index.cshtml
, cree la carpetaHome/EditorTemplates
). - Cree una vista fuertemente tipada en ese directorio con el nombre que coincida con su modelo. En su caso, eso sería
PlanCompareViewModel.cshtml
.
Ahora, todo lo que tienes en tu vista parcial quiere ir en esa plantilla:
@model PlanCompareViewModel
<div>
@Html.HiddenFor(p => p.PlanID)
@Html.HiddenFor(p => p.CurrentPlan)
@Html.CheckBoxFor(p => p.ShouldCompare)
<input type="submit" value="Compare"/>
</div>
Finalmente, su vista principal se simplifica a esto:
@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new { id = "compareForm" }))
{
<div>
@Html.EditorForModel()
</div>
}
DisplayTemplates
y EditorTemplates
son lo suficientemente inteligentes como para saber cuándo están manejando colecciones. Eso significa que generarán automáticamente los nombres correctos, incluidos los índices, para los elementos de su formulario, de forma que pueda vincular correctamente el modelo a una colección.