DEV Community

Cover image for Easily Generate Custom Date Field Input with JavaScript
Simon Ugorji
Simon Ugorji

Posted on

Easily Generate Custom Date Field Input with JavaScript

Today, I will show you how you can generate an input field that will enable users to select a date using JavaScript.

Our Date Input will take note of leap years and months that have either 31 or 30 days.

This means that:

  • if you select a leap year, and you choose the month of February, the days will count up to 29
  • If you choose the month of January, the days will count up to 31.

LET'S BEGIN

We will create a blank HTML file and add the Select fields; year, month, and day.

<!doctype html>
<html>
    <head></head>
    <body>

    <select id="select_year" start="1900" end="2022"> 
    </select>

    <select id="select_month">
    </select>

    <select id="select_day">
    </select>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

We will leave the fields empty and use their respective IDs (Identifiers) to refer to them in JavaScript.

Generate Days

In order to generate the days, we will start at the index of 1 and increment the value to the maximum number of days in a calendar which is 31, then create an option tag and set both the value and text to our current index.

Generate Months

In order to generate the months, we will start at the index of 1 and increment the value to the maximum number of months in a calendar which is 12, then create an option tag and set both the value and text to our current index.

Generate Years

If you take a close look at the year Select Element, you will see the attributes start and end.
These attributes will help us to generate the years from the specified start index to the end index.

document.addEventListener('DOMContentLoaded', function(){
    const yearElem = document.querySelector('#select_year');
    const dayElem = document.querySelector('#select_day');
    const monthElem = document.querySelector('#select_month');

    let days = 31; // maximum number of days
    let months = 12; // maximum number of months
    let yearStart = (yearElem.getAttribute("start")) ? yearElem.getAttribute("start") : 1900;
    let yearEnd = (yearElem.getAttribute("end")) ? yearElem.getAttribute("end") : 2022; 


    let d = 1;
    while(d <= days){
        const opt = document.createElement("option");
        opt.setAttribute("value", d);
        opt.innerText = d;
        dayElem.appendChild(opt);
        ++d;
    }
    let m = 1;
    while(m <= months){
        const opt = document.createElement("option");
        opt.setAttribute("value", m);
        opt.innerText = m;
        monthElem.appendChild(opt);
        ++m;
    }
    while(yearStart <= yearEnd){
        const opt = document.createElement("option");
        opt.setAttribute("value", yearStart);
        opt.innerText = yearStart;
        yearElem.appendChild(opt);
        ++yearStart;
    }
})
Enter fullscreen mode Exit fullscreen mode

image.png

Regenerate Days

Now we need a function that will enable us to regenerate the days based on the length specified.

This means that if we choose the month of September (09), the days will be regenerated and will count up to 30 instead of 31 because there are 30 days in the month of September.

In other to achieve this, we will create an array inside our function, that will store the days from (1 - 31), then shorten the length of the array based on the length parameter specified.

function buildDays(length){
    let daysArry = [];
    let d = 1;
    while(d <= 31){
        daysArry.push(d); 
        ++d;
    }
    //shorten the length
    daysArry.length = ( daysArry.length - length );
    //empty the days element
    dayElem.innerHTML = '';
    //loop through array, then create option tag and append to element
    daysArry.forEach(d => {
        const opt = document.createElement("option");
        opt.setAttribute("value", d);
        opt.innerText = d;
        dayElem.appendChild(opt);
     });
}
Enter fullscreen mode Exit fullscreen mode

Now in other to make use of this function, we need to create another function that will check the month selected.

We will use a switch statement in this function, to check the month selected and set the length appropriately.

function checkMonth(month){
    let len = 0;
    //check month that has 30 days
    switch(month){
        //september
        case "9" :
            len = 1;
        break;
        //april
        case "4" :
            len = 1;
        break;
        //june
        case "6" :
            len = 1;
        break;
        //november
        case "11" :
            len = 1;
        break;
        default :
             len = 0;
        break; 
    }
    //check if february is selected
    if(month == 2){
        checkLeapYear(yearElem.value);
    }else{
         buildDays(len);
    }
}
Enter fullscreen mode Exit fullscreen mode

For our last function, we need to check if the Year selected is a leap year.

Back in High School, my Math Teacher told me that if a year is divisible by 4, this means that such a year is a leap year.

For example, if you divide 2020 by 4, you will get an Integer (505). This means that the year 2020 was a leap year. But if you divide the year 2022 by 4, you will get a float (505.5). This means that the year 2022 is not a leap year.

So in our function, we will check if our division is an integer or a float using a Regular Expression, then rebuild our days appropriately.

//check leap year
function checkLeapYear(year){
    let v = (year / 4) * 1;
    //check if the result is an integer or a float using regExp
    if(/^[0-9]+$/.test(v)){
        (monthValue == 2) ?
            buildDays(2) //29 days
        : '';
    }else{
       (monthValue == 2) ?
           buildDays(3) //28 days
        : ''; 
    }
}
Enter fullscreen mode Exit fullscreen mode

Almost Done

Now we need to attach an Event Listener to our Month and Year select elements, in order to execute our functions based on the selected values.

We will also make sure of not executing the function twice when the same value is provided, by saving the value to a variable.

//Month Element Event Listener
var monthValue = 0
monthElem.addEventListener('click', function(){
    if(monthValue !== this.value){
        monthValue = this.value;
        checkMonth(this.value); //run the check month function
    }

});
//Year Element Event Listener
var yearValue = 0;
yearElem.addEventListener('click', function(){
    yearValue = this.value;
    checkLeapYear(this.value); //check for leap year
});
Enter fullscreen mode Exit fullscreen mode

So if we should select a month, say September, the function will rebuild the days up to 30. And if we select the leap year, say 2020, the function will check if the month selected is February (2) and it will rebuild the days up to 29 because there're 29 days in the month of February on a leap year.

Testing our script

Copy and paste this code in a blank HTML page and try to select a leap year + February, a month that has 30 days in it.

document.addEventListener('DOMContentLoaded', function(){
    const yearElem = document.querySelector('#select_year');
    const dayElem = document.querySelector('#select_day');
    const monthElem = document.querySelector('#select_month');

    let days = 31; // maximum number of days
    let months = 12; // maximum number of months
    let yearStart = (yearElem.getAttribute("start")) ? yearElem.getAttribute("start") : 1900;
    let yearEnd = (yearElem.getAttribute("end")) ? yearElem.getAttribute("end") : 2022; 

    let d = 1;
    while(d <= days){
        const opt = document.createElement("option");
        opt.setAttribute("value", d);
        opt.innerText = d;
        dayElem.appendChild(opt);
        ++d;
    }
    let m = 1;
    while(m <= months){
        const opt = document.createElement("option");
        opt.setAttribute("value", m);
        opt.innerText = m;
        monthElem.appendChild(opt);
        ++m;
    }
    while(yearStart <= yearEnd){
        const opt = document.createElement("option");
        opt.setAttribute("value", yearStart);
        opt.innerText = yearStart;
        yearElem.appendChild(opt);
        ++yearStart;
    }
//build days
function buildDays(length){
    let daysArry = [];
    let d = 1;
    while(d <= 31){
        daysArry.push(d); 
        ++d;
    }
    //shorten the length
    daysArry.length = ( daysArry.length - length );
    //empty the days element
    dayElem.innerHTML = '';
    //loop through array, then create option tag and append to element
    daysArry.forEach(d => {
        const opt = document.createElement("option");
        opt.setAttribute("value", d);
        opt.innerText = d;
        dayElem.appendChild(opt);
     });
}
//check selected month
function checkMonth(month){
    let len = 0;
    //check month that has 30 days
    switch(month){
        //september
        case "9" :
            len = 1;
        break;
        //april
        case "4" :
            len = 1;
        break;
        //june
        case "6" :
            len = 1;
        break;
        //november
        case "11" :
            len = 1;
        break;
        default :
             len = 0;
        break; 
    }
    //check if february is selected
    if(month == 2){
        checkLeapYear(yearElem.value);
    }else{
         buildDays(len);
    }
}
//check leap year
function checkLeapYear(year){
    let v = (year / 4) * 1;
    //check if the result is an integer or a float using regExp
    if(/^[0-9]+$/.test(v)){
        (monthValue == 2) ?
            buildDays(2) //29 days
        : '';
    }else{
       (monthValue == 2) ?
           buildDays(3) //28 days
        : ''; 
    }
}

//Month Element Event Listener
var monthValue = 0
monthElem.addEventListener('click', function(){
    if(monthValue !== this.value){
        monthValue = this.value;
        checkMonth(this.value); //run the check month function
    }

});
//Year Element Event Listener
var yearValue = 0;
yearElem.addEventListener('click', function(){
    yearValue = this.value;
    checkLeapYear(this.value); //check for leap year
});
})
Enter fullscreen mode Exit fullscreen mode

The Year 2020 (Leap Year) + Month of February

image.png

Month of January

image.png

Month of September

image.png

An Important Note

Most centurial years ( a period of 100 years ) are not leap years, even though they are divisible by 4.

Years such as 1700, 1800, and 1900 are not leap years but they are divisible by 4.

So this doesn’t agree with the fact that any year divisible by 4 must be a leap year.

According to this wonderful article, I got to realize that if a year is a centurial year ( a period of 100 years ), and is divisible by 4, it must also be divisible by 400 in order to qualify as a leap year.

Years 1700, 1800, 1900 are all divisible by 4 but are not divisible by 400, so they don’t qualify as leap years but the year 2000 is divisible by 4 and is also divisible by 400. This makes the year 2000 a leap year.

Let us update the function that checks for leap years. Here’s what we will do;

  • First, we check if it is a centurial year ( a period of 100 years ).

If the year provided is divisible by 100 ( without a remainder ), then it is a centurial year.

Then we check if it is divisible by 400 and is also divisible by 4 ( without a remainder ), if it is, we return the boolean (true) which means that the year is a leap year.

  • Second, we check if it is not a centurial year, but is divisible by 4.

If the year provided is divisible by 4 ( without a remainder ), we return the boolean (true) which means that the year is a leap year.

If none of the above is true, our function returns false, which means that the year provided is not a leap year.

function checkLeapYear(year){
    let result = false;

    //check for leap year
    (function(){
        //check for centurial year
        if( (year % 100) == 0 ) {
            //check if centurial year is a leap year
            if( ((year % 400) == 0) && ((year % 4) == 0) ){
                return ( result = true );
            }
        }else if( (year % 4) == 0){
            //check if it is not a centurial year but is divisible by 4
            return ( result = true );
        }
        return ( result = false );
    })();

    //check if the result is true ( leap year )
    if(result){
        (monthValue == 2) ?
            buildDays(2) //29 days
        : '';
    }else{
       (monthValue == 2) ?
           buildDays(3) //28 days
        : ''; 
    }
}
Enter fullscreen mode Exit fullscreen mode

All you have to do is to replace the function that checks for leap year with the function above, and the script will work 100% just fine.

You've reached the end of my article.

EXTRA

I recently launched a JavaScript package that validates your HTML forms using validation rules, regular expressions and form input attributes.

I will appreciate if you spared a few seconds to check it out.

octaValidate - A client-side form validation library | Product Hunt

This Tiny Script helps to validate your HTML forms using validation rules, sophisticated regular expressions and form input attributes.

favicon producthunt.com

Thank You

Image credit: vecteezy.com

Top comments (2)

Collapse
 
mrwilbroad profile image
wilbroad mark

Thanks for sharing

Collapse
 
ugorji_simon profile image
Simon Ugorji

You're welcome Francis!
Thank you for engaging