Controller:
[HttpPost]
public ActionResult GetChecked(FormCollection formCollection)
{
var checked = formCollection["Checked"].Split(',');
var ids = formCollection["Original.ID"].Split(',');
}
View:
@model IEnumerable<Models.Entry> []
<table>
@using (Html.BeginForm("GetChecked", "ControllerName"))
{
@foreach (var item in Model[0])
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Original.ID)
@Html.HiddenFor(modelItem => item.Original.ID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Original.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.New.Name)
</td>
<td>
@Html.CheckBoxFor(modelItem => item.Checked)
</td>
</tr>
}
</table>
//Then there's another table with Model[1]
Model
public class Entry
{
public Entry()
{
Original = new SomeObject();
New = new SomeObject();
Checked = false;
}
public SomeObject Original { get; set; }
public SomeObject New { get; set; }
public bool Checked { get; set; }
}
This works but the ids
-array in my controller gets both a true- and a false value for the checked rows. I read that it's because of the FormCollection
.
Question: How can I let GetChecked
take an IEnumerable<Models.Entry>
as a parameter instead? When I tried it it resulted in a null value.
There are a couple of things that you should change:
When rendering controls from a list or array using CheckBoxFor, EditorFor, etc. you should never use
foreach
- instead, ALWAYS use afor
-loop and apply indexing to your collection. The reason is that indexing creates numbered items in your<form>
that then no longer conflict with each other, and those numbered items are precisely what you need to successfully process a list of submitted values. See this answer for a simple example: https://stackoverflow.com/a/15375949/1220550Don't use
FormCollection
, use a ViewModel class instead. By usingFormCollection
you are giving up on Databinding /ModelState
/ValidationSummary
which together are a superb feature of ASP.NET MVC. It is too much to explain it all here, but here is a great link that does exactly that.It is best to use a fully defined ViewModel class, not only for databinding (see before) but also for consistency and ease-of-use. Having an array of
IEnumerable<X>
as your@model
is at best confusing, and at worst a cause for errors. And what if suddenly you also want to pass anint
? Impossible withIEnumerable<X>[]
, yet a piece of cake with a ViewModel - just add it to the class.