Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / jQuery

Creating a Professional Looking Calendar Control using jQuery

4.50/5 (3 votes)
24 Jan 2014CPOL3 min read 21K  
How to create a professional looking Calendar control using jQuery

One of the most used controls in a web page is the Calendar control. I’m sure you have seen so many and irritating ones as I have. Let’s see how to create a professional calendar control using jQuery and JavaScript.

calendar

As with any other control development, we start with plain HTML. We can render this from server, taking into account the locale of the user request, however, that concept is outside the scope of this article.

The HTML Part

We’re going to create one div that will serve as the container, then 3 divs inside, header, body and footer.

HTML
<div class="mopCalendar">
	<div class="mopCalendarHeader"></div>
	<div class="mopCalendarBody"></div>
	<div class="mopCalendarFooter"></div>
</div>

Header

For the header, we need 4 buttons, and one label to display the current month, so we write the markup accordingly, inside our header div.

HTML
<div class="mopCalendarBtnFirst"> </div>
<div class="mopCalendarBtnPrevious"> </div>
<div class="mopCalendarMonth"> </div>
<div class="mopCalendarBtnNext"> </div>
<div class="mopCalendarBtnLast"> </div>

Body

For the body, we’re going to write a table that will show the days. We could write this table using JavaScript, but for easing purposes, we put the markup directly.

HTML
<table style="width:100%;">
	<thead>
		<tr>
			<th class="mopCalendarDayRed">Sun</th>
			<th>Mon</th>
			<th>Tue</th>
			<th>Wed</th>
			<th>Thu</th>
			<th>Fri</th>
			<th class="mopCalendarDayRed">Sat</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
		</tr>
		<tr>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
		</tr>
		<tr>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
		</tr>
		<tr>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
		</tr>
		<tr>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
		</tr>
		<tr>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
			<td> </td>
		</tr>
	</tbody>
</table>

The table basically contains a header, with the day names. The mopCalendarDayRed style displays the weekend days with red forecolor. Then we have 7 rows, to display the whole month. Don’t worry about the styles, we’ll take care of that later.

Footer

The footer is the easiest one. We’ll have two buttons, one to clear the selected value and another to set current date. We place these buttons inside our footer div.

HTML
<button class="mopCalendarBtnToday">Today</button>
<button class="mopCalendarBtnClear">Clear</button>

That’s all! We have the HTML markup ready.

JavaScriptize It!

We will follow jQuery pattern for plug in authorize, so we start with the following skeleton:

JavaScript
(function($)
{
    //global properties, depending on current language
    var MonthNames = ['January', 'February', 
    'March', 'April', 'May', 'June', 
                      'July', 'August', 'September', 
                      'October', 'November', 'December'];
    var FirstDayOfWeek = 0;

    $.fn.mopCalendar = function(initialDate)
    {
        var $this = $(this);
        var selectedDate = initialDate || new Date();
        var selectedMonth = selectedDate.getMonth();
        var selectedYear = selectedDate.getFullYear();

        return this.each(function()
        {
        });
    };

} (jQuery));

We name our plug in mopCalendar, and we set several global properties for our plug in, like the month names and the first day of week. We can set this up accordingly to the current user language.

GetValue and SetValue functions:

JavaScript
var getValue = function()
            {
                return selectedDate;
            };

            var setValue = function(date)
            {
                if (date == null)
                {
                    selectedDate = null;
                    return;
                }

                selectedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
                selectedMonth = getMonth();
                selectedYear = getYear();
                refreshMonthTitle();
                refreshDayTable();
            };

We start setting different variables, that will hold current selected date, month and year. Also, the getValue functions return the currently selected date, and the important piece, setValue function, will update selected date, and also will call the refresh functions we’re going to describe next.

JavaScript
var getDay = function()
            {
                return selectedDate.getDate();
            };

            var getWeekDay = function()
            {
                return selectedDate.getDay();
            };

            var getMonth = function()
            {
                return selectedDate.getMonth();
            };

            var getYear = function()
            {
                return selectedDate.getFullYear();
            };

            var setSelectedMonth = function(monthNum)
            {
                if (monthNum == -1 && selectedMonth == 0)
                {
                    selectedYear--;
                    selectedMonth = 11;
                }
                else if (monthNum == 12 && selectedMonth == 11)
                {
                    selectedYear++;
                    selectedMonth = 0;
                }
                else if (monthNum >= 0 && monthNum <= 11)
                    selectedMonth = monthNum;
                else
                    return;

                refreshMonthTitle();
                refreshDayTable();
            };

            var setSelectedYear = function(yearNum)
            {
                selectedYear = yearNum;
                refreshMonthTitle();
                refreshDayTable();
            };
            var getContentTable = function () {
                return $this.find('table');
            };

We continue with the supporting functions, that quickly return us the current day number, week day, month, etc., from the selected date. Also, the setSelectedMonth and setSelectedYear will help us when the different buttons are clicked. Notice the two important functions we’re going to describe, refreshMonthTitle and refreshDayTable.

JavaScript
var refreshMonthTitle = function()
            {
                var monthTitle = $('.mopCalendarMonth').text(MonthNames[selectedMonth] + 
                                 ', ' + selectedYear);
            };

            var refreshDayTable = function () {
                var table = getContentTable();
                var month = selectedMonth;
                var year = selectedYear;

                var startd = new Date(year, month, 1);
                var d1 = FirstDayOfWeek;
                var d2 = startd.getDay();
                var diff = d1 < d2 ? d2 - d1 : d1 + 7;
                startd.setDate(startd.getDate() - diff);

                for (var j = 1; j < 7; j++) {
                    var row = table[0].rows[j];
                    for (var i = 0; i < 7; i++) {
                        var dy = startd.getDate();
                        var wd = startd.getDay();
                        var md = startd.getMonth();
                        var cell = $(row.cells[i]).text(dy);

                        cell.removeClass();
                        if (startd.valueOf() == selectedDate.valueOf())
                            cell.addClass('mopCalendarDaySelected');
                        else if (md != month)
                            cell.addClass('mopCalendarDayOdd');
                        else if (wd == 0 || wd == 6)
                            cell.addClass('mopCalendarDayRed');

                        dy++;
                        startd.setDate(dy);
                    }
                }
            };

refreshMonthTitle function is pretty straightforward. It basically updates the month title with the current selected month.

The most important function is refreshDayTable. This function cleans the whole table and updates it with the month days, drawing also the last days from the previous month and the first days of the next month, all of them in gray color. Also, if the week day is Sunday or Saturday, the color will be red. The trick here is knowing which is the very first day to start with, then it’s a simply add one more until all rows and cells have been drawn.

Put Those Buttons to Work!

And the final part is making the buttons to give some interactivity, so our super Calendar control will be finished.

On Header Click

We attach a single click event to the whole header, and then depending on the target, we’ll know which section the user has clicked on. Depending on that, we call one function or the other.

JavaScript
var onHeaderClick = function(e)
            {
                if (e.target)
                {
                    var target = $(e.target);
                    if (target.hasClass('mopCalendarBtnFirst'))
                        setSelectedYear(selectedYear - 1);
                    else if (target.hasClass('mopCalendarBtnPrevious'))
                        setSelectedMonth(selectedMonth - 1);
                    else if (target.hasClass('mopCalendarBtnNext'))
                        setSelectedMonth(selectedMonth + 1);
                    else if (target.hasClass('mopCalendarBtnLast'))
                        setSelectedYear(selectedYear + 1);
                }
                return false;
            };

On Body Click

The same for the days. In this case, we only care if user clicks on a cell, so we update the selected day.

JavaScript
var onBodyClick = function(e)
            {
                if (e.target && e.target.tagName == 'TD')
                {
                    var rowIndex = e.target.parentElement.rowIndex;
                    var month = selectedMonth;
                    var year = selectedYear;
                    var day = parseInt($(e.target).text());

                    if (rowIndex <= 1 && day >= 20)
                        month--;
                    else if (rowIndex >= 5 && day <= 15)
                        month++;

                    setValue(new Date(year, month, day));
                }
            };

On footer Click

And our footer buttons, to set the current value to either current date or empty value.

JavaScript
var onFooterClick = function(e)
            {
                if (e.target && e.target.tagName == 'BUTTON')
                {
                    var $target = $(e.target);
                    if ($target.hasClass('mopCalendarBtnToday'))
                        setValue(new Date());
                    else if ($target.hasClass('mopCalendarBtnClear'))
                        setValue(null);
                }
                return false;
            };

To attach the events, we have used this:

JavaScript
$('.mopCalendarHeader').on('click', onHeaderClick);
            $('.mopCalendarBody').on('click', onBodyClick);
            $('.mopCalendarFooter').on('click', onFooterClick);

            //disable drag
            $this.on('selectstart dragstart', function (e) { e.preventDefault(); });

And finally, public function access and auto-set to the received initial date:

JavaScript
this.setValue = (function (value) {
                setValue(value);
            })(initialDate);

To start with, simply put the initialization on our HTML page:

JavaScript
<script type="text/javascript">

        $(document).ready(
            function()
            {
                $(".mopCalendar").mopCalendar(new Date());
            }
        );
    
    </script>

That’s all! You can download the attached source code, which contains the CSS used as well.
Thanks for reading!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)