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.
You can have methods in your ViewModel .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With