안녕하세요. 이번 시간에는 AJAX로 폼 전송을 가능케해주는 FormData 객체에 대해 알아보겠습니다.
보통은 AJAX로 폼(form 태그) 전송을 할 일이 거의 없습니다. 주로 JSON 구조로 키-값 데이터를 전송하니까요. 하지만 폼 전송이 필요한 경우가 있습니다. 바로 이미지를 AJAX로 업로드할 경우입니다. 물론 이미지는 base64나, buffer, 이진 데이터 형식으로 서버로 전송해도 됩니다. 하지만 가장 자연스러운 것은 폼을 통해서 업로드하는 것이죠. input[type=file]을 사용해서요.
그런데 폼과 AJAX를 같이 쓴다는 것은 좀 이상하죠? 보통 폼 하면 제출 버튼을 누르면 action 속성에 지정한 페이지로 이동하면서 데이터를 전송하니까요. AJAX는 반대로 제출 버튼을 누르면 기본 폼 동작은 e.preventDefault()
로 멈추고, 페이지 전환 없이 데이터를 전송합니다.
페이지 전환 없이 폼 데이터를 제출하고 싶을 때 바로 FormData 객체를 사용합니다. AJAX 전송법은 다음 시간에 알아보고, 이번 시간에는 이 객체에 대해서 자세히 살펴보겠습니다.
FormData 객체는 window.FormData
에 위치합니다.
var formData = new FormData();
formData.append('name', 'zerocho');
formData.append('item', 'orange');
formData.append('item', 'melon');
자, new FormData()
로 새로운 객체를 생성해주시고요. append 메소드로 키-값 형식으로 하나씩 추가해주시면 되겠습니다. 같은 키를 가진 값을 여러 개 넣을 수도 있습니다. 덮어씌워지지 않고 추가됩니다. 참고로 값은 문자열로 자동 변환됩니다. 숫자를 넣어도 문자열이 되고, 배열을 넣어도 콤마로 구분한 문자열이 됩니다. 객체는 넣으면 무시됩니다. 이 점을 유의하세요!
기존 폼이 있는 경우는
var formData = new FormData(document.getElementById('폼 아이디'));
이렇게 선택하면 알아서 폼의 내용들의 formData 객체 안에 들어갑니다. 편리하죠?
append로 넣을 수만 있는 게 아니라 내용물을 확인할 수도 있습니다. 위의 코드와 이어집니다.
formData.has('item'); // true
formData.has('money'); // false
formData.get('item'); // orange
formData.getAll('item'); // ['orange', 'melon']
has 메소드로는 해당하는 키가 존재하는 지 확인할 수 있고요. get 메소드로 직접 가져올 수 있습니다. 유의할 점은 get은 처음 저장한 값 하나만 불러옵니다. 위에서 item 키에 값을 orange와 melon 두 개를 줬습니다. 그런데 get만 하면 orange밖에 뜨지 않습니다. 이 때 getAll 메소드가 있습니다. 해당 키에 매칭되는 값들을 전부 배열로 반환합니다.
var keys = formData.keys();
keys.next(); // { done: false, value: 'name' }
keys.next(); // { done: false, value: 'item' }
keys.next(); // { done: false, value: 'item' }
keys.next(); // { done: true, value: undefined }
var values = formData.values();
values.next(); // { done: false, value: 'zerocho' }
values.next(); // { done: false, value: 'orange' }
values.next(); // { done: false, value: 'melon' }
values.next(); // { done: true, value: undefined }
var entries = formData.entries();
entries.next(); // { done: false, value: ['name', 'zerocho'] }
entries.next(); // { done: false, value: ['item', 'orange'] }
entries.next(); // { done: false, value: ['item', 'melon'] }
entries.next(); // { done: true, value: undefined }
위의 코드는 반복자(이터레이터)를 사용한 코드입니다. 이터레이터 강좌는 여기를 참조하세요. 이터레이터는 상황에 따라 매우 유용할 수 있습니다. 물론 IE에서 안 되는 단점이 있지만요. FormData의 키나 값, 또는 키와 값 모두를 쉽게 보여줍니다. 반복문에 사용하면 좋습니다.
formData.append('test', ['hi', 'zero']);
formData.get('test'); // hi, zero
formData.delete('test');
formData.get('test'); // null
formData.set('item', 'apple');
formData.getAll('item'); // ['apple']
formData에 이제 값을 지워봅시다. delete 메소드를 사용하면 됩니다. append와 비슷한 set 메소드도 있습니다. set과 append의 차이점은 set도 추가를 해주기는 하지만, 기존 키가 있으면 그 값을 모두 덮어씌워버립니다. 위의 item에 대한 값이 orange와 melon이었는데 apple을 set하는 순간 item 값이 apple 하나로 덮어씌워졌습니다.
이상으로 FormData의 API에 대해 알아봤습니다. FormData에 이미지를 담고 싶으면
formData.append('img', document.getElementById('파일 인풋').files[0])
위와 같이 넣어주고 서버로 formData를 보내버리면 됩니다. 파일이 여러 개면 반복문으로 append를 하면 되고요. 주의할 점은 여러 개를 append할 때 항상 키값(위에서는 img)은 같아야 여러 파일이 같은 키로 업로드 됩니다.
네, 이제 폼데이터는 마스터 하셨고요. 이 값을 서버로 보내기만 하면 됩니다. AJAX로 보내려면 XMLHttpRequest에 대해서 알아야겠죠? 다음 시간에는 XMLHttpRequest에 대해 알아봅시다!
제로초님 여러 강의 정말 잘보고 있습니다.
혹시 사진을 폼데이터를 통해서보내고,
일반 데이터들(본문 제목, 내용 등)을 같이 보낼 수 있는 방법이 있을까요?