Create Strongly Typed Custom HTML Helper for Picking Dates
Recently a beginner asked me as to how a strongly typed HTML helper
can be created. Although the process is relatively simple you need to keep in
mind a certain steps. In this short article I will explain how a custom HTML
helper can be created to render an HTML5 date picker input field. I will explain
unbound as well as model bound versions for better clarity.
ASP.NET MVC offers TextBox() and TextBoxFor() helper to render a textbox that
is unbound and model bound respectively. You can use the same helpers to render
an HTML5 date picker by supplying an anonymous object as shown below:
@Html.TextBox("birthdate", null, new { type = "date" })
@Html.TextBoxFor(m => m.BirthDate, new { type="date" })
As you can see from the above code, you can override the default input type
from text to date by supplying the anonymous object. This works well in many
cases but at times you may prefer creating a custom HTML helper that saves that
extra step of overriding input type. In nutshell you may want to write something
like:
@Html.DatePicker("birthdate")
@Html.DatePickerFor(m=>m.BirthDate)
You can achieve this by creating a custom HTML helper. To illustrate how this
can be accomplished, let's develop unbound as well as model bound helper that is
intended to display date fields.
Model
Begin by creating a new ASP.NET MVC application in Visual Studio. Add an
Entity Framework data model for the Employees table of Northiwnd database. The
Employee entity class will look like this:

We will use the BirthDate property of the Employee class and display it in
the date picker custom helper.
Now, add a folder named CustomHelpers and add a class to it -
DatePickerHelper.cs
Unbound DatePicker helper
First we will write unbound version of our DatePicker helper.
public static class DatePickerHelper
{
public static MvcHtmlString DatePicker(this HtmlHelper helper,
string name)
{
TagBuilder tag = new TagBuilder("input");
tag.Attributes.Add("name", name);
tag.Attributes.Add("id", name);
tag.Attributes.Add("value", "");
tag.Attributes.Add("type", "date");
MvcHtmlString html = new MvcHtmlString(
tag.ToString(TagRenderMode.SelfClosing));
return html;
}
public static MvcHtmlString DatePicker(this HtmlHelper helper,
string name, DateTime value)
{
TagBuilder tag = new TagBuilder("input");
tag.Attributes.Add("name", name);
tag.Attributes.Add("id", name);
tag.Attributes.Add("value", value.ToString("yyyy-MM-dd"));
tag.Attributes.Add("type", "date");
MvcHtmlString html = new MvcHtmlString(
tag.ToString(TagRenderMode.SelfClosing));
return html;
}
}
The DatePicker class is marked to be static and all its methods are static.
You might have already guessed they are extension methods of HtmlHelper class.
In order to create a custom HTML helper you need to write it as an extension
method of inbuilt HtmlHelper class. The HtmlHelper class resides in
System.Web.Mvc namespace. All the extension methods of DatePicker class will
return MvcHtmlString - a class that wraps all the HTML markup to be rendered in
the browser as a part of the extension method.
The above code shows two overloads of DatePicker() method. The first overload
accepts helper and name parameters whereas the second overload accepts helper,
name and value parameters. The helper parameter indicates that this method is
extending HtmlHelper class. The name parameter indicates the name of the date
picker control in the final HTML markup. The value parameter indicates the
default value of the date picker.
Inside, the methods use TagBuilder to construct the <input> element needed to
display the date picker. Notice that the name and as well as id attributes are
set to the name you specify. The type attribute is set to date. In the second
overload even the value attribute is set to the value parameter of the extension
method. HTML5 date picker requires date value in ISO date format (yyyy-MM-dddd)
and that's why the supplied date is formatted as shown.
An MvcHtmlString is constructed using the ToString() method of the TagBuilder
class. Since the input tag is self closing (<input ... />) TagRenderMode is
specified as SelfClosing. The MvcHtmlString instance is then returned from the
methods.
Strongly typed or model bound DatePicker helper
So far so good. Now let's develop the model bound version. This will require
some more steps and the code is slightly complex than before.
Add another method to the DatePicker class with the following signature:
public static MvcHtmlString DatePickerFor<TModel, TProperty>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression)
{
...
}
The DatePickerFor() method is a generic method that allows you to specify
type of model (TModel) and its property to be bound (TProperty). It takes two
parameters helper and expression. The helper parameter is similar to the earlier
versions but also specifies TModel. The Expression parameter indicates the
property of model to be bound. I won't go into the details of LINQ and Lambda
expressions here. It is suffice to say that the expression parameter represents
the model property to be bound with the date picker field.
Inside the DatePickerFor() method write the following code:
string datePickerName = ExpressionHelper.
GetExpressionText(expression);
string datePickerFullName = helper.ViewContext.ViewData.
TemplateInfo.GetFullHtmlFieldName
(datePickerName);
string datePickerID = TagBuilder.CreateSanitizedId
(datePickerFullName);
The first line determines the name of the date picker. This is done using
GetExpressionText() method of ExpressionHelper class. You pass the lambda
expression to this method as a parameter and it will return its string
representation. For example, if you pass m=>m.BirthDate then datePickerName
would be BirthDate.
The next line determines the fully qualified name of the date picker. This is
done to cover scenarios where the date picker is nested or is placed in partial
pages. Finally, client side ID of the date picker is determined using
CreateSanitizedId() method of TagBuilder class.
Now, continue the DatePickerFor() by adding the following lines:
ModelMetadata metadata = ModelMetadata.FromLambdaExpression
(expression, helper.ViewData);
DateTime datePickerValue = (metadata.Model == null ?
DateTime.Now : DateTime.Parse
(metadata.Model.ToString()));
The above code grabs the value of the date picker. This value comes from the
specified model property. ModelMetadata object basically represents metadata
about the model properties and in this case you are retrieving one based on the
expression. The second line examines the metadata.Model property to decide
whether property value is null or not. If it is null, current date-time is
assigned to datePickerValue variable, otherwise value of Model property is
assigned to datePickerValue.
Now, further add the following code that forms the <input> tag for the date
picker field:
TagBuilder tag = new TagBuilder("input");
tag.Attributes.Add("name", datePickerFullName);
tag.Attributes.Add("id", datePickerID);
tag.Attributes.Add("type", "date");
tag.Attributes.Add("value", datePickerValue.ToString("yyyy-MM-dd"));
This code should be familiar to you by now. It uses a TagBuilder object and
adds name, id, type and value attributes. As before value attribute is formatted
as yyyy-MM-dd.
The code you wrote so far takes care of rendering a date field that is data
bound. However, in real-world cases the field under consideration might be
validated using client side script and data annotations. To take care of this
possibility you need to add the following code:
IDictionary<string, object> validationAttributes = helper.
GetUnobtrusiveValidationAttributes
(datePickerFullName, metadata);
foreach (string key in validationAttributes.Keys)
{
tag.Attributes.Add(key, validationAttributes[key].ToString());
}
The GetUnobtrusiveValidationAttributes() method returns a Dictionary that
contains all the client side custom data attributes (data-*) required for the
proper functioning of unobtrusive JavaScript based validation. A foreach loop
iterates through this Dictionary and adds those attributes to the TagBuilder
object under consideration.
Finally, MvcHtmlString is obtained from the TagBuilder as shown below:
MvcHtmlString html=new MvcHtmlString(tag.ToString(
TagRenderMode.SelfClosing));
return html;
Completed DatePickerFor() method
This completes the DatePickerFor() method. The complete code of DatePickerFor()
is given below for your quick reference:
public static MvcHtmlString DatePickerFor<TModel, TProperty>
(this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression)
{
string datePickerName =
ExpressionHelper.GetExpressionText(expression);
string datePickerFullName = helper.ViewContext.ViewData.
TemplateInfo.GetFullHtmlFieldName
(datePickerName);
string datePickerID = TagBuilder.CreateSanitizedId
(datePickerFullName);
ModelMetadata metadata = ModelMetadata.FromLambdaExpression
(expression, helper.ViewData);
DateTime datePickerValue = (metadata.Model == null ?
DateTime.Now : DateTime.Parse(
metadata.Model.ToString()));
TagBuilder tag = new TagBuilder("input");
tag.Attributes.Add("name", datePickerFullName);
tag.Attributes.Add("id", datePickerID);
tag.Attributes.Add("type", "date");
tag.Attributes.Add("value", datePickerValue.
ToString("yyyy-MM-dd"));
IDictionary<string, object> validationAttributes = helper.
GetUnobtrusiveValidationAttributes
(datePickerFullName, metadata);
foreach (string key in validationAttributes.Keys)
{
tag.Attributes.Add(key, validationAttributes[key].ToString());
}
MvcHtmlString html=new MvcHtmlString(
tag.ToString(TagRenderMode.SelfClosing));
return html;
}
Enabling Unobtrusive JavaScript Validations
In the previous sections you took precaution to emit attributes necessary for
unobtrusive validations. So, let's enable them so that we can test our helper
accordingly. Add a class - EmployeeMetadata and write the following code into
it:
public class EmployeeMetadata
{
[Required]
public DateTime BirthDate { get; set; }
}
[MetadataType(typeof(EmployeeMetadata))]
public partial class Employee
{
}
The EmployeeMetadata class defines BirthDate property. It also decorates the
property with [Required] attribute. Then EmployeeMetadata is attached with the
Employee model class as its metadata class. This is done using the partial
Employee class.
Now, add HomeController and create Index() action in it.
public ActionResult Index()
{
NorthwindEntities db = new NorthwindEntities();
return View(db.Employees.First());
}
Then add Index view. In the <head> section of Index view add <script>
references for the following files:
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
These JavaScript files are required to support unobtrusive validations.
Then you can use our DatePickerFor() helper as shown below:
@using(Html.BeginForm("ProcessForm","Home",FormMethod.Post))
{
@Html.DatePicker("birthdateUnbound")
@Html.DatePickerFor(m=>m.BirthDate)
@Html.ValidationMessageFor(m=>m.BirthDate)
<input type="submit" value="Submit" />
}
The <form> submits to ProcessForm action. The ProcessForm() action simply
receives the data and returns Index view.
public ActionResult ProcessForm(Employee obj)
{
return View("Index",obj);
}
The following figure shows how the model bound date picker is displayed in
the browser and how the unobtrusive validations work in case BirthDate is kept
empty.

You will find that if you comment out the foreach loop from the DatePickerFor()
method then client side unobtrusive validations stop working.
That's it! Keep coding !!