I know this is the era of Vue, Angular, React etc, but there are still applications running on old JQuery and javascript code. Recently I had a task to create or use a multidates picker from JQuery. I ran into the JQuery UI's multidatepicker and it was pretty nice. But I had a lot of issues and challanges customizing it. I then thought of why not creating one like I want.
Well I am no expert in front-end or scripting, but I still thought it was worth a try.
Though I was thinking to convert it to a plugin, here is a pure html and jquery code that I did for the multidatepicker. Here is my attempt:
Use bootstrap to create a HTML Skeleton
I have used bootstrap to create a HTML skeleton for the calendar that I will build dynamically.
<input type="text" id="selectedValues" class="date-values" readonly/>
<div id="parent" class="container" style="display:none;">
<div class="row header-row">
<div class="col-xs previous">
<a href="#" id="previous" onclick="previous()">
<i class="fa fa-arrow-left" aria-hidden="true"></i>
</a>
</div>
<div class="card-header month-selected col-sm" id="monthAndYear">
</div>
<div class="col-sm">
<select class="form-control col-xs-6" name="month" id="month" onchange="change()"></select>
</div>
<div class="col-sm">
<select class="form-control col-xs-6" name="year" id="year" onchange="change()"></select>
</div>
<div class="col-xs next">
<a href="#" id="next" onclick="next()">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</a>
</div>
</div>
<table id="calendar">
<thead>
<tr>
<th>S</th>
<th>M</th>
<th>T</th>
<th>W</th>
<th>T</th>
<th>F</th>
<th>S</th>
</tr>
</thead>
<tbody id="calendarBody"></tbody>
</table>
</div>
I have added the Bootstrap, Font-awesome(for the previous and next arrows) and JQuery in my html.
I have added some styles as well to this. The css file can be accessed from here
Now the crux of the script is generating the dates based on the days. Here is my attempt on it:
Script to load the calendar
function loadControl(month, year) {
addMonths(month);
addYears(year);
let firstDay = (new Date(year, month)).getDay();
// body of the calendar
var tbl = document.querySelector("#calendarBody");
// clearing all previous cells
tbl.innerHTML = "";
var monthAndYear = document.getElementById("monthAndYear");
// filing data about month and in the page via DOM.
monthAndYear.innerHTML = months[month] + " " + year;
selectYear.value = year;
selectMonth.value = month;
// creating the date cells here
let date = 1;
selectedDates.push((month + 1).toString() + '/' + date.toString() + '/' + year.toString());
// there will be maximum 6 rows for any month
for (let rowIterator = 0; rowIterator < 6; rowIterator++) {
// creates a new table row and adds it to the table body
let row = document.createElement("tr");
//creating individual cells, filing them up with data.
for (let cellIterated = 0; cellIterated < 7 && date <= daysInMonth(month, year); cellIterated++) {
// create a table data cell
cell = document.createElement("td");
let textNode = "";
// check if this is the valid date for the month
if (rowIterator !== 0 || cellIterated >= firstDay) {
cell.id = (month + 1).toString() + '/' + date.toString() + '/' + year.toString();
cell.class = "clickable";
textNode = date;
// this means that highlightToday is set to true and the date being iterated it todays date,
// in such a scenario we will give it a background color
if (highlightToday
&& date === today.getDate() && year === today.getFullYear() && month === today.getMonth()) {
cell.classList.add("today-color");
}
// set the previous dates to be selected
// if the selectedDates array has the dates, it means they were selected earlier.
// add the background to it.
if (selectedDates.indexOf((month + 1).toString() + '/' + date.toString() + '/' + year.toString()) >= 0) {
cell.classList.add(highlightClass);
}
date++;
}
cellText = document.createTextNode(textNode);
cell.appendChild(cellText);
row.appendChild(cell);
}
tbl.appendChild(row); // appending each row into calendar body.
}
// this adds the button panel at the bottom of the calendar
addButtonPanel(tbl);
// function when the date cells are clicked
$("#calendarBody tr td").click(function (e) {
var id = $(this).attr('id');
// check the if cell clicked has a date
// those with an id, have the date
if (typeof id !== typeof undefined) {
var classes = $(this).attr('class');
if (typeof classes === typeof undefined || !classes.includes(highlightClass)) {
var selectedDate = new Date(id);
selectedDates.push((selectedDate.getMonth() + 1).toString() + '/' + selectedDate.getDate().toString() + '/' + selectedDate.getFullYear());
}
else {
var index = selectedDates.indexOf(id);
if (index > -1) {
selectedDates.splice(index, 1);
}
}
$(this).toggleClass(highlightClass);
}
// sort the selected dates array based on the latest date first
var sortedArray = selectedDates.sort((a, b) => {
return new Date(a) - new Date(b);
});
// update the selectedValues text input
document.getElementById('selectedValues').value = datesToString(sortedArray);
});
var $search = $('#selectedValues');
var $dropBox = $('#parent');
$search.on('blur', function (event) {
//$dropBox.hide();
}).on('focus', function () {
$dropBox.show();
});
}
I have added a button panel to the bottom of the dates panel. It has two buttons, Reset and Done.
Also, to set the dates to be pre-selected on load, add your dates to the selectedDates array.
This is how the control looks:
I have been trying to improve my code here as I am not a JS or a frontend expert.
You can download the whole working sample from here
It is extremely easy to create your own controls and use them using simple HTML and JQuery/Javascript codes.
Top comments (4)
Nice
I love it man. Simple and Clears
Thanks! :)
Thanks! This is really helpful!