1
votes

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.

1
The name attributes of your partial are not prefixed correctly. One option is to pass the HtmlFieldPrefix as per this answeruser3559349
Prefixing worked too. I tried it.SpinDoctor
The correct approach is to use an EditorTemplate - rename you partial to BrandVM.cshtml and put it in the /Views/Shared/EditorTemplates folder - then in the view its just @Html.EditorFor(m => m.BrandVM) (the solution you accepted might work but makes no sense - it now means you cannot use that partial in other models, so you are defeating the whole purpose of using a partial)user3559349

1 Answers

0
votes

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.