This post explains in detail the steps necessary to use the jQuery DatePicker with the ASP.NET MVC Framework to enter dates, instead of the standard Textbox.

The description covers globalization, localization, as well as validation.

Required NuGet Packages

In addition to the standard libraries of jQuery and jQuery UI, the following libraries need to be installed in order to use globalization and localization:

  • Globalize – Contains date/time and currency formats for jQuery.
  • jQuery UI i18n – Contains localizations of jQuery UI (mainly translation of the calendar).

Changing File BundleConfig.cs

The file BundleConfig.cs can be used to configure the loading of JavaScript and CSS files.

The following sections need to be changed:

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
            "~/Scripts/jquery-{version}.js",
            "~/Scripts/globalize/globalize.js",
            "~/Scripts/globalize/cultures/globalize.culture.de-DE.js"));

bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
            "~/Scripts/jquery-ui-{version}.js",
            "~/Scripts/jquery-ui-i18n.js"));

The example shows the localization for German. Other languages can be configured accordingly.

Anpassen der Datei _Layout.cshtml

The file Views/Shared/_Layout.cshtml contains the standard layout of your website. There you can also add scripts, which are supposed to be used on every page.

If the entries are not already there, add the following (Order matters):

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")
@Styles.Render("~/Content/themes/base/css", "~/Content/css")
@RenderSection("scripts", required: false)

Entity mit DataAnnotation anpassen

The next step is to annotate the property for which the DatePicker shall be used with a data type. This data type will be mapped to an EditorTemplate at runtime. We will create the EditorTemplate in the next step.

[Display(Name = "Start Date")]
[Required(ErrorMessage = "Start Date Required!")]
[DataType(DataType.Date)] // Neu hinzugefügt
public DateTime StartDate { get; set; }

The DataType annotation will get the enum value DataType.Date as parameter in the constructor. The rest of the data annotations are nothing special.

Create EditorTemplate

EditorTemplates are used by the MVC framework to render the editor when the function @Html.EditorFor(…) is used in the view.

The mapping is done automatically by the DataAnnotation.

Create the file Views/Shared/EditorTemplates/Date.cshtml with the following content:

@model DateTime?
@{
  var value = "";
  if (Model.HasValue) {
    value = string.Format("{0:d}", Model.Value.ToShortDateString());
  }
}

@Html.TextBox("", value, new { @class = "datefield", type = "text"})

After opening the current language is used automatically and the date is stored in it’s short format. In the view a Textbox is rendered with the CSS class „datefield“. This class will later be used in the view of the page to attach the jQuery DatePicker.

Create View

Now it is time to create the view for a concrete example.

<div class="tablerow">
  <div class="tablecell">
    @Html.LabelFor(model => model.StartDate)
  </div>
  <div class="tablecell">
    @Html.EditorFor(model => model.StartDate)
    @Html.ValidationMessageFor(model => model.StartDate)
  </div>
</div>

This is an example of one date field that matches the example above. You have probably realized that this is the standard MVC template without any modifications.

Add the following script to the view:

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script type="text/javascript">
      $(document).ready(function () {
        $(".datefield").datepicker($.datepicker.regional["@System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName"], { dateFormat: '@Html.ConvertDateFormat()' });
        // Code to enable client validation
        $.validator.methods.date = function (value, element) {
          Globalize.culture(@System.Threading.Thread.CurrentThread.CurrentCulture.Name);
          // you can alternatively pass the culture to parseDate instead of
          // setting the culture above, like so:
          // parseDate(value, null, "en-AU")
          return this.optional(element) || Globalize.parseDate(value) !== null;
        }
      });
    </script>
}

After loading of a document, to all TextBoxes, which contain the CSS class „datefield„, an jQuery DatePicker will be attached (first line). Here the current culture will be used to use the translated texts from the jQuery UI i18n library.

The rest of the script handles the validation on the client site, considering the language specific date format.

If you have many pages using that kind of DatePicker, you can also add the script the the general layout file.

The date needs to be converted using the ConvertDateFormat extension method explained in the next chapter.

ConvertDateFormat

ConvertDateFormat converts a .NET string into a formatted string that can be used by JavaScript.

/// <summary>
/// JQuery UI DatePicker helper.
/// </summary>
public static class JQueryUIDatePickerHelper
{
  /// <summary>
  /// Converts the .net supported date format current culture format into JQuery Datepicker format.
  /// </summary>
  /// <param name="html">HtmlHelper object.</param>
  /// <returns>Format string that supported in JQuery Datepicker.</returns>
  public static string ConvertDateFormat(this HtmlHelper html) 
  {
    return ConvertDateFormat(html, Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern);
  }

  /// <summary>
  /// Converts the .net supported date format current culture format into JQuery Datepicker format.
  /// </summary>
  /// <param name="html">HtmlHelper object.</param>
  /// <param name="format">Date format supported by .NET.</param>
  /// <returns>Format string that supported in JQuery Datepicker.</returns>
  public static string ConvertDateFormat(this HtmlHelper html, string format) 
  {
    /*
     *  Date used in this comment : 5th - Nov - 2009 (Thursday)
     *
     *  .NET    JQueryUI        Output      Comment
     *  --------------------------------------------------------------
     *  d       d               5           day of month(No leading zero)
     *  dd      dd              05          day of month(two digit)
     *  ddd     D               Thu         day short name
     *  dddd    DD              Thursday    day long name
     *  M       m               11          month of year(No leading zero)
     *  MM      mm              11          month of year(two digit)
     *  MMM     M               Nov         month name short
     *  MMMM    MM              November    month name long.
     *  yy      y               09          Year(two digit)
     *  yyyy    yy              2009        Year(four digit)             *
     */

    string currentFormat = format;

    // Convert the date
    currentFormat = currentFormat.Replace("dddd", "DD");
    currentFormat = currentFormat.Replace("ddd", "D");

    // Convert month
    if (currentFormat.Contains("MMMM"))
    {
      currentFormat = currentFormat.Replace("MMMM", "MM");
    }
    else if (currentFormat.Contains("MMM")) 
    {
      currentFormat = currentFormat.Replace("MMM", "M");
    }
    else if (currentFormat.Contains("MM")) 
    {
      currentFormat = currentFormat.Replace("MM", "mm");
    }
    else 
    {
      currentFormat = currentFormat.Replace("M", "m");
    }

    // Convert year
    currentFormat = currentFormat.Contains("yyyy") ? currentFormat.Replace("yyyy", "yy") : currentFormat.Replace("yy", "y");

    return currentFormat;
  }
}