MVC Form not able to post List of objects

后端 未结 2 950
暗喜
暗喜 2020-11-22 11:48

so I have an MVC Asp.net app that is having issues. Essentially, I have a View that contains a form, and its contents are bound to a list of objects. Within this loop, it lo

相关标签:
2条回答
  • 2020-11-22 12:08

    Your model is null because the way you're supplying the inputs to your form means the model binder has no way to distinguish between the elements. Right now, this code:

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

    is not supplying any kind of index to those items. So it would repeatedly generate HTML output like this:

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

    However, as you're wanting to bind to a collection, you need your form elements to be named with an index, such as:

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

    That index is what enables the model binder to associate the separate pieces of data, allowing it to construct the correct model. So here's what I'd suggest you do to fix it. Rather than looping over your collection, using a partial view, leverage the power of templates instead. Here's the steps you'd need to follow:

    1. Create an EditorTemplates folder inside your view's current folder (e.g. if your view is Home\Index.cshtml, create the folder Home\EditorTemplates).
    2. Create a strongly-typed view in that directory with the name that matches your model. In your case that would be PlanCompareViewModel.cshtml.

    Now, everything you have in your partial view wants to go in that template:

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

    Finally, your parent view is simplified to this:

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

    DisplayTemplates and EditorTemplates are smart enough to know when they are handling collections. That means they will automatically generate the correct names, including indices, for your form elements so that you can correctly model bind to a collection.

    0 讨论(0)
  • 2020-11-22 12:18

    Please read this: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
    You should set indicies for your html elements "name" attributes like planCompareViewModel[0].PlanId, planCompareViewModel[1].PlanId to make binder able to parse them into IEnumerable.
    Instead of @foreach (var planVM in Model) use for loop and render names with indexes.

    0 讨论(0)
提交回复
热议问题