Chris Woods
Chris Woods

Reputation: 837

MVC Checkbox grouping

I've got a view that needs some checkboxes describing days of the week. I want to return back to the controller which boxes are selected. I found some help from various Google searches, etc, and here's what I have.

Section 1:

In the Controller:

vm.AllDays = Enum.GetValues(typeof(DayOfWeek)).Cast<DayOfWeek>().ToList();

In the View:

@foreach (var day in Model.AllDays) {
   <input type="checkbox" name="days" value="@day"/> <label>@day</label><br />
}

And then in my post handler:

[HttpPost]
public ActionResult _AddEdit(SubscriptionDetailsModel vm, IEnumerable<string> days) {
    //etc, etc, etc
}

This works, I get the selected days coming in on the days parameter. However, I got curious and changed the 'name' attribute on the checkboxes to the field in my model that I ultimately want these values to go to. In summary, my model for the view contains an object that has a List in it. That List is the collection I would like the selected values to end up in. But here's the relevant code.

Section 2

Model snippets:

public class SubscriptionDetailsModel {
    public CronTabModel CrontabModel { get; set; }
    //...
}

public class CronTabModel {
    public List<DayOfWeek> On { get; set; }
}

Controller:

[HttpPost]
public ActionResult _AddEdit(SubscriptionDetailsModel vm) {
    //etc, etc, etc
}

And, of course, view:

@foreach (var day in Model.AllDays) {
    <input type="checkbox" name="On" value="@day"/> <label>@day</label><br />
}

Edit: The reason I was seeing confusing results is due to a typo elsewhere in my View.

Technically, the code in Section 1 is usable for my situation, I can do some string parsing, etc. Is it possible to make the Checkbox group populate from one collection (Model.AllDays) and return in a second collection (Model.CronTabModel.On)?

Upvotes: 2

Views: 1460

Answers (1)

Slicksim
Slicksim

Reputation: 7172

Model binding to a list is a bit awkward, but possible. MVC has an issue with gaps in indices, they did build in a helper to fix it. The hidden field lets MVC know about the gaps so it can bind effectively.

@for (var index =; index < Model.AllDays.Count(); index++) {
    @Html.Hidden("AllDays.Index", index)
    @Html.CheckBoxFor(m => Model.AllDays[Index], new { Value= Model.AllDays[index] }
    <label>@Model.AllDays[Index]</label><br />
}

That should let you bind to a list of checkboxes that post their values back and are bound to a property called AllDays on your model.

If you want to change the name, you will need to change the name on your Model that you pass out. Doing it this way allows MVC to add the indexers onto the name, so you end up with

AllDays[0] = "Sunday"
AllDays[1] = "Monday"

Etc etc.

Some more reading about array binding http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

Upvotes: 1

Related Questions