HTML Form 마크업, Vanila JS 를 통한 인풋 검증 및 AJAX Submit 요령
JS에서의 AJAX 등과 같은 다양한 처리로 인해, Form 자체의 순수한 기능을 쓸 일은 거의 없어졌습니다. 그럼에도 불구하고 form 의 기능을 어느정도 사용하면 웹 표준을 준수함과 물론, 코드의 유지보수성이 향상되는 효과가 있는데요, 어떻게 작성하면 되는지 그 방법을 한번 공유해보고자 합니다.
기본적인 Form 의 구조
<form>
<input type="text" name="name1" />
<input type="text" name="name2" />
...
...
<!-- (Toast UI Grid)외부 라이브러리로 동작하는 input 예시 -->
<div class="tui-datepicker-input tui-datetime-input tui-has-focus">
<input type="text" name="startDate" aria-label="Date" autocomplete="off" />
<span class="tui-ico-date"></span>
<div id="startpicker-container"></div>
</div>
<button type="submit">저장</div>
<button type="reset">리셋</div>
</form>
AJAX 요청을 한 이상, method나 action 속성을 지정할 일이 거의 없어졌습니다. 따라서 form 태그를 구성하지 않고 input과 버튼만으로 구성하는 경우도 종종 볼 수 있는데요, 그럼에도 불구하고 Form 태그를 사용하는것이 저는 옳다고 생각합니다. 그 이유로는
- 웹표준을 준수하게 되어 SEO 등의 여러가지 측면에서 이득이 발생할 수 있습니다.
- input 입력 후 Enter를 눌러도 Submit 이벤트가 발생하여 ‘웹 접근성’을 쉽게 준수할 수가 있습니다. 굳이 input 에 키보드 이벤트를 바인딩 하지 않아도 되므로, 더욱 목적지향적으로 코드를 간결하게 작성할 수 있게됩니다.
- form 안에 name 속성을 가진 여러 input 이 있다는 연관관계가 손쉽게 형성됩니다. form submit 이벤트 핸들러에서 FormData 객체를 생성할 때, event target(form element)을 매개변수로 전달해주면, name-value 가 key-value 로 매핑돼있는 객체를 손쉽게 얻을 수 있습니다.
- ‘저장’과 ‘리셋’ 버튼 각각에 click 이벤트를 바인딩 하지 않아도, form 요소에만 submit, reset 이벤트를 바인딩하면 되므로, 코드 목적성을 분명히 함과 동시에 Form의 사용 철학 또한 분명히 할 수 있게 됩니다. 특히 '리셋'과 같은 경우는, 외부 라이브러리로 동작하는 input 이 아니라면 별다른 이벤트 리스너를 추가하지 않아도 손쉽게 리셋할 수가 있게 됩니다.
Form 이벤트 바인딩
const form = document.querySelector('form selector')
form.addEventListener('submit', handleSubmit);
form.addEventListener('reset', handleReset);
표준에 맞게 HTML 을 구성하면 이렇게 더욱 목적이 분명하게 이벤트를 바인딩 할 수가 있습니다.
Form 이벤트 핸들러 구조
submit
function handleSubmit(e) {
e.preventDefault();
var formElement = e.target;
var formData = new FormData(formElement);
var formDataList = Array.from(formData); // IE 미지원
// Validation 검증 - ex) formDataList 를 순회하며 값을 체크한다.
// formData 를 파라미터로 전달하여 AJAX 수행
}
- Submit 핸들러에서는 필수적으로 preventDefault 해야 합니다. 폼의 기본 동작이 아닌 AJAX로 http request 보낼거니까요. (preventDefault, stopPropagation 의 자세한 동작을 알고 싶다면, 여기 를 참고해주시기 바랍니다)
- html 에서 form 내부에 name 속성들이 있는 input 을 정의해줬으므로,
e.target
을 통해 name-value 가 key-value 로 매핑된 객체를 손쉽게 만들 수 있습니다. Form 종류에 상관없이 그 Form 에 맞는 객체를 구성하므로, 유지보수에 탁월합니다. 만약handleSubmit
이것이 버튼 클릭 이벤트 핸들러였다면,document.querySelector
로 특정 form을 비효율적으로 가져와야 할 것입니다. - Validation 체크는 자유롭게 진행하시면 됩니다.
- 마지막에 formData 객체를 파라미터로 전달하여 AJAX 수행하면 됩니다. 경우에 따라 AJAX API에서 요구하는 데이터 형태가 다를 수도 있는데 재량껏 변형하시면 됩니다.
preventDefault 위치는 아무데나 두셔도 되는데, 주로 읽기 편하라고 맨 위에 두는 편입니다. 아무데나 둬도 되는 이유는 어차피 이벤트가 모두 전파되고 난 마지막(root)에 default 이벤트가 발생하기 때문입니다. 현재 handleSubmit 함수는 이벤트가 모두 전파된 상태도 아닌 상태이기 때문에 코드 어디에서 preventDefault 해도 괜찮은 겁니다.
reset
function handleReset(e) {
// preventDefault 하지 않는다.
// Reset 시 따로 처리하고 싶은 로직 작성(ex. 변경하고 싶은 상태 변경)
// 단순 비우기 reset이 아닌 초기값을 할당하고 싶은 것은 task queue 에 적재하여
// 디폴트 이벤트보다 나중에 실행되도록 한다.
window.setTimeout(customReset)
}
function customReset() { /* ... */ }
- 저는 브라우저의 기능을 최대한 활용하고 싶어서
preventDefault
는 따로 하지 않았습니다. handleReset
내부에는 디폴트 리셋이 발생하면서 처리하고 싶은 로직을 따로 자유롭게 구성하면 됩니다.- 브라우저에서 제공하는 단순 값 비우기 리셋이 아닌, 초기값을 할당하는 등의 커스텀 로직을 실행하고 싶으면 함수를 따로 빼서 그것을 호출하면 됩니다. 단,
setTimeout
을 이용해서 Task Queue 에 적재되어 마지막에 이벤트루프가 실행하도록 설정해야 합니다. 원래는 디폴트 이벤트가 나중에 호출되어 커스텀 로직이 적용되지 않기 때문입니다.
이벤트루프에 관한 설명을 nhn meetup 에서 공부하시는 것을 추천드립니다. 매우 설명이 잘 돼있고 중요한 개념입니다!!
어떠한 submit 필요 없이 단순 input 만 필요한 경우에도 form 태그를 구성하는 것을 추천드립니다. 그 이유는 맨 앞서 말한 접근성 측면과 같은 이유와 같습니다.
Author And Source
이 문제에 관하여(HTML Form 마크업, Vanila JS 를 통한 인풋 검증 및 AJAX Submit 요령), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@seop/HTML-Form-마크업-Vanila-JS-를-통한-인풋-검증-및-AJAX-Submit-요령저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)