The following is the follow up to the ever so popular Coding a Calendar in JavaScript, in which I created a calendar widget in JavaScript.
SUN
MON
TUE
WED
THUR
FRI
SAT
Before you continue with this post, you should head on over to that post and get familiar with that process as I will be using the same code to render the following.
I will be continuing the implementation by allowing users to select multiple days, both by clicking on date regions and by dragging multiple dates at once.
1. New variables
We are going to need to add the following new variables to the calendar script.
var selectedDays = new Array();
var mousedown = false;
The selectedDays array will be used to keep track of the currently selected dates on the calendar and the mousedown boolean expression will be used to monitor the current state of the mouse. Essentially, we want to know if we are currently mid-drag or not, for when selecting multiple days.
2. Single Day Selection
Let's begin by allowing your users to select single days on the calendar, which is most often than not the most required feature for any online calendar. The following is the loadCalendarDays() function from part 1. It has 2 new additions that you will need to make, and those are adding a new dataset to the 'day' div, to make it simpler to retrieve the selected date. And we will be adding the click event handler, that will take care of adding/removing the selected date from the selectedDays array.
function loadCalendarDays() {
document.getElementById("calendarDays").innerHTML = "";
var tmpDate = new Date(year, month, 0);
var num = daysInMonth(month, year);
var dayofweek = tmpDate.getDay(); // find where to start calendar day of week
for (var i = 0; i <= dayofweek; i++) {
var d = document.createElement("div");
d.classList.add("day");
d.classList.add("blank");
document.getElementById("calendarDays").appendChild(d);
}
for (var i = 0; i < num; i++) {
var tmp = i + 1;
var d = document.createElement("div");
d.id = "calendarday_" + tmp;
d.className = "day";
d.innerHTML = tmp;
d.dataset.day = tmp; // easier to retrieve the date
/* ****************** Click Event ********************** */
d.addEventListener('click', function(){
this.classList.toggle('selected');
if (!selectedDays.includes(this.dataset.day))
selectedDays.push(this.dataset.day);
else
selectedDays.splice(selectedDays.indexOf(this.dataset.day), 1);
});
/* **************************************************** */
document.getElementById("calendarDays").appendChild(d);
}
var clear = document.createElement("div");
clear.className = "clear";
document.getElementById("calendarDays").appendChild(clear);
}
Let's take a look at the click event in more detail. Essentially, we're adding or removing a class to the day element, that shows that it is selected. And we will be checking if the currently selected date exists already in the selectedDays array. If it does not, it is pushed to the array, otherwise, it is spliced out.
/* ****************** Click Event ********************** */
d.addEventListener('click', function(){
this.classList.toggle('selected');
if (!selectedDays.includes(this.dataset.day))
selectedDays.push(this.dataset.day);
else
selectedDays.splice(selectedDays.indexOf(this.dataset.day), 1);
});
/* **************************************************** */
Multiple Day Selection
Multiple days can be selected by dragging the mouse through the calendar, selecting the desired days along the way. And for that we're going to be needing a few of the mouse event handlers that JavaScript provides, starting with the mousedown event, following along with the mousemove event and finishing off with the mouseup event.
mousedown - The mousedown event will simply keep track of when the mouse key is being held down. This will help ensure that we only select the days if the mouse key is indeed pressed down.
d.addEventListener('mousedown', function(e){
e.preventDefault();
mousedown = true;
});
mouseup - The mouseup event is essentially the same as the mousedown event. Once the mouse key has been depressed, we want to reset the mousedown variable so that it can stop selecting days.
d.addEventListener('mouseup', function(e){
e.preventDefault();
mousedown = false;
});
mousemove - The mousemove event is where the selection actually happens. It is very similar to the click event. The first thing we want to do is to check if the mouse key is currently pressed, which if it is, it means we are dragging our move around. In which case, we will want to pretty much replicate the click event, except we don't want to toggle the selections, we just want to make sure that they get selected.
d.addEventListener('mousemove', function(e){
e.preventDefault();
if (mousedown)
{
this.classList.add('selected');
if (!selectedDays.includes(this.dataset.day))
selectedDays.push(this.dataset.day);
}
});
Note that if you wanted to, you could likely have the days deselected on mousemove as well.
Upgrades
There's plenty that you can do with a calendar widget. While this was a good start into creating a realistically functional version of a calendar, you can go further and build out any of the following.
- Select based on 'number of day' ranges
- Select whole months
- Select whole weeks
In a future post, I will be addressing these features and more.
Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.