Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I bind nested ViewModels from View to Controller in MVC3?

Tags:

I am developing an ASP.NET MVC 3 application in C# and I use Razor. I am now dealing with a problem concerning the binding of objects through ViewModels passed/received to/from the View by the Controller. Let's make it clear. I have the following ViewModels:

public class ContainerViewModel {    public int ContainerId {get; set;}    public string ContainerName {get; set;}    public List<ItemPostModel> ItemData {get; set;} }  public class ItemPostModel {     public int ItemId {get; set;}    public string ItemName {get; set;}    public int ItemValue {get; set;} } 

The ContainerViewModel is used to pass the data to the View. Its properties ContainerId and ContainerName are used just for display purposes. The List<ItemPostModel> property has to be filled using a Form. The View looks something like this (it is a simplified version):

<strong>@Model.ContainerName</strong>   @using (Html.BeginForm())  {     <fieldset>     @foreach(var item in Model.ItemData)     {        @Html.TextBox(item.ItemId);        @Html.TextBox(item.ItemName);        @Html.TextBox(item.ItemValue);         <p>            <input type="submit" value="Save" />        </p>     }     </fieldset> } 

The Controller corresponding action methods are as follows:

public ActionResult UpdateItems() {    //fill in the ContainerViewModel lcontainer     return View("UpdateItems", lcontainer); }  [HttpPost] public ActionResult UpdateItems(int containerId, ItemPostModel itemData) {    //store itemData into repository } 

The problem is that with this code the ItemPostModel itemData passed to the Post ActionMethod UpdateItems is always empty. The containerId is correctly passed. Same result if I use the following code in the Controller (obviously not DRY);

[HttpPost] public ActionResult UpdateItems(ContainerViewModel container) {    //extract itemData from ContainerViewModel container    //store itemData into repository } 

How can I "teach" the application that I want the form elements stored in the List<ItemPostModel>? Shall I modify the ModelBinder or there is a simpler way to perform this task? Thanks everybody for your answers.

like image 229
CiccioMiami Avatar asked Apr 18 '11 08:04

CiccioMiami


People also ask

Can Viewmodels have methods?

You can have methods in your ViewModel .

How do I use ViewModel in view?

In ViewModel put only those fields/data that you want to display on the view/page. Since view reperesents the properties of the ViewModel, hence it is easy for rendering and maintenance. Use a mapper when ViewModel become more complex.


1 Answers

Don't write loops in a view. Use editor templates:

<strong>@Model.ContainerName</strong> @using (Html.BeginForm())  {     <fieldset>         @Html.EditorFor(x => x.ItemData)         <input type="submit" value="Save" />     </fieldset> } 

and inside the corresponding editor template (~/Views/Shared/EditorTemplates/ItemPostModel.cshtml):

@model ItemPostModel @Html.TextBox(x => x.ItemId) @Html.TextBox(x => x.ItemName) @Html.TextBox(x => x.ItemValue) 

And in the controller action you might need to specify the prefix:

[HttpPost] public ActionResult UpdateItems(     int containerId,      [Bind(Prefix = "ItemData")]ItemPostModel itemData ) {    //store itemData into repository } 

and that should be pretty much all. The editor template will take care of generating the proper input field names for the binding to work.

like image 147
Darin Dimitrov Avatar answered Sep 23 '22 01:09

Darin Dimitrov