Blake Rivell Blake Rivell - 2 months ago 18
C# Question

Posting multiple forms on MVC6 Razor View with a Single View Model

I have a razor view that will contain 5 forms. (A, B, C, D, E). Each of these forms has their own ViewModel (AViewModel, BViewModel, CViewModel, DViewModel, EViewModel).

I created a parent ProductViewModel that the page will use as its only ViewModel. Within this ViewModel will be all of the other ViewModels for each form on the page (listed above).

Here is what the ProductViewModel's properties look like:

public AViewModel { get; set; }
public BViewModel { get; set; }
public CViewModel { get; set; }
public DViewModel { get; set; }
public EViewModel { get; set; }


My razor view looks like the following:

@model MVCApp.ViewModels.ProductViewModel

@{
ViewData["Title"] = "Product Detail";
}

<h2>Product Detail</h2>

<form asp-controller="A" asp-action="Save" data-ajax="true" data-ajax-method="POST">
<div class="form-horizontal">
<h4>Form A</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="AViewModel.Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="AViewModel.Name" class="form-control"/>
<span asp-validation-for="AViewModel.Name" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="AViewModel.StartDate" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="AViewModel.StartDate" class="form-control"/>
<span asp-validation-for="AViewModel.StartDate" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="AViewModel.EndDate" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="AViewModel.EndDate" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>

<div>
<a asp-action="Index">Back to List</a>
</div>

@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}


When the Save button is clicked I end up in the Save (POST) Action Method of the A Controller just as I would expect:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Save(AViewModel viewModel)
{
return Ok();
}


However, I noticed all of the properties of the viewModel param are empty.

Does this mean I really have to pass the ProductViewModel object as my ViewModel to the Save Action Method for all 5 of these forms where only the ViewModel in scope will be populated and everything else will be null? Or is there a better way?

Answer

I suggest make each form a partial view and pass in only the sub model needed from the parent model

 @{await Html.RenderPartialAsync("AViewPartial", Model.AViewModel); }

then your inputs in the partial can be changed from

<input asp-for="AViewModel.Name" class="form-control"/>

to

<input asp-for="Name" class="form-control"/>

which should make it bind correctly by the modelbinder so it gets passed into your action

Comments