I have a problem and I can't find solution.
I'm using Razor and it is my VieModel class.
public class GroupToExport
{
public GroupToExport()
{
ToExport = false;
}
[DisplayName("Export")]
public bool ToExport { get; set; }
public Group Group { get; set; }
}
public class GroupsToExport
{
public GroupsToExport()
{
//refill list
}
public List<GroupToExport> ExportingGroups { get; set; }
}
View:
@using (Html.BeginForm("Export", "ElmahGroup", FormMethod.Post, new { id = "toExportForm" }))
{
//some divs
<input type="submit" id="js-export-submit" value="Export" />
@foreach (var item in Model.ExportingGroups)
{
<tr>
<td class="js-export-checkbox">
@Html.CheckBoxFor(modelItem => item.ToExport)
</td>
</tr>
}
//some divs
}
Controller:
public ActionResult Export(GroupsToExport model)
{
var groupsToExport = model.ExportingGroups.Where(x => x.ToExport).Select(x => x);
throw new System.NotImplementedException();
}
After submit "ToExport", in Controller, every group always has value 'false'. Even if all groups are checked.
Can somebody help me? What I'm doing wrong?
You cannot use a foreach
loop to generate controls for a collection. The html you're generating for each checkbox (and for the associated hidden input) is <input type="checkbox" name="item.ToExport" .../>
. Your model does not contain a property which is named item
.
Use a for
loop
@for(int i = 0; i < Model.ExportingGroups.Count; i++)
{
<tr>
<td class="js-export-checkbox">
@Html.CheckBoxFor(m => m.ExportingGroups[i].ToExport)
</td>
</tr>
}
Now your HTML will be
<input name="ExportingGroups[0].ToExport" .../>
<input name="ExportingGroups[1].ToExport" .../>
etc. which will correctly bind to your model
Edit
Alternatively you can use a custom EditorTemplate
for typeof GroupToExport
. Create a partial view /Views/Shared/EditorTemplates/GroupToExport.cshtml
@model yourAssembly.GroupToExport
<tr>
<td class="js-export-checkbox">
@Html.CheckBoxFor(m => m.ToExport)
</td>
</tr>
And then in the main view
@Html.EditorFor(m => m.ExportingGroups)
The EditorFor()
method will generate the correct html for each item in your collection based on the template.
You are using Incorrect syntax to Map the values back when they are posted, since the checked value of a checkbox is initialised to false by default, that is the reason why it is always false,use sysntax
@for(int i = 0; i < Model.ExportingGroups.Count(); i++)
{
<tr>
<td class="js-export-checkbox">
@Html.CheckBoxFor(modelItem => Model.ExportingGroups[i].ToExport)
</td>
</tr>
}
//some divs
This should map back all values you are looking for.
I found this works much better: Leave the foreach loop as is (do not user a counter)
@foreach (var item in Model.GroupToExport)
{
Then use this Razor format to display a checkbox
@Html.CheckBox("Active", @item.ToExport)
Simple to use and does not make you change the typical foreach loop.