Home / AJAX

How Do I Create a Popup Datepicker?

RSS
Modified on 2010/08/18 01:13 by James Chambers Categorized as Uncategorized

Problem

I want an easy way to add popup datepicker functionality to my site, and I would like it to share the same look-and-feel as the other components on an ASP.NET MVC view. How do I make this happen?

Solution

If you're already using jQuery and the jQuery UI library you're in luck. Not only is it easy to implement, but it's also part of the themeable components in jQuery UI. Not using jQuery yet? Why not get started?

Up-And-Running Quickly

It doesn't take much to get this running: you need an input of type text and a single line of script. Your HTML will look like this:
<input type="text" id="simple-date" />

And your corresponding JavaScript will be as follows:
// the jQuery ready shortcut
$(function () {
    // set up our datepicker
    $("#simple-date").datepicker();
});

All we've done here is use the CSS-style selection for identifying a DOM element with the ID of simple-date. This returns our text box, to which we apply the datepicker.

Try Me!

The default options are a great start, but not every page is going to work the same and you need some level of control over how this component behaves. No worries, mate, you're just an options block away from success! All you need to do is modify the code to pass in the options you wish to override. For instance, if you wanted to show two months at a time and allow users to pick the year, you would update the call to datepicker as follows:
$("#simple-date").datepicker({
    numberOfMonths: 2,
    changeYear: true
});

Image

And, as with all jQuery UI components, you can take advantage of the many themes available to jQuery UI. See this article in the series for more information on themes.

Integration with ASP.NET MVC

Let's get moving with the MVC Framework, now. First off, keep in mind that any of your models will, by default, be rendered as text inputs when you use the view templating from your controller. Let's say you've got a simple GameInformation class:
public class GameInformation
{
    public string HomeTeam { get; set; }
    public string AwayTeam { get; set; }
    public string FieldName { get; set; }
    public DateTime GameDate { get; set; }
}

We add a controller action that allows people to create a new game, and we default the date to tomorrow.
public ActionResult CreateGameInformation()
{
    GameInformation gi = new GameInformation { GameDate = DateTime.Now.AddDays(1) };
    return View(gi);
}

By right-clicking anywhere in the method we bring up a context menu that allows us to add a view.

Image

We select options for the view, making it strongly-typed for the GameInformation class and setting the View Content to Create. This builds us a quick-and-dirty view with a series of text inputs. The portion representing the DateTime looks like this:
<div class="editor-label">
    <%: Html.LabelFor(model => model.GameDate) %>
</div>
<div class="editor-field">
    <%: Html.TextBoxFor(model => model.GameDate) %>
    <%: Html.ValidationMessageFor(model => model.GameDate) %>
</div>

We have two options to light up the datepicker at this point, the first is simply taking advantage of how the ASP.NET MVC Framework renders our model. A property named GameDate has a client ID of GameDate on the view, making it easy to incorporate the jQuery UI datepicker:
$("#GameDate").datepicker({
    defaultDate: new Date($(this).val()),
    changeMonth: true,
    changeYear: true
});

Image

Excellent. You can see that our default date is populated and we've got a slick, themeable interface. We're a lot closer to cool, but we're still a ways away. Let's take it up a notch here and do some real MVC-ish stuff.

Power Tip: Leveraging MVC Well-Known Folders

The MVC Framework provides a good, wide brush for getting the basic elements of our models rendered out with a single stroke. This gives us a quick start, but also a solid canvas for us to paint things the way we'd like them to appear. Enter: known folders.

Jump into your Views -> Shared folder in your project, and create a folder called EditorTemplates where we'll override the way the dates are rendered. To do this, we create a partial view called DateTime.ascx and make it strongly-typed to DateTime. In our case, we don't care about the time portion of the DateTime, so we'll axe that off by formatting the date. The entire editor template can be created as follows:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime>" %>
<%=Html.TextBox("", Model.ToShortDateString()) %>

Finally, we need to make a simple change to the auto-generated template to use the helper method EditorFor:
<div class="editor-label">
    <%: Html.LabelFor(model => model.GameDate) %>
</div>
<div class="editor-field">
    <%: Html.EditorFor(model => model.GameDate) %>
    <%: Html.ValidationMessageFor(model => model.GameDate) %>
</div>

It's a subtle change, but rather than just putting a text box on the view, it directs the MVC Framework to go to that EditorTemplates folder to look for hints on how to build the user interface.

Here's how it looks in the end:

Image

Now that may seem like a bit of work for simply knocking the time off the back end of that, but now we'll never have to do it again for any of the views in our site.

Try Me!

Controller to Client and Back Again with Datepicker

Here's another scenario for you: a view you've created needs to allow the user to select a single date from a range. It might be for a flight ticket, a reservation at a golf course, or the preferred date for a family supper at Aunt Martha's.

Image

When users click on the RSVP button, they are taken to a page where they see how others have indicated their preference.

Image

Let's get that RSVP form all gussied up and add our jQuery UI datepicker, complete with options set for limiting the dates the user is allowed to pick.
var mindate, maxdate, eventid;

mindate = $("#event-min-date").val(); maxdate = $("#event-max-date").val(); eventid = $("#event-id").val();

$("#SelectedDate").datepicker( { minDate: mindate, maxDate: maxdate } );

What we're doing here is extracting our min and max values from some DOM elements and passing those in to the options for datepicker. We could've just written the values into those vars as we write out the page, but let's side bar for a minute...

Power Tip: Referencing Model Values in JavaScript

Listening to best practices will mean putting your JavaScript - including your jQuery scripts - in files external to your web pages. You'll still need to reference data in the model, however, so it's a good idea to stuff that data into hidden inputs on your form.
<input type="hidden" id="event-id" value="<%: Model.EventId %>" />
<input type="hidden" id="event-min-date" value="<%: Model.EarliestDate %>" />
<input type="hidden" id="event-max-date" value="<%: Model.LastestDate %>" />

While we could've used <%: Model.SomeDate %> and written the model values directly to the script, we'd be losing out on an opportunity to break the code out of the page into it's own file.

Sending the Data Back to the Controller

Our user's now entered their name and selected their date and we want to POST the data back to an action on our controller. We'll create a click event handler for our RSVP button and extract the values for the name and date. Next, we'll use the jQuery.post() Ajax method to bundle up the data.
$("#rsvp-button").button().click(function () {

var familyMemberName = $("#FamilyMemberName").val(); var selectedDate = $("#SelectedDate").val();

$.post( 'AddFamilyMemberConfirmation', { EventId: eventid, FamilyMemberName: familyMemberName, SelectedDate: selectedDate }, // our success event anon handler function (data) { $("#rsvp-responses").append('<li><b>' + data + '</b></li>'); $("#rsvp-area").html('Thank you for RSVPing to the event!'); } ); });

We're calling a controller action called AddFamilyMemberConfirmation, and it's expecting a complex type, FamilyMemberConfirmation, which looks a little like this:
public class FamilyMemberConfirmation
{
    public int EventId { get; set; }
    public string FamilyMemberName { get; set; }
    public DateTime SelectedDate { get; set; }
}

Finally, our method to handle the POST would process the confirmation and send a message of sorts back to the client:
[HttpPost]
public ContentResult AddFamilyMemberConfirmation(FamilyMemberConfirmation confirmation)
{
    //int EventId, string FamilyMemberName, 
    // save the confirmation to the database, such as
    // _repository.AddEventConfirmation(confirmation);
    
    string result = string.Format("{0} has picked {1}", 
                                    confirmation.FamilyMemberName, 
                                    confirmation.SelectedDate.ToString("MMM d yyyy"));
    return Content(result);
}

Whew! It might seem a little complicated, but it's much easier to digest if we consider the basic steps required:
  • Save any model values we need to access from JavaScript in some hidden form fields
  • Apply datepicker() to our date fields
  • Create a button handler that POSTs data to our controller

Try Me!

Wrapping Up

There's no need to reinvent the wheel when it comes to creating a good-looking control that allows users to select a date. The jQuery UI library provides a simple way to jazz up our interface and deliver a solid experience to the end user while maintaining compatibility with ASP.NET MVC.

About the Author

James Chambers is a Senior Software Developer in Canada, where he keeps several dental surgeons employed due to his hockey exploits. His development passions are fueled by new tech, new tools and mentoring others. Follow his coding adventures at Mister James.
  Name Size
- event-list.PNG 88.97 KB
- event-rsvp.PNG 43.56 KB
- gamedate-lessugly.PNG 32.07 KB
- gamedate-ugly.PNG 39.96 KB
- mvc-contextmenu.PNG 31.23 KB
- simple-2up.PNG 58.62 KB