NOTE: This post is out of date! I'll update it later.
Using the DefaultModelBinder in ASP.NET MVC Beta, you can bind submitted form values to arguments of an action method. But what if that argument is a list? Can you bind a posted form to an IList<T>?
Sure thing! It’s really easy if you’re posting a bunch of simple types. For example, suppose you have the following action method.
public ActionResult UpdateInts(IList<int> ints) {
return View(ints);
}
You can bind to that by simply submitting a bunch of form fields which each have the same name. For example, here’s an example of a form that would bind to this, assuming you keep each value a proper integer.
<form method="post" action="/Home/UpdateInts">
<input type="text" name="ints" value="1" />
<input type="text" name="ints" value="4" />
<input type="text" name="ints" value="2" />
<input type="text" name="ints" value="8" />
<input type="submit" />
</form>
For a list of complex types, it gets a bit trickier. Suppose you have the following product class and action method.
public class Product {
public string Name { get; set; }
public decimal Price { get; set; }
}
//Action method on HomeController
public ActionResult UpdateProducts(IList<Product> products) {
return View(products);
}
We thought about taking a similar approach as we did with simple types, but ran into potential potholes. For example, a checkbox doesn’t submit a value if its unchecked. So if we had four products on the form, and the last two products had a boolean property checked, when binding, we might associate those two checks with the first two properties.
So we decided we needed some way of indexing form fields. Here’s an example of a form that submits three products.
<form method="post" action="/Home/UpdateProducts">
<input type="hidden" name="products.Index" value="0" />
<input type="text" name="products[0].Name" value="Beer" />
<input type="text" name="products[0].Price" value="7.32" />
<input type="hidden" name="products.Index" value="1" />
<input type="text" name="products[1].Name" value="Chips" />
<input type="text" name="products[1].Price" value="2.23" />
<input type="hidden" name="products.Index" value="2" />
<input type="text" name="products[2].Name" value="Salsa" />
<input type="text" name="products[2].Price" value="1.23" />
<input type="submit" />
</form>
Note that the index can be anything, as long as the form fields associated with the index line up. So the following is also valid.
<form method="post" action="/Home/UpdateProducts">
<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />
<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />
<input type="hidden" name="products.Index" value="caliente" />
<input type="text" name="products[caliente].Name" value="Salsa" />
<input type="text" name="products[caliente].Price" value="1.23" />
<input type="submit" />
</form>
Currently, we don’t have any helpers for generating the form, so this is a very manual process. This is something we may consider in the future. In the meanwhile, give it a whirl and let us know how it works out for you. I’m honestly curious about what scenarios people have for using this.