상세 컨텐츠

본문 제목

Form(폼) Serialize 속 살짝 들여다 보깅!

자바스크립트

by e7e 2023. 11. 24. 19:38

본문

웹프로그램에서 form 태그 안의 사용자 입력 태그들의 name과 value를  서버로 보낼 때

그냥 form 태그 객체의 submit 으로  보낼 때는 상관없는뎅,이것들을 AJAX로 보내야 할 때,

form태그안에 사용자 입력태그(input:text 등등)가 꽤나 많다면 이것들을 일일이 접근해서

name=value&name=value 식의 쿼리스트링으로 만드는 건 여간 귀찮은 일이 아닐 것이당.

(input:text만 만개가 있다고 가정해 보라!~~  토 나오공 분명 빼먹을거당!)

 

이럴 때 보통  퀴리스트링으로 만들려면  jQuery의 serialize() 메소드를 사용하고,

JSON 문자열 형태로 만들려면 serializeJSON() 메소드사용한당.

 

jQuery는 자바스크립트로 맹글어졌기 때문에 jQuery로 할 수 있는 건 자바스크립트로

다 할 수 있지만, 그 역은 항상 그렇지만은 않당.

 

serialize와 serializeJSON을 그냥 사용하는 것도 크게 나쁘지는 않지만, 별로 

그리 대다한 내용이 아니니, 직접 한번 만들어 보면, 그 시간이 초롱초롱 반짝할 것 같당!.

 

serialize 이해에 필요한 핵심은  form  태그 객체의 elements 속성이당.

아래 html 소스를 복사/붙여넣기로 실행해보고, console.log 결과에 느낌 받장!

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
    <form>
        <h3 name="huk">요건 elements에 포함 안되용</h3>
        <input type="text" name="samNm" value="e7e"><br>
        <input type="text" name="samAge" value="30"><br>
        <div name="merong">안 담겨용</div>
        <input type="text" name="samAlias" value="cuty"><br>
        <input type="button" name="samBtn" value="포함되용">
    </form>
    <script>
        // form태그 객체의 elements 속성에 사용자 입력태그들만 담겨 옴
        const elems = document.forms[0].elements;
        for (let i = 0; i < elems.length; i++) {
            let elem = elems[i];
            console.log("체킁", i, elem, elem.name, elem.value);
        }
    </script>
</body>

</html>

위 샘플 소스에 느낌받았다면 아래 소스도 그냥 이해 될 수 밖에 없당.

복사/붙여넣기로 실행해서 결과와 소스를 눈과 뇌에 매칭시키장!

일부러 주석을 많이 달았으니, 자바스크립트 소스에 주목해서 보도록 하장.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>E7E 만만세</title>
    <style>
        * {
            font-weight: bolder;
        }

        h1 {
            background-color: black;
            color: yellowgreen;
        }

        #disp {
            white-space: pre-wrap;
            word-wrap: break-word;
            border: 1px solid blue;
            min-height: 70px;
            width: 360px;
            overflow: auto;
        }
    </style>
</head>

<body>
    <form>
        <table border="1">
            <tr>
                <td colspan="2">
                    <h1>Serialize 해봐용</h1>
                </td>
            </tr>
            <tr>
                <td>이름</td>
                <td><input type="text" name="empName" id="empName" style="width:95%" 
                    pattern="[가-힣]{3,4}" 
                    placeholder="한글3~4자" value="금수저" required></td>
            </tr>
            <tr>
                <td>이메일</td>
                <td><input type="text" name="empEmail" id="empEmail" 
                        pattern="[a-z0-9]+@[a-z]+\.[a-z]{2,3}"
                        style="width:95%" value="ksj@onami.com" required></td>
            </tr>
            <tr>
                <td>성별</td>
                <td>
                    남<input type="radio" name="empSB" id="empSB" value="male">
                    여<input type="radio" name="empSB" id="empSB" value="femail" checked>
                </td>
            </tr>
            <tr>
                <td>역할</td>
                <td>
                    <select name="empRole" id="empRole">
                        <option value="si">개발[SI]</option>
                        <option value="sm">유지보수[SM]</option>
                        <option value="mg" selected>매니저[총괄]</option>
                    </select>
                </td>
            </tr>
            <tr>
                <td>능력</td>
                <td>
                    프론트<input type="checkbox" name="empScope" id="empScope" value="front">
                    백엔드<input type="checkbox" name="empScope" id="empScope" value="backend">
                    D B<input type="checkbox" name="empScope" id="empScope" value="db">
                    메롱<input type="checkbox" name="empScope" id="empScope" value="merong">
                </td>
            </tr>
            <tr>
                <td>간략자기소개</td>
                <td><textarea name="empAbout" id="empAbout" cols="30" rows="10" required></textarea></td>
            </tr>
            <tr>
                <td colspan="2" style="text-align: center;">
                    <input type="submit" name="serBtn" id="serBtn" value="serialize">
                    <input type="submit" name="jsonBtn" id="jsonBtn" value="serializeJSON">
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <pre id="disp">
                    </pre>
                </td>
            </tr>
        </table>
    </form>
    <script>
        /**************    임시 대책부     ***************/
        //textarea에 직접 값 넣으면 htmlㅅ소스가 안 예쁨
        document.querySelector("#empAbout").value = "안농 난 E7E라고 행\n아프로 뒤로 잘 지내보장";

        /**************    전역변수 객체 선언부    ***************/
        const empForm = document.forms[0];  // form태그가 1개 밖에 없으니깡!

        // console.log로 찍었을 때, ...List, ...Collection이라고 나오는 것은
        // 유사배열이라고 해서, 배열의 메소드를 사용하려면 배열로 변환해야 함!
        const formElems = Array.from(empForm.elements);
        const justDisp = document.querySelector("#disp");

        // submit 버튼을 2개 넣었음!(일부렁) 
        const submitBtns = Array.from(document.querySelectorAll("input[type=submit]"));
        let whichBtn = "";  // 어느 submit 버튼을 눌렀는가? 저장변수 serBtn Or jsonBtn

        /**************    전역함수 선언부    ***************/

        // 시리얼라이즈 하기 전에 의미없는 element 제거
        // 곧 서버로 전달할 필요가 없는 값! 예를 들면 체크 안된 체크박스의 값
        // 시리얼라이즈, JSON문자열화 양쪽에 필요해서 별도 함수로 추출
        const preRemoveElem = () => {
            // 배열의 filter 메소드를 이용하여 제거
            let selElems = formElems.filter(elem => {
                if (elem.type == "button" || elem.type == "submit" || elem.type == "reset") {
                    return false; // 제거 하겠다는 의미
                }
                if ((elem.type == "radio" || elem.type == "checkbox") && !elem.checked) {
                    return false;
                }
                return true;  // 담겠다는 의미
            });

            return selElems;
        }

        // 시리얼라이즈 함수!, 여기서의 의미는 쿼리스트링 형태
        // name=금수저&initial=ksj&age=23  형태의 문자열
        const fFormSerialize = () => {
            let serializeStr = "";  // 시리얼라이즈 결과 담을 변수

            // 필요없는 거 먼저 제거 후, 시리얼라이즈
            preRemoveElem().forEach(elem => {
                serializeStr += `${elem.name}=${elem.value}&`;
            });

            serializeStr = serializeStr.substr(0, serializeStr.length - 1);// 마지막 & 제거
            console.log("시리얼 디버깅:", serializeStr);
            justDisp.innerText = serializeStr;  // 화면에 뿌리깅

            return serializeStr;
        }

        const fFormSerializeJSON = () => {

            //필요없는 거 먼저 제거 후, JSON화
            let jsonObj = {};           // 빈 객체
            let arrForCheck = [];       // 체크된 체크박스값 담을 빈 배열
            preRemoveElem().forEach(elem => {
                if (elem.type == "checkbox") {
                    arrForCheck.push(elem.value);
                    jsonObj[elem.name] = arrForCheck;  // 배열식 접근법 이용
                    return;
                }
                // 배열식 접근법 이용 객체에 속성:값 형태 추가 
                jsonObj[elem.name] = elem.value;
            })

            console.log("JSON 디버깅:", jsonObj);
            let jsonStr = JSON.stringify(jsonObj);
            justDisp.innerText = jsonStr;

            return jsonStr;
        }

        // submit 버튼을 클릭하면, form객체에 전송 직전에 submit이벤트 발생
        const fSubmit = () => {
            event.preventDefault(); // form 전송(submit) 막깅
            if (whichBtn == "serBtn") {
                alert("시리얼라이즈 누르셨어용");
                alert(fFormSerialize());  // Form의 element serialize
            } else {
                alert("JSON 누르셨어용");
                alert(fFormSerializeJSON());  // Form의 element serialize json
            }
        }

        // submit 버튼을 클릭하면, 버튼 id를 전역변수에 저장
        const fWhichBtn = () => {
            whichBtn = event.target.id;
        }


        /**************    이벤트 등록부(바인딩)   ***************/
        // form submit이벤트 발생시 fSubmit 호출
        empForm.addEventListener("submit", fSubmit)

        // submit 버튼 클릭시 fWhichBttn 호출
        submitBtns.forEach(btn => {
            btn.addEventListener("click", fWhichBtn)
        });


    </script>
</body>

</html>

혹 소스 기럭지가 길어  거부감이 생기지 않을까 시퍼 

뽀인또를 쪼금 설명하면 , 사용자 입력태그가 아닌 것(h1,div등등)은 알아서 걸러주므로,

신경 쓸 것이 없는뎅, 문제는 button 태그등의 name,value값은 서버에 보낼 필요가 없고,

radio는 체크된 값만 보내야 하며, checkbox는 여러개가 체크 될 수 있으므로,

JSON문자열로 만들 때 value들을 배열에 담고, 속성명은 name에 담으면 , 서버쪽에서

받기가 편할 것이당. 

이 부분을 배열의 filter메소드를 이용해서, submit 버튼과 체크 안된 radio, checkbox등을

미리 걸러낸 다음에 forEach를 이용하여, serialize나 serializeJSON을 진행하였당.

이 생각을 담고 본다면, 소스의 핵심만 느낌있게 보일거시당.(당신 자신을 믿어랑!)

 

잘 이해가 되었다면, 당신은 JSON의 배열식 접근법이 얼마나 편한지 느꼈을거공,

아프론 데이타 구조 변화가 당신 손에서  마구 자유로울 거시당.

 

추가적으로  Array.from 메소드도 잘 확인해 두고,

배열의 메소드 filter와 forEach도 사용법 확인(callback을 안다면 만들 수 있당) 하고

한번 그냥 for(let i=0; i<리미트; ㅑ++){} 문으로 바꾸는 작업을 해보장

뜻밖에 얻는 것이 분명 있을 거시당.

 

 

 

 

 

입장 바꿔 생각해 보라는 글은 가슴에 공감을 남기는데,

입장 바꿔 생각해 보라는 말을 듣는 것은 가슴에 생채기를 남긴다.

탑-다운의 질책을 받는 느낌이당. 

정말 입장바꿔서 생각할 수가 있기는 하는 걸까?

 

친구였었다면, 이해 할 수 있었을까?

난 결국 나르시스트!!!!

 

 

 

https://www.youtube.com/watch?v=z8FS19r1Xo4

 

관련글 더보기