DEV Community

Praneet Nadkar
Praneet Nadkar

Posted on

Create your own multi date picker using JQuery/Javascript

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>

Enter fullscreen mode Exit fullscreen mode

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();
    });
}

Enter fullscreen mode Exit fullscreen mode

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:
multi_dates_picker

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.

Latest comments (4)

Collapse
 
kosoko_daniel profile image
Oluwagbenga

Nice

Collapse
 
katedatema profile image
KateDatema

Thanks! This is really helpful!

Collapse
 
adusoft profile image
Geofrey Aduda

I love it man. Simple and Clears

Collapse
 
praneetnadkar profile image
Praneet Nadkar

Thanks! :)