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.
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 div
s inside, header
, body
and footer
.
<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
.
<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.
<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
.
<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:
(function($)
{
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:
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.
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
.
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.
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.
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.
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:
$('.mopCalendarHeader').on('click', onHeaderClick);
$('.mopCalendarBody').on('click', onBodyClick);
$('.mopCalendarFooter').on('click', onFooterClick);
$this.on('selectstart dragstart', function (e) { e.preventDefault(); });
And finally, public
function access and auto-set to the received initial date:
this.setValue = (function (value) {
setValue(value);
})(initialDate);
To start with, simply put the initialization on our HTML page:
<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!
CodeProject