How to persist data models passed to partial views?

To illustrate the problem I face, I have put together three simple data models:

 public class PersonalModel {
     public string FirstName { get; set; }
     public string LastName { get; set; }
 }

 public class AddressModel {
     public string Street { get; set; }
 }

 public class OverallModel {
    public string Id { get; set; }
    public PersonalModel Personal { get; set; }
    public AddressModel Address { get; set; }
 }

Here is my simple Index.chtml:

@model WebAppTest.Models.OverallModel
@using (Html.BeginForm())
{
  @Html.AntiForgeryToken()

  <div class="form-horizontal">
    <h4>OverallModel</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.Id)

    <div>
        @Html.Partial("Personal", Model.Personal)
    </div>
    <div>
        @Html.Partial("Address", Model.Address)
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
  </div>
}

When the "Save" button is clicked, the following controller method gets invoked:

[HttpPost]
public ActionResult Index(OverallModel model) {
    return View(model);
}

The problem I have is that model.Personal and model.Address values always show up as null in the controller method.

Although the values are correctly getting passed to the partial views, the Razor engine is not able to put the overall object back together when submit is clicked.

Would appreciate it if you could enlighten me on what is it that I am missing. Regards.


Solution 1:

Pass the OverallModel to your partials so that the controls will be correctly named for posting back to OverallModel. Currently you would have controls with name="FirstName" but they need to be name="Personal.FirstName"

@Html.Partial("Personal", Model)

and change the partials to suit

@model OverallModel
....
@Html.TextBoxFor(m => m.Personal.FirstName)

As an alternative, you can also pass the prefix to the partial

@Html.Partial("Address", Model.Personal, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "Personal" }})