Complex models and partial views - model binding issue in ASP.NET MVC 3
I have 2 models in my sample MVC 3 application, SimpleModel
and ComplexModel
, shown below:
public class SimpleModel
{
public string Status { get; set; }
}
public class ComplexModel
{
public ComplexModel()
{
Simple = new SimpleModel();
}
public SimpleModel Simple{ get; set; }
}
I have defined views for this models:
_SimplePartial.cshtml
:
@model SimpleModel
@Html.LabelFor(model => model.Status)
@Html.EditorFor(model => model.Status)
and Complex.cshtml
:
@model ComplexModel
@using (Html.BeginForm()) {
@Html.Partial("_SimplePartial", Model.Simple)
<input type="submit" value="Save" />
}
After submitting form, with random value entered in Status
field, the value is not binded to my model. The Status
field is NULL
when I'm checking the model in my controller action:
[HttpPost]
public ActionResult Complex(ComplexModel model)
{
// model.Simple.Status is NULL, why ?
}
Why is it not binded ? I don't want to inherit models. Do I have to write my custom model binders for such simple case ?
Regards.
Instead of:
@Html.Partial("_SimplePartial", Model.Simple)
I would recommend you using Editor templates:
@model ComplexModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.Simple)
<input type="submit" value="Save" />
}
and then put the simple partial inside ~/Views/Shared/EditorTemplates/SimpleModel.cshtml
or inside ~/Views/Home/EditorTemplates/SimpleModel.cshtml
where Home
is the name of your controller:
@model SimpleModel
@Html.LabelFor(model => model.Status)
@Html.EditorFor(model => model.Status)
Of course if you prefer to have the partial in some special location and not follow the conventions (why would you?) you could specify the location:
@Html.EditorFor(x => x.Simple, "~/Views/SomeUnexpectedLocation/_SimplePartial.cshtml")
then everything will come into place as expected.
As Daniel Hall suggests in his blog, pass a ViewDataDictionary
with a TemplateInfo
where HtmlFieldPrefix
is set to the name of the SimpleModel-property:
@Html.Partial("_SimplePartial", Model.Simple, new ViewDataDictionary(ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo
{
HtmlFieldPrefix = "Simple"
}
})