Bootstrap Advanced Date Picker Plugin
For some time now I've been creating date fields in Bootstrap-based websites that look like this:
Clicking either in the field or on the button next to it launches a date-picker, like this:
In the Notes Form the Date Field is configured in such a way that it accepts dates in the format 12-Dec-2009 (while storing them in normal Notes DateTime format of course).
The field properties are like so:
It all works well and users like them. Not least because there's no confusion over whether it's mm/dd or dd/mm! When the document is viewed in read-mode the dates are displayed in the same format automatically!
The only downside is that the field is marked up as "readonly" to prevent users trying to type in their own dates, which forces them to use the picker. Ok for most, but if you want to pick a date 10 years ago....
I'm assuming you're using Domino, but this is by no means restricted to use only with Domino.
Taking it Further
I was asked recently if a certain date field could be extended to add the ability for a user to choose from a list of predefined date ranges. Such as "A year from now" or "3 months from now".
Such is the beauty of bootstrap that I was soon able to extend my date field by creating a plugin that adds extra button, as below:
When clicked on, it looks like this:
Happy days!
How Did I Do It?
Creating the basic date picker is a simple case of marking it up like this:
<div class="input-append"> <input name="DOB" id="DOB" rel="date" type="text" readonly="readonly"> <button class="btn" onclick="$('#DOB').focus()"><i class="icon icon-calendar"></i></button> </div>
Then at the bottom of the page (or better still, in an "form.init()" function called on "dom ready") do this:
$(function() { $("input[rel='date']").datepicker({dateFormat: "dd-M-yy"}); });
This code looks for all fields where rel="date" and binds the jQuery UI date picker to it.
Hey presto.
Advanced Version
To make the version with the additional dropdown, the HTML markup for the field changes to something like this:
<div class="input-append"> <input name="DateExpected" value="" id="DateExpected" rel="date" type="text" class="span2" readonly="readonly"> <div class="btn-group"> <button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button> <ul class="dropdown-menu month-adder" role="menu"> <li data-increment="1"><a>In One Month</a></li> <li data-increment="3"><a>In 3 Months</a></li> <li data-increment="6"><a>Within 6 Months</a></li> <li data-increment="12"><a>In a year</a></li> </ul> <button class="btn"><i class="icon icon-calendar"></i></button> </div> </div>
It should be obvious from that HTML how it all works. Maybe it's obvious to me as I'm au fais with Bootstrap?
Turning It In To A Plugin
While the HTML markup needed to wrap round a field to make it a datepicker isn't complicated you can imagine it's a bit of a pain to markup lots of date fields. What we really need is a plugin.
To create a plugin you'd simply add the following code in to your main "application.js" file:
(function( $ ) { $.fn.datePicker2 = function(options){ var settings = $.extend({ dateFormat: "dd/mm/yy" }, options ); this.datepicker({dateFormat: settings.dateFormat}) //Initiate the datepicker .attr("readonly",true) //Make the field itself readonly! .wrap('<div class="input-append" />') //wrap it in all a div .after($('<button class="btn"><i class="icon icon-calendar" /></button>') //add a button after the field .click(function(){$(this).closest('.input-append').children().first().focus()})); //Bind a click even to it }; }( jQuery ));
Now, you don't need to wrap the date fields in any HTML. You just specify rel="date" and call change the previous "on load" event to this:
$(function() { $("input[rel='date']").datePicker2({dateFormat: "dd-M-yy"}); });
We're now using our own new jQuery plugin which does all the HTML markup for us.
Here's the code for the plugin which takes it further and adds the dropdown of "1 month", "1 year" etc.
(function( $ ) { $.fn.dateSelector = function(options){ var settings = $.extend({ dateFormat: "dd-M-yy" }, options ); this.parent().children().last() .wrap($('<div class="btn-group" />')) .before('<button class="btn dropdown-toggle" style="border-radius:0 !important;" data-toggle="dropdown"><span class="caret"></span></button>') .before( $('<ul class="dropdown-menu month-adder" role="menu"><li data-increment="1"><a>In One Month</a></li><li data-increment="3"><a>In 3 Months</a></li><li data-increment="6"><a>Within 6 Months</a></li><li data-increment="12"><a>In a year</a></li></ul>') .on('click', 'li', function(){$(this).closest('.input-append').children().first().val(new Date((new Date().setMonth(new Date().getMonth()+$(this).data('increment')))).toUTCString().substring(5,16).replace(/ /g,"-"))}) ); }; }( jQuery ));
A Demo
You can see it in use in this "fiddle".
Taking it further Still
It's far from perfect. For a start the JavaScript is messy and could do with being re-factored. But also, it would be nice to have options like "in 2 days", "in 3 weeks" etc. And to be able to specify different or additional options on a per-field basis.
For now though, it'll do. Hope you like.
Way back in the beginning of 2006 I created a date input module for the web that allowed you to type in text like "next tue" and it would convert to a date. At the time I was tasked with helping our Notes group make everything web. This was hard for some programmers because at the time Notes web pages didn't have much in the way of validation. A date field in the client had all the attributes of a date field while on the web it was a text field. I started with Simon Willison's "A better way of entering dates", fixed a few bugs and added more date output formats. You can find the instructions here.
http://tanny.ica.com/ica/tko/tkoblog.nsf/dx/date-input-and-calendar-popup-instructions
And the code here.
http://tanny.ica.com/ica/tko/tkoblog.nsf/dx/date-input-and-calendar-popup
The drop down calendar and date text modules are separate. You are welcome to use the text code to enhance your date code.
Reply
Very nice, Jake. I spotted it on your twitter feed at the beginning of the week and shared it around to my colleagues here (to typical silence). Nice usability feature and surprisingly little code in that fiddle - that's what surprised me most.
Reply
Very cool Jake. you always have such excellent little tricks that make things just that much better!
Reply
Here's a nice bootstrap form component that allows the user to select a time as well as a date. It also translates using I18N.
http://www.malot.fr/bootstrap-datetimepicker/
Reply
Brilliant! I love it.
Reply