I've got a viewmodel that contains other viewmodels.
public class AggregateVM
{
public BrandVM BrandVM { get; set; }
public TinTypeVM TinTypeVM { get; set; }
}
When I http post to the controller action, the TinTypeVM is populated with my edited values, but the BrandVM viewmodel where I used a partial is always null.
Here's are the view.
@model SaveEF.ViewModels.AggregateVM
@using (Html.BeginForm("EditAggregate", "Aggregate"))
{
@Html.Partial("_EditBrand", Model.BrandVM)
@Html.Label("Tin Name")
@Html.EditorFor(model => model.TinTypeVM.Name)
<input type="submit" value="Save" />
}
Here's the partial view.
@model SaveEF.ViewModels.BrandVM
@Html.Label("Brand Name")
@Html.EditorFor(model => model.Name)
Here's the controller action.
public ActionResult EditAggregate(AggregateVM vm)
{
SaveBrand(vm.BrandVM);
SaveTinType(vm.TinTypeVM);
return RedirectToAction("Index");
}
How can I use partials in the view and still pass a single view model into the EditAggregate action? I've tried different parameters in Html.BeginForm("EditAggregate", "Aggregate", FormMethod.Post, new { vm = Model })) but that didn't help.
Short Answer
You need to pass AggregateVM
to your partial too.
Long Answer
The way you are doing it right now is:
@model SaveEF.ViewModels.BrandVM
@Html.EditorFor(model => model.Name)
So if you were to inspect the name
generated for the editor would be Name
. Thus when you post, the default model binder of MVC will look for a matching property in your view model. But you view model is like this:
public class AggregateVM
{
public BrandVM BrandVM { get; set; }
public TinTypeVM TinTypeVM { get; set; }
}
And there is no Name
property.
Fix
You need to pass AggregateVM
to your partial too.
@model SaveEF.ViewModels.AggregateVM
@Html.EditorFor(model => model.BrandVM.Name)
and now the name for the editor will be BrandVM.Name
. So when you post, the default model binder will look for the property BrandVM.Name
and find it. Thus it will populate it.
The other alternative is to specify the name
attribute yourself by using @Html.Editor
or pass the attribute.