HTML Helpers For Forms In Razor Web Pages

A nugget that has remained partially hidden from view within the Web Pages framework is the HtmlHelper class. Parts of this class peek out in the template sites provided in WebMatrix where validation is performed and related messages displayed, but a vast range of methods designed for rendering form inputs are often overlooked in tutorials, blog articles and books (mine included). This article provides an overview of Web Pages HTML Helpers, and digs into one or two in more detail.

There are HTML helpers for every kind of form control: check boxes, hidden fields, password boxes, radio buttons, text boxes, text areas, dropdown lists and list boxes. There is also a helper for the HTML Label element, which associates descriptive text to a form control and can provide usability improvements in certain cases. Each helper method provides a shorthand way to render valid HTML for the specific control. The following table lists the Html Helpers and maps them to their HTML counterpart:

Helper HTML Element
Html.CheckBox <input type="checkbox" />
Html.DropDownList <select></select>
Html.Hidden <input type="hidden" />
Html.Label <label for="" />
Html.ListBox <select></select> or <select multiple></select>
Html.Password <input type="password" />
Html.Radio <input type="radio" />
Html.TextArea <textarea></textarea>
Html.TextBox <input type="text" />

 

If you have had any exposure to ASP.NET MVC, these helpers will look familiar. However, don't be fooled - the Web Pages helpers do not always work in the same way as their MVC counterparts. For one thing, there is no concept of "model binding" in ASP.NET Web Pages (yet). For another, some of the overloads do not map to an MVC counterpart.

Most of the Web Pages HTML Helpers work in the same way to MVC, and have a similar set of overloads. The TextBox helper is a good example for illustrating the basics. Here's a list of the overloaded methods:

TextBox(String)
TextBox(String, Object)
TextBox(String, Object, IDictionary<String, Object>)
TextBox(String, Object, Object)

The first method generates an HTML text input with a name and id attribute that uses the string value passed to the method. The second does the same, but allows you to specify the value of the text box through the object parameter. The third and fourth options build on the second, but offer two different ways to pass values for other attributes (width, style, class etc) either as a dictionary, or as an anonymous object. Here's a form that illustrates how these work:

<form method="post">
    First Name: @Html.TextBox("firstname")<br />
    Last Name: @Html.TextBox("lastname", Request["lastname"])<br />
    Town: @Html.TextBox("town", Request["town"], new Dictionary<string, object>(){{ "class", "special" }})<br />
    Country: @Html.TextBox("country", Request["country"], new { size = 50 })<br /> 
    <input type="submit" />
</form>

And here's the HTML source for the rendered page:

<form method="post">
    First Name: <input id="firstname" name="firstname" type="text" value="" /><br />
    Last Name: <input id="lastname" name="lastname" type="text" value="" /><br />
    Town: <input id="town" name="town" class="special" type="text" value="" /><br />
    Country: <input id="country" name="country" size="50" type="text" value="" /><br /> 
    <input type="submit" />
</form>

Most of the other helpers feature the same set of four overloaded methods - even the Hidden field where attributes other than id, name and value seem irrelevant. The Radio and CheckBox helpers feature additional overloads that have a Boolean parameter through which you can specifiy whether the input should be checked or not. The following line of code results in a checked checkbox with the name and id of "myCheck":

@Html.CheckBox("myCheck", true)

DropDownLists and ListBoxes are a different proposition.There are eight overloads for the DropDownList and twelve overloads for the ListBox helper. Eight of the ListBox overloads result in exactly the same HTML as the eight DropDownList helper methods - an HTML select element that allows single selection. The other four ListBox overloads accept a Boolean, which if set to true, allows multiple selections. All a bit odd and unnecessary, really. And for that reason, I would recommend that you use the DropDownList helper for single selection lists, and the ListBox only for multi-selection to save yourself confusion. Doing this will make transition to MVC (should you decide to go that route) a lot easer too, because MVC doesn't feature anywhere as many overloads for the ListBox.

All of the DropDownList and ListBox helpers expect an IEnumerable<SelectListItem> to be provided. A SelectListItem has three properties: Value, Text and Selected. The Value property is used by the HTML value attribute of an option element, and is the value passed in the Request collection when the form is submitted. The Text property is displayed on screen and the Selected property determines whether the the item should be preselected. The following code shows how to construct a List<SelectListItem>, setting two of the items as Selected, and then passing that to a ListBox which allows multiple selection:

@{
    var items = new List<SelectListItem>{
        new SelectListItem {Value = "1", Text = "Blue"},
        new SelectListItem {Value = "2", Text = "Red"},
        new SelectListItem {Value = "3", Text = "Green", Selected = true},
        new SelectListItem {Value = "4", Text = "Yellow", Selected = true},
        new SelectListItem {Value = "5", Text = "Black"}
    };
}
@Html.ListBox("myListbox", items, null, 6, true)  

The overloaded helper method used here is ListBox(String, IEnumerable(SelectListItem), Object, Int32, Boolean). The next example shows how to generate a IEnumerable<SelectListItem> from a database query. This time, the collection will feature in a DropDownList and only one of the items will be set as selected - the item with a CategoryId of 4:

@{
    var db = Database.Open("Northwind");
    var data = db.Query("SELECT CategoryId, CategoryName FROM Categories");
    var items = data.Select(i => new SelectListItem {
        Value = i.CategoryId.ToString(), 
        Text = i.CategoryName,
        Selected = i.CategoryId == 4 ? true : false
    });
}
@Html.DropDownList("CategoryId", items)

The code above uses LINQ To Objects to work on the collection returned from the Database.Query method call. You don't have to use LINQ To Objects. You could simply iterate the data variable in a foreach loop, and build a collection of SelectListItems that way, but LINQ is the new foreach loop.

The final example shows a DropDownList created from the overloaded method that has the most parameters:

@{
    var db = Database.Open("Northwind");
    var data = db.Query("SELECT CategoryId, CategoryName FROM Categories");
    var items = data.Select(i => new SelectListItem {
        Value = i.CategoryId.ToString(), 
        Text = i.CategoryName
    });
}
@Html.DropDownList("CategoryId", "Please Select One", items, 4, new {@class = "special"})

This is the same database query as in the previous example, except that none of the items have their Selected property set to true. That job is left to the helper instead. The first parameter provides a name attribute as usual, and the second sets the "default text". The fourth parameter represents the value of the selected item and the final parameter sets the CSS class of the select list to "special". Notice that when using an anonymous object to specify HTML attributes, you must prefix C# keywords used as property names with an @ sign (in this case "class"). This is nothing to do with Razor, but is part of the C# language specification.