Tuesday, 12 November 2013

Adding datepicker in ASP.NET MVC 4 application



This tutorial will be very easy for most of you intermediate developers, but I wanted to show bundle feature that is available in MVC 4 using date picker example. I will also show how we can add datepicker in previous versions of MVC.
There are few methods we can do it however I will show you only 2.
First we have to add some references to jquery, jquery-ui and styles. As I mention in mvc 4 we can use bundles which improve performance and give us less headache in the future.
To access bundle configuration go to App_Start and open BundleConfig.cs.



You can very easily add your own custom styles and scripts to existing bundles. For instance you can MyCustomStyles.css to existing bundle:

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css", "~/Content/MyCustomStyles.css"));



Open _Layout page and find at the bottom @Scripts.Render("~/bundles/jquery"). Cut it and paste inside head – sounds creepy. Also add @Styles.Render("~/Content/themes/base/css") and @Scripts.Render("~/bundles/jqueryui"). This way we included files we need to use datepicker.

Your code should like this:
 @Styles.Render("~/Content/css")
        @Styles.Render("~/Content/themes/base/css")
        @Scripts.Render("~/bundles/modernizr")
        @Scripts.Render("~/bundles/jquery")
        @Scripts.Render("~/bundles/jqueryui")


Using model for datepicker (preferred method).
To use this method we are going to create Discount model. Create a new class and call it Discount.

public class Discount
    {
        public Discount()
        {
            dateFrom = DateTime.Now.Date;
            dateTo = DateTime.Now.Date;
        }

        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        public DateTime dateFrom { get; set; }
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        public DateTime dateTo { get; set; }
        public decimal discountPercentage { get; set; }
        public string discountName { get; set; }
    }

We are using simple constructor to define default date. Date are also formatted to show only date.
Add new controller and call it Date and add new View from the controller(you can right click on the Action name and choose add View.




public ActionResult Index()
        {
            return View(new Discount());
        }



Open Index view from Date controller.

@model Components.Models.Discount
<script>
    $(function () {
        $("#dateFrom, #dateTo").datepicker();
    });
</script>
<h2>
    Date picker test</h2>
<table>
    <tr>
        <td>@Html.EditorFor(m => m.dateFrom)
        </td>
        <td>@Html.EditorFor(m => m.dateTo)
        </td>
    </tr>
</table>


In view we added class for model (Components is the name of the project, Models is the folder where we created Discount class).
As you can see we do not have to reference jquery here, as it was already referenced in Layout. In previous MVC you would have to include 3 separate files inside layout, or on the individual page (not recommended).
It would look something like that:

<script src="../../Scripts/jquery-ui-1.8.20.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
        <link href="../../Content/themes/base/jquery.ui.datepicker.css" rel="stylesheet"
            type="text/css" />

In the old MVC version if you wanted to update jquery you would have to manually change the version name to match your newest jquery, where in MVC 4 system will automatically figure it out.
Check BundleConfig.cs file again:

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

 Adding date picker without model.

@{
    ViewBag.Title = "Index";
}
@model Components.Models.Discount
<script>
    $(function () {
        $("#dateFrom, #dateTo, #datepickerNoModel").datepicker();
    });
</script>
<h2>
    Date picker test</h2>
<table>
    <tr>
        <td>@Html.EditorFor(m => m.dateFrom)
        </td>
        <td>@Html.EditorFor(m => m.dateTo)
        </td>
        <td>
            <input type="text" id="datepickerNoModel" />
        </td>
    </tr>
</table>


Main advantage using the model for datepicker is that you can very easily pass data from view to controller, where in other case you would have to formcollection.

Calling the controller with model date picker
@using(Html.BeginForm("SubmitDiscount", "Date", FormMethod.Post))
{
<table>
<tr>
<td>@Html.LabelFor(m=>m.discountName)</td>
<td>@Html.LabelFor(m=>m.dateFrom)</td>
<td>@Html.LabelFor(m=>m.dateTo)</td>
</tr>
    <tr>
        <td>@Html.TextBoxFor(m=>m.discountName)</td>
        <td>@Html.EditorFor(m => m.dateFrom)
        </td>
        <td>@Html.EditorFor(m => m.dateTo)
        </td>
    </tr>
</table>
    <input type="submit" value="Apply discount"/>
}

 We have modified View a bit and added new controller SubmitDiscount.


Run the application and go to date controller so your path should something like that localhost:9930//Date, put a break point for debugger on SubmitDiscount method. You will see that the fields we have submitted have been passed to controller via model.




Now let’s use form collection now to pass date without using the model.

Modify controller:

public ActionResult SubmitDiscount(Discount model, FormCollection form)
        {
            var date = form["dateNoModel"];
            DateTime convertDateFromString = DateTime.Parse(date);
            return RedirectToAction("Index");
        }

And view by replacing dateTo model with input.


@using(Html.BeginForm("SubmitDiscount", "Date", FormMethod.Post))
{
<table>
<tr>
<td>@Html.LabelFor(m=>m.discountName)</td>
<td>@Html.LabelFor(m=>m.dateFrom)</td>
<td>@Html.LabelFor(m=>m.dateTo)</td>
</tr>
    <tr>
        <td>@Html.TextBoxFor(m=>m.discountName)</td>
        <td>@Html.EditorFor(m => m.dateFrom)
        </td>
        <td><input type="text" id ="dateTo" name="dateNoModel"/>
        </td>
    </tr>
</table>
    <input type="submit" value="Apply discount"/>
}

Run the application and debug the method again. Choose dateTo and check your model and form.



As you can see it is faster and more reliable to use model with date picker. All elements within the form are type of string so you will have to convert them if necessary which is time consuming and can be avoided.