Date Picker and Calendar utility using pure/core JavaScript constructs

Introduction

A simple pure javascript date picker utility/script created from core javascript constructs. It is easy to use, customizable and extendable. I wrote it for my purpose without using javascript object oriented features. Later, i used the object oriented features for extendability. If you are a beginner it is better to have an idea of JS OOP. JavaScript is not object oriented. Yet, you can acheive it. The date picker object created in this script is a singleton by default. In JavaScript singleton can be acheived using object literals. Yet, there are other ways to use singleton pattern. This is one amongst the example for singleton pattern. This script works in major browsers except IE 7 and below.

Demo

             

Click on any input element above to show the calendar. Click on a date to select.
Click any where outside the calendar to close.
Use the single left and right arrows(< and >) to change months to previous or next.
Use the double left and right arrows(<< and >>) to change year to previous or next.

How to use

Download the date picker js file. Copy the css used for the demo into a css file. Create an HTML document. Include the javascript file and css file in it. Create input elements and give id's to it. For example create three input elements and give value for its id's like input1, input2, input3. Before the closing body tag include this javascript code. DatePicker.init('input1,input2,input3); Open the html document in a browser and check. Feel free to customize. If you find a glitch then kindly mention it in the comments. I will work on it and will update datapicker.js

Source Code Explanation

var DatePicker = {
	init : function(elements)
	{
        var pthat = this;
        this.element = null;
        this.date = new Date()
        this.date.setDate(1);	
        this.bod = this.newElement('div','dpbody');
        document.body.appendChild(this.bod);
        
        this.title = this.newElement('div','title');
        this.title.innerHTML = "
<<
<
-
>
>>
"; this.bod.appendChild(this.title); this.bod.appendChild(this.newElement('ul','weekdays', '
  • Sun
  • Mon
  • Tue
  • Wed
  • Thu
  • Fri
  • Sat
  • ')); this.days = this.newElement('div','dp_days'); this.bod.appendChild(this.days); this.title.onclick = function(e){ pthat.changeMonthYear(e); e ? e.stopPropagation() : event.cancelBubble = true; } this.days.onclick = function(e){ pthat.dateClicked(e); e ? e.stopPropagation() : event.cancelBubble = true; } this.setupEvent(elements); }, //... }

    var DatePicker is an object now. As it an object literal it is instantiated immediately. Objects created using object literals cannot have constructors. If you want to do initialization then do it like the init method. DatePicker.init('id-of-input-element1,id-of-input-element2,...etc...');. In the init method i do the initialization and the creation of the date picker user interface.

    init method

    setupEvent, newElement, addEvent and inputClicked methods

    I have given code samples few a functions. You shall open the datapicker.js to refer the source of all the method.

    setupEvent method

    This method will set onclick event listeners to the input elements. Input elements id's are passed to this function from init function as comma seperated string value. addEvent method is a cross browser code to add event listeners to html elements.

    newElement method

    The newElement method is self explanatory. It creates a new html element with the first parameter. 2nd and 3rd parameters are optional. 2nd parameter is to specify an existing css class name and the 3rd parameter is to specify an html content as inner html. So, this method creates a new element, assigns the css class name to that element and will assign the inner html to the newly created element.

    addEvent method

    addEvent method is written for cross browser compatibility. There are two functions to consider. One is the addEventListener function which works in browsers that supports W3C standards and the other is attachEvent function which works in Internet Explorer. The addEventHandler function takes three arguments were as attachEvent takes only two. The first two parameters in both the functions are same. Its the type of the event and the callback. The last parameter of addEventHandler is of type boolean. It is to specify whether the event handlers should be invoked in the bubbling phase or in the capturing phase. True for bubbling phase and false for capturing phase. The default is true. IE supports only event bubbling. So, no need for a third parameter. Here is a best explanation on event registration in javascript. And here is the first page of this series Intro to javascript events. One amongst the best resource in the internet on javascript events.

    inputClicked method

    In the callback of the addEvent i have called inputClicked method. This method is called when a click event occurs on an input element for which the date picker should be shown. Any event listener callback will receive an event object as a parameter in which the source element and the event properties are available. In Internet Explorer the current event object is a global variable and can be accessed using window.event. getEventTarget function is a cross browser code to get the element on which the click event occured. It checks whether the browser is w3c complaint or IE. According to that the event object is returned. After that the date picker UI is displayed in showCalendar function. addCloseListener is setup to close the datepicker when the user clicks anywhere outside of the datepicker.

    showCalendar and addCloseListener methods

        showCalander : function()
        {
            var dow = this.date.getDay(); //day of week from (0-6) on 1st of the month. 0=sun, 1=mon, 2=tue, etc.
            var ndays = (new Date(this.date.getFullYear(), this.date.getMonth() + 1, 0)).getDate(); //no of days in the month.	
            
            var temp = this.date.toDateString().split(' ')
            this.title.childNodes[2].innerHTML = temp[1] + ' - ' + temp[3];
            
            this.days.innerHTML = '';	
            
            for(var i = -dow ; i < ndays; i++)
            {
                temp = this.newElement(i<0?'span':'div','',' ');
                this.days.appendChild(temp);
                if(i>-1)temp.innerHTML = i+1;
            }
    
            var pos = this.findAbsolutePosition(this.element);	
            this.bod.style.left = pos[0] + this.element.offsetWidth + 5 + 'px';
            this.bod.style.top = pos[1] + 'px';	
            this.bod.style.display = 'block';
        },
    	
        addCloseListener : function(e)
        {
            var pthat = this;
            
            pthat.closeHandler = function(e){
                e = pthat.getEventTarget(e)
                if(e!==pthat.element && pthat.bod.style.display == 'block')
                    pthat.hideCalander();
            }        
            
            pthat.removeEvent(document, 'click', pthat.closeHandler);
            pthat.addEvent(document, 'click', pthat.closeHandler)
        }	
    
    When you click on an input element the showCalendar method is invoked. The calendar user interface is created and is made visible. The current month and year is displayed in the element div.title span. Let us see step by step.
    
    Line 3, variable dow will hold the weekday day number for 1st day of the month. In this calendar the weekdays are written starting from Sunday. Consider that 1st of the month falls on Wednesday then day number for Sunday, Monday, Tuesday should be empty. The day numbering from 1 to 30/31 should start from Wednesday. So, the variable dow will hold for how many days it should skip day numbering. In our example it is 3 days(sun, mon and tue). So, for the first row of day numbering the first three boxes will be empty. The first 3 boxes represents the previous months last 3 days. They also mean that the first of the current month doesn't fall on Sunday or Monday or Tuesday.
    
    In the next line 4, the variable ndays will hold the number of days in a month. It will be either 30 or 31 and for February it will be 28. 29 in case of a leap year. In line 6,7 display the current month and year in the element div.title span. Line 11. For loop runs for ndays + dow. var i starts with -dow.
    
    Line 13,14,15  For (dow) many days i insert an empty span tag with no click event. Empty span tags represents the previous months dates. temp = this.newElement(i<0?'span':'div','',' '); When i < 0 an empty span tags are inserted else div tags with numbers 1 to 30/31. To distingush between previous month dates and the current month i had used span tags and div tags respectively.  
    
    Line 18-21: The calendar is ready with dates. It has to be displayed next to the input element on which the click event occured. To show the calendar next to the input element we need to find the absolute position of the input element. the findAbsolutePosition function is used to do that. This function returns the x,y position of the input element as an array. We can display the calendar in x'th position or a bit right so that it will not hide the input element. Now, the calendar is visible.
    
    When the user clicks a date(div numbered 1 to 30/31) the event is bubbled up to its parent(dp_days) as there are no event listeners added to divs with date numbers. Since dp_days has an event listener(dateClicked function) it will be called with an event object as parameter. The event object will hold a reference to the element which is clicked. With that reference the value of the div can be retrieved. Using that the input element is populated with the selected date with current month and year. I did not provide an option to change the date format. You can do it yourself.

    In hideCalendar function and in addCloseListener function i have called remove event before adding an event. The reason is to remove an existing events if present. It is to prevent multiple event handlers for a given element. Removing a non existant event listener will not throw any error.

    Download Source Code

    Right click and select save target as or save link as to download date picker.
    Click here to download Date Picker


    That is all folks. Enjoy.

    By -

    Comments, Suggestions, Objections, ...