A Popup DatePicker
by Peter Higgins

One commonly requested feature of Dijit is to allow a DateTextBox to contain a clickable image outside of the input that triggers the popup _Calendar class to display, rather than display when the element is focused. It opens up countless levels of complication internally: design consideration, a11y states, etc. But the concept is really quite simple, and even easier to implement. Shall we?

In this brief Dojo 1.2+ tutorial, we’re going to walk through the steps needed to make a dojo.query “plugin” that will add the desired behavior to any input that accepts a .value assignment. The end result will be a simple API:


The addPicker method will add an icon after each of the matched input’s with class=”wantingACalendar”, wire the click events, and manipulate a shared instance of a Calendar. (In this example we’ll use the DojoX Animated Clander from Shane O’Sullivan: dojox.widget.Calendar) We will be using a shared instance of a Calendar for all inputs, as you can really only be acting on one input at a time, at least in this UI pattern.

Start with a skeleton HTML page, including Tundra, DojoX Calendar CSS, and dojo.js:

	<title>Sample Dojo / Dijit Page</title>
	<!-- a Dijit theme, and Calendar CSS: -->
	<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.2/dijit/themes/tundra/tundra.css" />
	<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.2/dojox/widget/Calendar/Calendar.css" />
	<!-- load Dojo -->
	<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.2/dojo/dojo.xd.js"></script>
<body class="tundra">
   <label for="foo">Select A Date:</label><input id="foo" name="foo" type="text" />

This won’t do anything just yet, but sets the page up perfectly for us. The rest of our code will code in a single <script> tag immediately following the dojo.js script tag. We’ll require the Calendar code, and register an addOnLoad function to execute when the required resources are solved:

<script type="text/javascript">
    // plugin code goes in here

The rest of this JavaScript goes inside the addOnLoad function. The first thing to do would be to create the plugin method by extending dojo.NodeList:

dojo.extend(dojo.NodeList, {
      addPicker: function(){
            // plugin code goes in here.
            return this; // dojo.NodeList

We’ve added a method to dojo.NodeList called addPicker, but it doesn’t do anything yet except for the “most important part” … by returning ‘this’ from our method, we allow ‘chaining’ to continue, so you can call other dojo.NodeList methods (like .removeClass) after using the .addPicker() method.

The .addPicker code needs to create an image for each of the matched elements in the NodeList. For that we can use .forEach (another NodeList method). The code path is relatively straightforward:

dojo.extend(dojo.NodeList, {
	// the guts of the "plugin"
	addPicker: function(args){
			// add an image after the input we're targeting for clickage
			var img = dojo.doc.createElement('img');
			dojo.attr(img, {
				// change this to something better:
				style:{ cursor:"pointer" }
			dojo.place(img, n, "after");
			dojo.connect(img, "onclick", function(e){
				// tell popup which node to send onChange value to
				calendar._pushChangeTo = n; 
				// and open the popup below the targeted input
					popup: calendar,
					around: n
		return this; // dojo.NodeList

We create an img variable (a DomNode), give it attributes with dojo.attr, place it after our target node (n) with dojo.place, and call dojo.connect to register the onclick. The magic happens inside the onclick function, and if you were paying attention you noticed we’re referencing an undefined variable ‘calendar’ in two places. Once to store as a reference to the associated input on the ‘calendar’ object, and again in the dijit.popup.open function. This ‘calendar’ variable is our (thus far) uncreated DojoX Calendar instance we plan to share between inputs. We should make that now, immediately before the dojo.extend() call:

// create a new instance of a Calendar
var calendar = new dojox.widget.Calendar({
	onChange: function(val){
		// when the value changes, hide the popup 
		// and set a value to our input 
		console.log(val, typeof val);
		this._pushChangeTo.value = dojo.date.locale.format(val);
	destroy: function(){
		// avoid leaving a ref in object for IE?
		delete this._pushChangeTo;

So we create a single Calendar instance we can reference as ‘calendar’ within this addOnLoad function. The two functions we’re including here are onChange and destroy. The destroy is simply there to cleanup the node reference that is stashed on the Calendar as part of the icon’s onclick function (calendar._pushChangeTo = n), and may not truly be necessary. Good to be safe.

The onChange function simply closes the popup, and set’s the .value property of the _pushChangeTo node (populated onclick of the icon, remember) using dojo.date.locale to format the date into something pretty.

And that’s it. Simply locate the input(s) you wish to make datepickers, and run the command:


This of course can use a plain dijit._Calendar, or any of the various mix and matches of DojoX Calendars available, and could easily be extended into allowing special formatting on the input value. This is left as an exercise to you, reader.

Worth noting: As of Dojo 1.3 there is a dojo.create function, which could reduce the code to create the image and register the onclick to:

dojo.create("img", { 
 	style:{ cursor:"pointer" },
	onclick: function(e){
		calendar._pushChangeTo = n; 
			popup: calendar,
			around: n
}, n, "after");

… if that fits your coding style. Happy Dojo’ing.

Tags: , ,

This entry was posted on Tuesday, January 6th, 2009 at 4:48 pm and is filed under Dojo Cookies. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

8 Responses to “A Popup DatePicker”

  1. luke Says:

    I’m new to dojo and can’t get this to work. Are you able to post up a demonstration page so I can look at the source code how it should be when all together? This tutorial is appreciated, but the way it is written is utterly confusing as there seem to be blocks of code that are later discarded, or moved above, or below, or inbetween, a previous block of code.

  2. luke Says:

    ooop, dunno what I’ve done but it works now. Will post up a link once I’m happy with it.

  3. sos Says:

    > of course can use a plain dijit._Calendar….

    Sure, but it wouldn’t be nearly as pretty as that sexy DojoX calendar :-)

  4. dante Says:

    @sos - how very true :)

    @luke - I agree. It all is in order except the block about making the calendar variable, which I decided was better to describe after setting up the onclicks. That block is the only one that goes “before” any previous step. I tried to attach the full working example, but couldn’t figure out how :/ Go figure. I’ve put it on my sandbox though:

  5. sos Says:

    A couple of suggestions:

    1. Make the calendar disappear when the user clicks outside the calendar - an onclick handler on the body should do it.

    2. Provide an example where the image is already there. In many corporate environments (including mine) the HTML for the image already exists as other code is already used to provide a different date picker. It also makes automated testing easier if the Java (or Php/whatever) creates as much of the HTML as possible. So, an example that uses an existing image would be good.

  6. sos Says:

    one more thing - it’s better to use onValueSelected instead of onChange - otherwise clicking on month and year values also closes the calendar, when they shouldn’t

  7. dante Says:

    @sos - Great suggestions! I added an updated version incorporating the onValueSelected change as well as a backwards-compatible (wrt to this cookie) to specify that a particular input already has an icon, though is out of the scope of this particular cookie.

    preview: http://dante.dojotoolkit.org/static/calendar-icon-2.html

    Though extending this to handle the body.onclick closing and reading the value from the node seem like good option, but we’re going to get into API discussions and bikesheds at some point. “Exercise to the reader” — I encourage you to write a followup cookie, or better yet - full length tutorial.

  8. cs44 Says:

    Really like this one. Love the extension on NodeList, always useful! Thanks!

Leave a Reply

You must be logged in to post a comment.