I'm following this standard pattern for using Ajax to reload a partial view. However, when the partial view is reloaded, the controls in the view have different IDs. They lose the name of the parent model. This means that when the form is posted back, model binding won't work.
So in the example below, when the page is first loaded, the checkbox id is "PenguinEnclosure_IsEnoughPenguins" but after the partial is reloaded, the checkbox id is "IsEnoughPenguins" The ID must be "PenguinEnclosure_IsEnoughPenguins" for model binding to correctly bind this to the PenguinEnclosure property of the VM.
Model:
public class ZooViewModel
{
public string Name { get; set; }
public PenguinEnclosureVM PenguinEnclosure { get; set; }
}
public class PenguinEnclosureVM
{
public int PenguinCount { get; set; }
[Display(Name = "Is that enough penguins for you?")]
public bool IsEnoughPenguins { get; set; }
}
Controller:
public ActionResult Index()
{
var vm = new ZooViewModel
{
Name = "Chester Zoo",
PenguinEnclosure = new PenguinEnclosureVM { PenguinCount = 7 }
};
return View(vm);
}
public ActionResult UpdatePenguinEnclosure(int penguinFactor)
{
return PartialView("DisplayTemplates/PenguinEnclosureVM", new PenguinEnclosureVM { PenguinCount = penguinFactor * 10 });
}
View:
@model PartialProblem.Models.ZooViewModel
@Scripts.Render("~/bundles/jquery")
<p>
Welcome to @Model.Name !
</p>
<p>
<div id="penguin">
@Html.DisplayFor(m => m.PenguinEnclosure)
</div>
</p>
<button id="refresh">Refresh</button>
<script>
$(document).ready(function () {
$("#refresh").on("click", function () {
$.ajax({
url: "/Home/UpdatePenguinEnclosure",
type: "GET",
data: { penguinFactor: 42 }
})
.done(function (partialViewResult) {
$("#penguin").html(partialViewResult);
});
});
});
</script>
Partial View:
@model PartialProblem.Models.PenguinEnclosureVM
<p>
We have @Model.PenguinCount penguins
</p>
<p>
@Html.LabelFor(m => m.IsEnoughPenguins)
@Html.CheckBoxFor(m => m.IsEnoughPenguins)
</p>