简体   繁体   中英

MVC4: nested partial-view loses model data

In an MVC4 project im using a partial View thats using a ViewModel and has a GET Form on it. In the Controller action i expect the ViewModel object with some data. When this partial is placed on a normal (.cshtml) View, i recieve the data via the expected ViewModel object in the Controller action. But, When this partial is placed on another partial view , for some reason the ViewModel object in the controller action is empty. When i step through the creation of the HttpGet-form, the passed-in model is not empty, but when the GET controller action is called, the model is.

Anyone know the reason for this? Is this some MVC behavior i don't know about maybe? Thanks!

The Partial:

@model ViewModel
    @if (Model != null)
    {
        using (Html.BeginForm("DoSomething", "Home", FormMethod.Get))
        { 
            @Html.HiddenFor(m => m.Object)            
            <input id="btnSend" type="submit"> 
        }
    }

The Other Partial:

@using OtherViewModel.ViewModel
@Html.Partial("The Partial", Model.ViewModel, ViewData)

The View:

@Html.Partial("_TheOtherPartial", Model.OtherViewModel, new ViewDataDictionary(ViewData) {
                TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "prefix" }
    })

The Controller

[HttpGet]
[AllowAnonymous]
public ActionResult DoSomething(ViewModel data)
{
}

There ore two things you should take under consideration here. The first is try not to put forms inside partial views . If you do that, you might end up with nested forms, which are not supported by the browsers because it's not valid HTML :

<!ELEMENT FORM - - (%block;|SCRIPT)+ -(FORM) -- interactive form -->

-(FORM) construction disallows a nested form.

The second thing is instead of partial views I'd advice you to use editor templates . Take a look here how to use them. Next, as I said before, try to keep the forms outside of your editor templates - use the form in your main view and let editor templates to render distinct parts of your page. It will be less confusing and results in cleaner code.

In your specific example it can look like this:

The main view:

@model MainModel
@using (Html.BeginForm("YourAction", "YourController"))
{ 
    @Html.EditorFor(m => m.OtherViewModel)
    <input id="btnSend" type="submit"> 
}

OtherViewModel.cshtml editor template:

@model OtherViewModel
@Html.EditorFor(m => m.ViewModel)

ViewModel.cshtml editor template:

@model ViewModel
@Html.EditorFor(m => m.Object)

The main controller:

public ActionResult YourAction(MainModel data)
{
    ...

Models:

public class MainModel
{
    public MainModel() { OtherViewModel = new OtherViewModel(); }
    public OtherViewModel OtherViewModel { get; set; }        
}

public class OtherViewModel
{
    public OtherViewModel() { ViewModel = new ViewModel(); }
    public ViewModel ViewModel { get; set; }
}

public class ViewModel
{
    public string Object { get; set; }
}

Notice that the templates names reflect model types names. Next, put your templates under this ~/Views/Shared/EditorTemplates/ or this ~/Views/YourController/EditorTemplates/ directory.

或者,您可以将与在“视图”中获得的原始模型相同的模型传递给“其他部分”,然后再次传递给“部分”,同时仅使用所需部分的相应视图。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM