jQuery / Method / .submit() - 폼 전송 이벤트
jQuery에서 폼 제출을 처리할 때는 $(form).on("submit", handler)로 form의 submit 이벤트를 받습니다. 코드에서 브라우저 입력 검사를 거쳐 제출을 요청하려면 form.requestSubmit()을 사용합니다. 기존 .submit() 축약 메서드, jQuery의 이벤트 발생, 브라우저의 form.submit()은 같은 이름처럼 보여도 검사와 이벤트 처리 경로가 다릅니다.
이벤트 연결과 제출 요청 구분하기
jQuery .submit() 축약 메서드는 3.3에서 deprecated로 분류되었습니다. .submit(handler)는 연결, 인자 없는 .submit()은 이벤트 발생을 뜻합니다. 확인한 전체 버전 3.7.1·4.0.0에서는 두 호출이 존재하지만 새 코드는 의미가 분명한 .on("submit", handler) 등을 사용합니다. deprecated를 곧바로 삭제되었다는 뜻으로 해석하지 않습니다.
submit 이벤트는 버튼이 아니라 폼에 발생합니다. form에서 처리하면 클릭뿐 아니라 Enter와 코드의 제출 요청도 같은 처리 지점으로 모을 수 있습니다. 버튼 click에만 검사 코드를 넣으면 다른 제출 경로를 놓칠 수 있습니다.
| 방식 | 입력 검사와 이벤트 | 사용 기준 |
|---|---|---|
| .on("submit", handler) | 이벤트 처리 함수를 연결하며 자체 제출은 하지 않음 | 폼 제출 전 처리 |
| 실제 submit 버튼 또는 requestSubmit() | required 등 검사 후 유효하면 submit 이벤트 | 일반적인 제출 요청 |
| jQuery .trigger("submit") | jQuery 핸들러 실행이 브라우저 입력 검사와 같은 경로는 아님 | 이벤트 발생 목적을 이해하고 사용 |
| 브라우저 form.submit() | 기본 입력 검사와 submit 이벤트를 우회 | 우회가 필요한 특별한 처리 |
입력 검사와 여러 제출 경로의 전체 예제
UTF-8의 submit-demo.html로 저장하고 엽니다. jQuery 전체 파일 4.0.0을 인터넷에서 읽으며 서버나 빌드 없이 실습합니다. 예제는 모든 제출을 preventDefault로 막고 결과만 표시하므로 외부 전송이나 저장은 하지 않습니다. Windows Edge에서 4.0.0·3.7.1으로 아래 경로와 제출 버튼 정보를 검증했습니다.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Inspect form submit events</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 720px; margin: 20px; }
label { display: block; margin-top: 12px; }
input, select, button { font: inherit; max-width: 100%; margin: 5px 0; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<form id="chooser">
<label for="person">Name</label>
<input id="person" name="person" required>
<label for="fruit">Fruit</label>
<select id="fruit" name="fruit" required>
<option value="">Choose a fruit</option>
<option value="apple">Apple</option><option value="banana">Banana</option>
</select>
<button id="inside" type="submit" name="intent" value="inside">Inspect inside</button>
</form>
<button id="outside" type="submit" form="chooser" name="intent" value="outside">Inspect outside</button>
<button id="request" type="button">requestSubmit(inside)</button>
<button id="trigger" type="button">jQuery trigger submit</button>
<button id="restore" type="button">Reset</button>
<label><input id="automatic" type="checkbox">Request submission when fruit changes</label>
<pre id="result" aria-live="polite">events=0
No submission inspected.</pre>
<script>
jQuery(function ($) {
const form = document.querySelector("#chooser");
let events = 0;
$(form).on("submit", function (event) {
event.preventDefault(); events++;
if (!form.reportValidity()) {
$("#result").text("events=" + events + "\nInvalid data; not inspected."); return;
}
const submitter = event.originalEvent ? event.originalEvent.submitter : null;
const data = submitter ? new FormData(form, submitter) : new FormData(form);
$("#result").text("events=" + events + "\nsubmitter=" + (submitter ? submitter.id : "(none)") +
"\nvalues=" + JSON.stringify(Object.fromEntries(data)));
});
$("#request").on("click", function () { form.requestSubmit(document.querySelector("#inside")); });
$("#trigger").on("click", function () { $(form).trigger("submit"); });
$("#fruit").on("change", function () {
if (document.querySelector("#automatic").checked) form.requestSubmit();
});
$("#restore").on("click", function () {
form.reset(); document.querySelector("#automatic").checked = false; events = 0;
$("#result").text("events=0\nNo submission inspected.");
});
});
</script>
</body>
</html>
초기 출력입니다. events는 submit 핸들러에 들어온 횟수이며 서버 저장 성공 횟수가 아닙니다.
events=0
No submission inspected.
- 아무것도 채우지 않고 Inspect inside, Inspect outside, requestSubmit(inside)를 각각 누릅니다. required 검사가 먼저 막으므로 events=0입니다.
- 빈 상태에서 jQuery trigger submit을 누릅니다. 핸들러에 들어와 events=1이 되지만 reportValidity 검사로 Invalid data; not inspected.가 표시됩니다.
- Reset 후 Name에 JB, Fruit에 Apple을 입력하고 Inspect inside를 누릅니다. events=1, submitter=inside와 person·fruit·intent 값이 표시됩니다.
- Inspect outside는 submitter=outside, intent=outside를 보여줍니다. 폼 밖 버튼도 form="chooser"로 같은 폼에 연결됩니다.
- requestSubmit(inside)는 inside를 제출 버튼으로 지정합니다. Name 입력창에서 Enter를 누르는 경로도 이 예제에서는 첫 제출 버튼 inside로 처리됩니다.
- 유효한 값에서 jQuery trigger submit은 submitter=(none)이며 버튼 intent는 데이터에 없습니다.
- Request submission when fruit changes를 켜고 Banana로 바꿉니다. requestSubmit()을 버튼 인자 없이 호출하므로 submitter=(none)입니다.
- Reset은 값·자동 요청 체크·카운터를 되돌립니다.
event.originalEvent.submitter는 실제 SubmitEvent의 제출 버튼을 읽는 경로입니다. jQuery가 인위적으로 만든 이벤트에는 originalEvent가 없을 수 있어 분기했습니다. FormData(form, submitter)를 사용하면 해당 버튼의 name/value도 포함됩니다. 같은 name이 반복되는 폼에서는 Object.fromEntries가 마지막 값만 남길 수 있으므로, 이 단일 값 데모를 체크박스 배열 수집 예제로 그대로 확장하지 않습니다.
외부 버튼·자동 요청·전송 중지하기
폼 외부의 p나 div에 클릭 동작을 붙이는 대신 실제 button type="submit"과 form 속성을 쓰면 브라우저의 키보드·제출 동작을 활용할 수 있습니다. 외부라는 위치 자체가 required를 무시하게 만들지는 않습니다. 어떤 제출 API를 사용했는지가 중요합니다.
requestSubmit()은 브라우저의 제약 검사를 거치고 유효할 때 이벤트를 발생시킵니다. 인자로 지정하는 요소는 해당 폼에 연결된 제출 버튼이어야 합니다. 예제는 지정 버튼이 있는 호출과 없는 호출을 모두 보여줍니다.
select의 change에서 즉시 제출하면 방향키로 값을 고르는 중 의도보다 빨리 이동할 수 있습니다. 예제는 자동 요청을 명시적으로 켜게 했고 실제 페이지 이동도 막았습니다. 서비스에서는 필터 변경처럼 즉시 적용이 필요한지, 제출 버튼으로 확정해야 하는지 먼저 정합니다. .val()로 값을 바꾸는 것만으로 change가 자동 발생하는 것도 아닙니다.
event.preventDefault()는 기본 제출을 막습니다. 비동기 작업을 기다려야 한다면 이벤트 처리 중 먼저 막아야 하며, await 뒤에 호출해서 이미 진행된 제출을 되돌릴 수는 없습니다. 이 예제에는 비동기 전송이 없습니다. 실제 전송을 구현할 때는 처리 중 상태·중복 요청·실패 복구와 서버의 입력 검사를 별도로 설계합니다.
기존 .submit()과 브라우저 메서드 확인
다음은 기존 축약 메서드를 이해하는 작은 확인 코드입니다. 초기화가 끝난 뒤 실행하며, 화면에 붙이지 않은 폼의 핸들러가 기본 동작을 막으므로 서버 전송은 없습니다.
const $probe = $("<form>");
let calls = 0;
$probe.submit(function (event) {
event.preventDefault();
calls++;
});
$probe.submit();
console.log("legacy calls=" + calls);
Console 결과입니다. 예전 코드를 읽을 때는 함수 인자가 있는지 없는지부터 구분합니다.
legacy calls=1
.trigger("submit")도 핸들러 실행을 의미하며, 기본 동작을 막지 않으면 네이티브 메서드 호출로 이어질 수 있습니다. 버튼 클릭·브라우저 입력 검사를 완전히 재현하는 API라고 가정하지 않습니다. 예제는 합성 이벤트에서도 reportValidity로 검사한 뒤 결과를 보여줍니다.
브라우저 HTMLFormElement.submit()은 검사를 건너뛰고 submit 핸들러도 호출하지 않습니다. 확인 시험에서는 빈 required 필드를 가진 별도 폼을 iframe으로 제출하고 요청을 로컬에서 가로채, 빈 값 요청과 이벤트 0회를 확인했습니다. 실제 수신 서버의 저장 성공을 시험한 것은 아닙니다.
form.submit is not a function이 보이면 name 또는 id가 submit인 입력 요소가 메서드를 가렸는지도 확인합니다. reset 등 폼 API와 같은 이름도 피합니다. 선택자를 잘못 잡았거나 jQuery 객체와 DOM 폼을 혼동한 경우도 구분합니다. requestSubmit은 DOM 폼의 메서드이므로 jQuery 집합에서는 [0] 등으로 실제 요소를 얻어야 합니다.
실제 서버 제출로 바꾸려면 올바른 action·method와 수신 처리를 준비하고, 이 실습의 무조건적인 preventDefault·결과 표시 방식을 목적에 맞게 바꿉니다. 단순히 화면에 Valid라고 나왔다고 서버가 저장했다고 판단하지 않으며, required 등 브라우저 검사를 서버 검사의 대체로 사용하지 않습니다.




