최근 진행한 프로젝트에서 Javascript로 Form태그 하위의 Input 요소들이 유동적으로 추가 및 삭제되는 기획이 많아서, Javascript로 어떻게 하면 유동적으로 첨삭되는 Input태그들과 Form을 손쉽게 POST 전송하여 데이터를 첨삭할 수 있을까 고민하다 JsFormController라는 Class를 만들어보며 나름 뜻깊었고, 본인과 같은 고민을 하시는 분들께 약소하게나마 도움이 되고자 포스팅합니다.
- javascript를 사용하여 form 태그 하위 요소들을 핸들링하여 fetch 함수로 비동기 post 전송을 실행해보자.
- 본 예제는 Insert 부분까지만 다루며 update, destory 등은 스스로 해보면서 학습하길 권장합니다.
1. JsFormController.js 이름의 Class 만들기
- new 연산자를 사용하여 JsFormController를 생성하는 페이지의 Form태그 하위 요소들을 자동으로 설정하게 생성자 설정
- 생성자에서 현재 페이지에 맞는 Form태그의 하위 요소들을 초기화하는 init() 메서드를 설정
class JsFormController {
// New 연산자를 통한 현재 Class 생성시 자동 실행되는 생성자
constructor() {
this.init();
}
init() {
// 현재 페이지에 있는 Form Id
this.formId = document.forms[0].id;
// Form 하위 selectBox 요소 전역 변수 초기화
if (document.getElementById(this.formId).getElementsByTagName('select')) {
this.selectElements = document.getElementById(this.formId).getElementsByTagName('select');
}
// Form 하위 input 요소 전역 변수 초기화
if (document.getElementById(this.formId).getElementsByTagName('input')) {
this.inputElements = document.getElementById(this.formId).getElementsByTagName('input');
}
// Form 하위 textarea 요소 전역 변수 초기화
if (document.getElementById(this.formId).getElementsByTagName('textarea')) {
this.textareaElements = document.getElementById(this.formId).getElementsByTagName('textarea');
}
// Form 하위 Input File 요소를 담을 전역 변수 생성
this.fileElements = new Map();
}
}
2. dataSetting() 함수 생성
- init() 호출을 통해 초기화된 각 요소들에 name,value를 Map계열 객체의 key-value로 설정하는 dataSetting() 메서드 생성
class JsFormController {
constructor() {...}
init() {...}
dataSetting() {
let retrunData = new Map();
// select box
if (this.selectElements.length > 0) {
for (let selectElement of this.selectElements) {
retrunData.set(selectElement.name, selectElement.value);
}
}
// input tag
if (this.inputElements.length > 0) {
for (let inputElement of this.inputElements) {
if (inputElement.getAttribute('type') != null && inputElement.getAttribute('type') === 'radio') {
// input radio
if (inputElement.checked === true) {
retrunData.set(inputElement.name, inputElement.value);
}
} else if (inputElement.getAttribute('type') != null && inputElement.getAttribute('type') === 'checkbox') {
// input checkbox
if (inputElement.checked === true) {
retrunData.set(inputElement.name, inputElement.value);
}
} else { // input text
if (inputElement.name.includes('[]')) { // when input type name array
if(inputElement.value.includes(",")) {
// ,(쉼표) 문자가 자연스레 아스키코드로 전환되게 변경
inputElement.value = inputElement.value.replace(',',',');
}
if (!retrunData.get(inputElement.name)) {
// 배열로 넘어온 input name값이 처음 값일때 설정
retrunData.set(inputElement.name, [inputElement.value]);
} else {
// 배열로 넘어온 input name값이 1개 이상일 때 설정
let dumpArr = retrunData.get(inputElement.name);
dumpArr.push(inputElement.value);
retrunData.set(inputElement.name, dumpArr);
}
} else { // default
retrunData.set(inputElement.name, inputElement.value);
}
}
}
}
// input file
for (let inputElement of this.inputElements) {
if (inputElement.files != null) {
if (inputElement.name.includes('[]')) { // when input File name array
if (!this.fileElements.get(inputElement.name)) {
// 배열로 넘어온 input file type name값이 처음 값일때 설정
this.fileElements.set(inputElement.name, [inputElement.files]);
} else {
// 배열로 넘어온 input file type name값이 1개 이상일 때 설정
let dumpArr = this.fileElements.get(inputElement.name);
dumpArr.push(inputElement.files);
this.fileElements.set(inputElement.name, dumpArr);
}
} else { // default
this.fileElements.set(inputElement.name, inputElement.files);
}
}
}
// textarea tag
if (this.textareaElements.length > 0) {
for (let textareaElement of this.textareaElements) {
// when textarea type name array
if (textareaElement.name.includes('[]')) {
if (!retrunData.get(textareaElement.name)) {
let firstValue = new Array();
firstValue.push(textareaElement.value);
retrunData.set(textareaElement.name, firstValue);
} else {
let firstAfterValue = retrunData.get(textareaElement.name);
firstAfterValue.push(textareaElement.value);
retrunData.set(textareaElement.name, firstAfterValue);
}
} else { // default
retrunData.set(textareaElement.name, textareaElement.value);
}
}
}
return retrunData;
}
}
3. insert() 함수 생성
- form 태그 하위 요소들에 값을 다 채운 후, submit 시 실행될 insert()함수를 생성한다.
- fetch 함수를 이용하여 비동기식 POST전송을 실행한다.
class JsFormController {
constructor() {...}
init() {...}
dataSetting() {...}
insert() {
// 새로운 FormData객체 생성
let postFormData = new FormData;
// 현재 페이지 Form 하위 요소의 name,value를 key-value의 형태로 담은 map객체 생성
let inputFormData = this.dataSetting();
// Map 형식의 데이터를 새로 생성한 FormData 형식으로 재가공
for (let [key, value] of inputFormData) {
postFormData.append(key, value);
}
// File tag의 경우 파일이 존재할 경우에만 FormData객체에 추가함
if (this.fileElements != null && this.fileElements.size > 0) {
for (let [key, value] of this.fileElements) {
if (key.includes('[]')) { // type name array
for (let i = 0; i < value.length; i++) {
if (value[i].length > 1) {
// multiple
for (let y = 0; y < value[i].length; y++) {
postFormData.append(key, value[i][y]);
}
} else {
// sinlge
postFormData.append(key, value[i][0]);
}
}
} else { // default
postFormData.append(key, value[0]);
}
}
}
// Insert
fetch(this.requestURL + '/insert', {
method: 'POST',
cache: 'no-cache',
body: postFormData,
})
.then((response) => response.json())
.then((data) => {
if (data.is_success == true) {
// back단에서 성공시 작업처리
} else {
// back단에서 실패시 return하는 에러를 핸들링하여 후작업 처리
}
})
.catch((error) => {
// fetch로 전송하는 값에 대한 에러 핸들링
});
return false;
}
}
'Language > JavaScript' 카테고리의 다른 글
서버 사이드 렌더링(SSR) 이해하기 (2) | 2023.11.23 |
---|---|
웹 애플리케이션의 꽃 - 비동기(asynchronous) 쉽게 이해하기 (1) | 2023.11.20 |
[프로그래머스 코딩테스트] Summer/Winter Coding(~2018) - 소수 만들기 (0) | 2022.04.07 |
[프로그래머스 코딩테스트] 완전탐색 - 모의고사 (0) | 2022.03.31 |
[프로그래머스 코딩테스트] 찾아라 프로그래밍 마에스터 - 폰켓몬 (0) | 2022.03.28 |