[JavaScript] SelectBox를 사용하는 날짜 검색창 제작[JavaScript] SelectBox를 사용하는 날짜 검색창 제작

Posted at 2020. 7. 12. 20:31 | Posted in JavaScript & jQuery/JavaScript
반응형







■ 셀렉트 박스를 이용한 캘린더 제작







위와 같이 <SELECT> 태그를 통해 날짜값을 지정하여 검색하는 페이지를 제작하게 되었다.


jQuery UI의 DatePicker등을 사용하면 그냥 손쉽게 해결 할 수 있고,


보통은 다 이렇게 하지만, 또 막상 일을 하다보면 위와 같은 검색을 선호하는 클라이언트가 또 있을 수 있다라는 생각이들어


추가적으로 실제 업무에서 많이 쓰이게 되는 GET 방식을 통한 검색조건 전달의 경우를 포함하여


내용을 정리해보았다.





※ 예외 처리해야할 사항들


 ① 매월의 마지막 날의 날짜는 항상 일치하지 않기에, 그달의 마지막 날보다 큰 날짜는 자동적으로 선택할 수 없어야 한다.

 ② 처음 접속시 해당월의 첫째날( 01일 )과 마지막날( 28일, 29,일 30일, 31일 등 )이 자동 세팅되어야 한다.

 ③ GET방식을 통해 검색 시작일과 종료일의 날짜 데이터가 전달되는 경우의 수를 처리해야 한다.

 ④ 사용자가 날짜를 선택하는 과정에서 31일이 선택되어 있는 가운데 31일이 존재하지 않는 년, 월을 선택한 경우

     해당 월의 마지막 날로 자동 변경시켜주어야 한다.




위 경우를 상정하여 아래 코드를 작성하게 되었다.




# 소스코드

<html>

<head>

<title>:: JavaScript 매월 주차 구하기 ::</title>

<script type="text/javascript">


    document.addEventListener("DOMContentLoaded", function() {


        const stdDays = document.querySelector("span:nth-child(1)");     // @param 시작일 영역지정

        const endDays = document.querySelector("span:nth-child(2)");    // @param 종료일 영역지정


        let stdFirstDate = null;    // @param 시작일의 첫날

        let endFirstDate = null;   // @param 종료일의 첫날

        let stdLastDate = null;    // @param 시작일의 전체일수

        let endLastDate = null;   // @param 종료일의 전체일수



        // @param GET방식으로 전달된 시작일, 종료일의 지정값이 존재하지 않는경우 ( ※ 맨처음 시작시에 실행 )

        if(nullPointerException(getParameter("stdDate")) == false && nullPointerException(getParameter("endDate")) == false) {


            const toDate = new Date();


            stdFirstDate = new Date(toDate.getFullYear(), (toDate.getMonth() + 1));

            stdLastDate = new Date(stdFirstDate.getFullYear(), (stdFirstDate.getMonth() + 1), 1);  // @param 다음달의 첫째날을 지정

            stdLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


            endFirstDate = new Date(toDate.getFullYear(), (toDate.getMonth() + 1));

            endLastDate = new Date(endFirstDate.getFullYear(), (endFirstDate.getMonth() + 1), 1);  // @param 다음달의 첫째날을 지정

            endLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


        }


        // @param GET방식으로 전달된 시작일, 종료일의 지정값이 존재하는 경우

        else {


            const stdDate = getParameter("stdDate");

            stdFirstDate = new Date(

                  Number(stdDate.substring(0, 4))

                , Number(stdDate.substring(6, 8))

                , Number(stdDate.substring(4, 6))

            );

            stdLastDate = new Date(stdFirstDate.getFullYear(), stdFirstDate.getMonth(), 1);  // @param 다음달의 첫째날을 지정

            stdLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


            const endDate = getParameter("endDate");

            endFirstDate = new Date(

                  Number(endDate.substring(0, 4))

                , Number(endDate.substring(4, 6))

                , Number(endDate.substring(6, 8))

            );

            endLastDate = new Date(endFirstDate.getFullYear(), endFirstDate.getMonth(), 1);  // @param 다음달의 첫째날을 지정

            endLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


        }


        // @param 년도( Year ) - 선택

        for(let year = 0; stdDays.querySelector("select:nth-child(1)").length > year; year++) {

            if(stdDays.querySelector("select:nth-child(1)").options[year].value == stdFirstDate.getFullYear()) {

                stdDays.querySelector("select:nth-child(1)").options[year].selected = true;

            }


            if(endDays.querySelector("select:nth-child(1)").options[year].value == stdFirstDate.getFullYear()) {

                endDays.querySelector("select:nth-child(1)").options[year].selected = true;

            }

        }


        // @param 월( Month ) - 선택

        for(let month = 0; stdDays.querySelector("select:nth-child(2)").length > month; month++) {

            if(stdDays.querySelector("select:nth-child(2)").options[month].value == stdFirstDate.getMonth()) {

                stdDays.querySelector("select:nth-child(2)").options[month].selected = true;

            }


            if(endDays.querySelector("select:nth-child(2)").options[month].value == endFirstDate.getMonth()) {

                endDays.querySelector("select:nth-child(2)").options[month].selected = true;

            }

        }


        // @param 일( Day ) - 생성 및 선택

        // @details - 날짜는 매월 마지막일이 다르게 끝나기 때문에 직접 생성하고,

        //                선택한 날( 기본값 시작일 - 01일, 종료일은 - 말일 )을 자동으로 selected 한다.

        for(let date = 1; stdLastDate.getDate() >= date; date++) {

            if(stdFirstDate.getDate() == date) {

                stdDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "' selected>" + autoLeftPad(date, 2) + "</option>";

            } else {

                stdDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "'>" + autoLeftPad(date, 2) + "</option>";

            }

        }


        for(let date = 1; endLastDate.getDate() >= date; date++) {

            if((nullPointerException(getParameter("endDate")) == true) ? endFirstDate.getDate() : endLastDate.getDate() == date) {

                endDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "' selected>" + autoLeftPad(date, 2) + "</option>";

            } else {

                endDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "'>" + autoLeftPad(date, 2) + "</option>";

            }

        }

    });



    /**

     * @brief   시작일( 년, 월 ), 종료일 ( 년, 월 )의 값이 변경된 경우 실행

     * @details 시작일( 년, 월 ), 종료일 ( 년, 월 )의 값이 변경에 따른 해당 년월의 전체일수를 다시 체크,

     *             변경된 년월의 일보다 선택된 일이 큰경우 마지막 날로 선택일 자동 변경

     */

    function changeConditionPeriod(cal) {


        const searchDays = cal.parentNode;

        const checkDate = searchDays.querySelector("select:nth-child(3)").value;


        // @param 다음달의 첫째날을 지정

        let lastDate = new Date(

              searchDays.querySelector("select:nth-child(1)").value

            , searchDays.querySelector("select:nth-child(2)").value

            , 1

        );

        lastDate.setDate(0);    // @param 하루를 뺌


        // @param 일정보 초기화

        searchDays.querySelector("select:nth-child(3)").innerHTML = "";


        // @param 일정보 재삽입

        for(let date = 1; lastDate.getDate() >= date; date++) {

            if(checkDate == date) {

                searchDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "' selected>" + autoLeftPad(date, 2) + "</option>";

            } else {

                searchDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "'>" + autoLeftPad(date, 2) + "</option>";

            }

        }


        // @param 일정보 예외처리 선택되어있는 마지막 날이 바꾼 월의 날보다 큰경우의 예외처리

        if(checkDate > lastDate.getDate()) {

            searchDays.querySelector("select:nth-child(3) > option:last-child").selected = true;

        }

    }


    /**

     * @brief   강제로 앞에 0을 붙여서 두자릿수 숫자로 변경한다.

     * @param   num     앞에 0을 붙일 숫자 값

     * @param   digit   자릿수를 지정

     */

    function autoLeftPad(num, digit) {

        if(String(num).length < digit) { num = new Array(digit - String(num).length + 1).join("0") + num; }

        return num;

    }


    /**

     * @brief   GET으로 넘어오는 값의 존재 여부를 체크

     */

    function nullPointerException(worth) {

        if(

               worth == "" 

            || worth == null 

            || worth == undefined 

            || (worth != null && typeof worth == "object" && !Object.keys(worth).length == "")

        ) {

            return false;

        } else {

            return true;

        }

    }


    /**

     * @brief   GET방식으로 전달된 값을 추출

     * @param   param     추출할 key의 명칭

     */

    var getParameter = function(param) {

        let returnValue;

        let url = location.href;

        let parameters = (url.slice(url.indexOf("?") + 1, url.length)).split("&");

        for(let i = 0; i < parameters.length; i++) {

            let varName = parameters[i].split("=")[0];

            if (varName.toUpperCase() == param.toUpperCase()) {

                returnValue = parameters[i].split("=")[1];

                return decodeURIComponent(returnValue);

            }

        }

    };

</script>

</head>

<body>

    <h1>■ SelectBox를 이용한 캘린더</h1>

    <hr/>

    <!-- 년( Year )은 자동으로 생성시 너무 많이 늘어날 수 있어서 -->

    <!-- 월( Month )은 01 ~ 12라는 고정값을 알고 있기에 직접 값을 지정 -->

    <!-- 일( Day )은 마지막 일이 항상 변하기 때문에 자동 생성 한다. -->

    <div>

        <span>

            시작일&nbsp;:&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="2018">2018</option>

                <option value="2019">2019</option>

                <option value="2020">2020</option>

                <option value="2021">2021</option>

                <option value="2022">2022</option>

                <option value="2023">2023</option>

                <option value="2024">2024</option>

                <option value="2025">2025</option>

            </select>

            &nbsp;년&nbsp;&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="1">01</option>

                <option value="2">02</option>

                <option value="3">03</option>

                <option value="4">04</option>

                <option value="5">05</option>

                <option value="6">06</option>

                <option value="7">07</option>

                <option value="8">08</option>

                <option value="9">09</option>

                <option value="10">10</option>

                <option value="11">11</option>

                <option value="12">12</option>

            </select>

            &nbsp;월&nbsp;&nbsp;

            <select class="choiceDay"></select>

            &nbsp;일

        </span>

        &nbsp;&nbsp;~&nbsp;&nbsp;

        <span>

            종료일&nbsp;:&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="2018">2018</option>

                <option value="2019">2019</option>

                <option value="2020">2020</option>

                <option value="2021">2021</option>

                <option value="2022">2022</option>

                <option value="2023">2023</option>

                <option value="2024">2024</option>

                <option value="2025">2025</option>

            </select>

            &nbsp;년&nbsp;&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="1">01</option>

                <option value="2">02</option>

                <option value="3">03</option>

                <option value="4">04</option>

                <option value="5">05</option>

                <option value="6">06</option>

                <option value="7">07</option>

                <option value="8">08</option>

                <option value="9">09</option>

                <option value="10">10</option>

                <option value="11">11</option>

                <option value="12">12</option>

            </select>

            &nbsp;월&nbsp;&nbsp;

            <select class="choiceDay"></select>

            &nbsp;일

        </span>

    </div>

</body>

</html> 



이제 위 코드를 브라우저를 통해 실행시켜 보면




# 출력결과




위와 같이 예외처리해야할 사항들이 정상적으로 반영되어 기능하는 모습을 확인 할 수 있다.








반응형
//