How do I make the default modelbinding handle Lists?
Let’s say I have a ShoppingCart class, which has a ShoppingCartItem List:
Public Class ShoppingCart
Public Property CouponCode As String
Public Property Items As New List(Of ShoppingCartItem)
End Class
Public Class ShoppingCartItem
Public Property Title As String
Public Property Count As Integer
End Class
My view looks like this (as per the advice from this, and this, blogpost):
@ModelType VAVTag.LuckyDraw.ShoppingCart
@Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head runat="server">
<title>Index</title>
</head>
<body>
@Using Html.BeginForm()
@<fieldset>
<legend>ShoppingCart</legend>
@Html.TextBoxFor(Function(m) m.CouponCode)
<hr />
@Html.EditorFor(Function(m) m.Items)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
End Using
</body>
</html>
The items are rendered using an EditorTemplate (thanks Darin):
@ModelType ShoppingCartItem
@Html.EditorFor(Function(m) m.Title )
@Html.EditorFor(Function(m) m.Count )
<br />
In my controller, I’m inserting some random data, and the view renders my shoppingcart nicely, with three items.
Public Class ShoppingCartController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Dim model As New ShoppingCart
model.Items.Add(New ShoppingCartItem With {.Count = 1, .Title = "Item A"})
model.Items.Add(New ShoppingCartItem With {.Count = 17, .Title = "Item B"})
model.Items.Add(New ShoppingCartItem With {.Count = 100, .Title = "Item C"})
Return View(model)
End Function
<HttpPost()>
Function Index(model As ShoppingCart) As ActionResult
Return View(model) ' model is empty!
End Function
End Class
However, when I submit the page, no values are picked up, not even the CouponCode field. The model object is empty. What gives?
Ultimately, my goal is to add/remove items clientside via javascript and then have the modelbinder pick up the changes automatically when the page is submitted.
Update: I was just missing the Property keyword from my model properties declarations. It’s too late, and I got to get some sleep. 🙂
The default model binder already handles lists and dictionaries perfectly fine.
Just use editor templates. For example:
View model:
Controller:
View:
and finally the editor template (
~/Views/Home/EditorTemplates/ShoppingCartItem.cshtml) which will be rendered for each item of theItemscollection: