CheckBoxList Helper for MVC
The early previews of the MVC Toolkit contained a few helpers that are not available in the current MVC Beta and MVC Beta Futures. On of the ones that was nixed was the CheckBoxList helper. I was in need of this type of functionality lately and found myself out of luck. I needed to add a dynamic list of checkboxes to a form, like the roles that a user could possible be a member of. These roles could be added to or deleted from at any time.
I looked to the Html.CheckBox helper to see if that would work. This helper can be used like so:
1: /* The model for this is a Dictionary<string,bool> that contains
2: the name for the role and whether the user is a member */
3:
4: <% foreach (var info in ViewData.Model) { %>
5: <div><%= Html.CheckBox(info.Key, info.Value) %> <%= info.Key %></div>
6: <% } %>
The problem with using Html.CheckBox for my scenario arises when you need to get the values in the form ActionMethod. For Html.CheckBox, the form handler is expecting a boolean parameter for each checkbox. An example is show below.
1: [AcceptVerbs(HttpVerbs.Post)]
2: public ActionResult Roles(bool administrator, bool user, bool poweruser)
3: {
4: // Each bool parameter is the checked value for the checkbox that
5: // has the same name. If my list of roles is dynamic, this does
6: // not work so well :(
7: }
As you can see, this would not satisfy the requirements that I had. So what is the answer? Create my own CheckBoxList helper of course.
Here is the extension method code for my implementation, along with a simple class that contains the info needed for each checkbox in the list..
1: public static class InputExtensions
2: {
3: public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<CheckBoxListInfo> listInfo)
4: {
5: return htmlHelper.CheckBoxList(name, listInfo,
6: ((IDictionary<string, object>) null));
7: }
8:
9: public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<CheckBoxListInfo> listInfo,
10: object htmlAttributes)
11: {
12: return htmlHelper.CheckBoxList(name, listInfo,
13: ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes)));
14: }
15:
16: public static string CheckBoxList(this HtmlHelper htmlHelper, string name, List<CheckBoxListInfo> listInfo,
17: IDictionary<string, object> htmlAttributes)
18: {
19: if (String.IsNullOrEmpty(name))
20: throw new ArgumentException("The argument must have a value", "name");
21: if (listInfo == null)
22: throw new ArgumentNullException("listInfo");
23: if (listInfo.Count < 1)
24: throw new ArgumentException("The list must contain at least one value", "listInfo");
25:
26: StringBuilder sb = new StringBuilder();
27:
28: foreach (CheckBoxListInfo info in listInfo)
29: {
30: TagBuilder builder = new TagBuilder("input");
31: if (info.IsChecked) builder.MergeAttribute("checked", "checked");
32: builder.MergeAttributes<string, object>(htmlAttributes);
33: builder.MergeAttribute("type", "checkbox");
34: builder.MergeAttribute("value", info.Value);
35: builder.MergeAttribute("name", name);
36: builder.InnerHtml = info.DisplayText;
37: sb.Append(builder.ToString(TagRenderMode.Normal));
38: sb.Append("<br />");
39: }
40:
41: return sb.ToString();
42: }
43: }
44:
45: // This the information that is needed by each checkbox in the
46: // CheckBoxList helper.
47: public class CheckBoxListInfo
48: {
49: public CheckBoxListInfo(string value, string displayText, bool isChecked)
50: {
51: this.Value = value;
52: this.DisplayText = displayText;
53: this.IsChecked = isChecked;
54: }
55:
56: public string Value { get; private set; }
57: public string DisplayText { get; private set; }
58: public bool IsChecked { get; private set; }
59: }
This can then be used to render the list of checkboxes in a View as shown below:
1: /* Where ViewData.Model is a List of CheckBoxListInfo objects that
2: provide the details for the checkboxes. */
3:
4: <div><%= Html.CheckBoxList("roles", ViewData.Model) %></div>
And now, in the post ActionMethod, we can access the ones that have been checked like so:
1: [AcceptVerbs(HttpVerbs.Post)]
2: public ActionResult Roles(string[] roles)
3: {
4: /* The 'roles' parameter contains the values from the
5: checkboxes that were checked. */
6: }
In addition to solving the issue that I was having, this post shows how easy it is to implement your own custom helpers in MVC.