ASP.Net MVC 2.0 comes with great HTML helpers right out of the box, which include a check box helper. Unfortunately the way in which the check box helper renders a check box is not the traditional way most web developers use check boxes. Microsoft instead went with a true/false scenario for check boxes, which is great for many uses of check boxes. However, it does not support a named group of check boxes that many web developer’s use.
What We Want
So with that in mind we’re going to create a MVC Check Box Group Helper.
First let’s look at what the well formed html for the check box group with labels looks like:
[code lang="html"]
[/code]
Obviously the check box group is for selecting colors and the values are hex color codes.
The check box group name is “Colors”; each check box has a unique value and a unique ID. The unique ID allows you to use the labels “for” attribute to specify which check box it is for, thus when you click on an associated label it toggles the check box.
Constraints
Now for some constraints for the check box group:
- Easy to use
- Maps to an IEnumerable
- Does not use JavaScript
- Does not use hidden form elements
- If possible reuse preexisting MVC classes
All of these are pretty straight forward and will come into play as we design this.
If you’re not aware Microsoft released MVC’s source code under the MS-PL open source license. This is great as it lets us peak under the hood and see how they implement things. This is really great if you want to make your own helpers and take into consideration things that the official helpers do as well.
The Foundation
Since a check box group will obviously need some data it will need some sort of container which can represent a check box. It will need to keep track of just a few things:
- The text to display
- A value to use
- And if it’s checked
In fact, just like SelectListItem. Here’s the source from the MVC project for SelectListItem.
[code lang="C#"]
namespace System.Web.Mvc {
public class SelectListItem {
public bool Selected {
get;
set;
}
public string Text {
get;
set;
}
public string Value {
get;
set;
}
}
}
[/code]
It can’t be much simpler than that, and as it turns out we can make use of this perfectly for our check box. With SelectListItem we can either use SelectList or IEnumerable<SelectListItem> to keep our list.
With that out of the way we now have something to hold the data for our check boxes in that is easy to translate our own data into, people are familiar with it already, and it satisfies our fourth constraint.
The Helper
Okay, now for our helper. If you’re not familiar with how to create a basic helper with extension methods you can read this great article and then come back here.
Let’s look at the constructor of our new helper whose parameters are quite simple.
[code lang="C#"]
public static string CheckBoxGroup(this HtmlHelper htmlHelper, string name, IEnumerable
[/code]
And you’ll use it in your view like so:
[code lang="asp"]
<%= Html.CheckBoxGroup("Colors", Model.Colors) %>
[/code]
As you can see, the name of the group will be “Colors” and I’m passing an IEnumerable<Color> from my View’s model (you’re using strongly typed views right?).
Now here’s the actual helper code:
[code lang="C#"]
public static string CheckBoxGroup(this HtmlHelper htmlHelper, string name, IEnumerable
{
name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("Parameter must be specified.", "name");
}
StringBuilder listItemBuilder = new StringBuilder();
int count = 0;
foreach (SelectListItem item in selectList)
{
listItemBuilder.AppendLine(ListItemToCheckBox(item, name, count) + ListItemToLabel(item, name, count) + "
");
count++;
}
return listItemBuilder.ToString();
}
[/code]
This is obviously modeled after the Drop Down List helper that comes with MVC.
The guts of the helper come down to the for loop. For each of the select list items we’re building a line of HTML that includes both our check box and our label. The code for which is here:
[code lang="C#"]
internal static string ListItemToCheckBox(SelectListItem item, string name, int count)
{
TagBuilder builder = new TagBuilder("input");
builder.Attributes["type"] = "checkbox";
builder.Attributes["name"] = name;
builder.Attributes["id"] = name + count;
if (item.Value != null)
{
builder.Attributes["value"] = item.Value;
}
if (item.Selected)
{
builder.Attributes["checked"] = "checked";
}
return builder.ToString(TagRenderMode.Normal);
}
internal static string ListItemToLabel(SelectListItem item, string name, int count)
{
TagBuilder builder = new TagBuilder("label")
{
InnerHtml = item.Text
};
builder.Attributes["for"] = name + count;
return builder.ToString(TagRenderMode.Normal);
}
[/code]
And there you have it. Put the constructor and the two internal static methods in a class and you have a Html.CheckBoxGroup helper.
What Next?
There is room for improvement on this model. I didn’t handle everything, if you want to expand it some things I’ve done or looked into are:
- Custom HTML Attributes
- More customization on how check boxes are separated
- Creating a Strongly Typed version