Подтвердить что ты не робот

Форма MVC не может отправлять список объектов

поэтому у меня есть приложение MVC Asp.net, у которого есть проблемы. По сути, у меня есть представление, которое содержит форму, и ее содержимое привязано к списку объектов. Внутри этого цикла он загружает PartialView, когда элементы зацикливаются. Теперь все работает до подачи формы. Когда он отправляется, контроллер отправляется нулевым списком объектов. Приведенный ниже код демонстрирует проблемы.

Родительский просмотр:

@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new { id = "compareForm" }))
{
<div>
    @foreach (var planVM in Model)
    {
        @Html.Partial("_partialView", planVM)
    }
</div>
}

_partialView:

@model PlanCompareViewModel
<div>
    @Html.HiddenFor(p => p.PlanID)
    @Html.HiddenFor(p => p.CurrentPlan)
    @Html.CheckBoxFor(p => p.ShouldCompare)
   <input type="submit" value="Compare"/>
</div>

И это классы для вышеуказанного кода:

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

Контроллер:

public class PlansController : MyBaseController
{
    [HttpPost]
    public ActionResult ComparePlans(IEnumerable<PlanCompareViewModel> model)
    {
         //the model passed into here is NULL
    }
}

И проблема в действии контроллера. Насколько мне известно, он должен публиковать перечислимый список PlanCompareViewModels, но он является нулевым. Когда вы проверяете отправленные данные, они отправляют правильные параметры. И если бы я изменил "IEnumerable" на "FormCollection", он содержит правильные значения. Может ли кто-нибудь понять, почему связующее не создает правильный объект? Я могу обойти это с помощью javascript, но это побеждает цель! Любая помощь будет принята с благодарностью!

4b9b3361

Ответ 1

Ваша модель null, потому что способ ввода входов в вашу форму означает, что связующее устройство модели не имеет возможности различать элементы. Прямо сейчас, этот код:

@foreach (var planVM in Model)
{
    @Html.Partial("_partialView", planVM)
}

не предоставляет какой-либо индекс этим элементам. Поэтому он будет генерировать HTML-вывод следующим образом:

<input type="hidden" name="yourmodelprefix.PlanID" />
<input type="hidden" name="yourmodelprefix.CurrentPlan" />
<input type="checkbox" name="yourmodelprefix.ShouldCompare" />

Однако, поскольку вы хотите привязать к коллекции, вам нужны ваши элементы формы, которые будут называться с индексом, например:

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

Этот индекс - это то, что позволяет привязке модели связывать отдельные фрагменты данных, позволяя ему создавать правильную модель. Итак, вот что я предлагаю вам сделать, чтобы исправить это. Вместо того, чтобы перебирать вашу коллекцию, используя частичный вид, вместо этого используйте силу шаблонов. Вот шаги, которые вам нужно выполнить:

  • Создайте папку EditorTemplates внутри текущей папки просмотра (например, если ваше представление Home\Index.cshtml, создайте папку Home\EditorTemplates).
  • Создайте строго типизированное представление в этом каталоге с именем, которое соответствует вашей модели. В вашем случае это будет PlanCompareViewModel.cshtml.

Теперь все, что у вас есть в частичном представлении, хочет войти в этот шаблон:

@model PlanCompareViewModel
<div>
    @Html.HiddenFor(p => p.PlanID)
    @Html.HiddenFor(p => p.CurrentPlan)
    @Html.CheckBoxFor(p => p.ShouldCompare)
   <input type="submit" value="Compare"/>
</div>

Наконец, ваше родительское представление упрощено:

@model IEnumerable<PlanCompareViewModel>
@using (Html.BeginForm("ComparePlans", "Plans", FormMethod.Post, new { id = "compareForm" }))
{
<div>
    @Html.EditorForModel()
</div>
}

DisplayTemplates и EditorTemplates достаточно умны, чтобы знать, когда они обрабатывают коллекции. Это означает, что они автоматически генерируют правильные имена, включая индексы, для ваших элементов формы, чтобы вы могли корректно привязать модель к коллекции.

Ответ 2

Прочтите следующее: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Вы должны установить атрибуты для ваших атрибутов "name" html-элементов, таких как planCompareViewModel[0].PlanId, planCompareViewModel[1].PlanId, чтобы сделать связующее, способное анализировать их в IEnumerable.
Вместо @foreach (var planVM in Model) используйте for цикл и визуализируйте имена с индексами.