0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

event.preventDefault と form.submit() で、なぜ押下された button type="submit" の情報が送信できなくなるのか

Last updated at Posted at 2025-08-17

タイトルの件、人から尋ねられました。備忘録として、少し整理したものを初学者向けに解説します。

結論

form.submit() によってフォームがサブミットされたからといって、submit ボタンが押されたことにはならないためです。<button type="submit" name="button-id" value="123"> を押された際に送信される 123 はあくまでもそのボタンを 押した ときに送られます。

事象

以下のようなフォームがあるときに button-id の値が送信されない、といった事象がありました。 favorite の値は送信されます。

<form id="test-form">
  <input type="text" name="favorite" value="CPU">
  <button type="submit" name="button-id" value="123">go</button>
</form>

<script>
document
	.querySelector('#test-form')
	.addEventListener('submit', function(event) {
		event.preventDefault();
        /* 処理 */
	    event.target.submit();
     });
</script>

解説

イベント

本来 Web ページは表示して終わりです(画面表示後にユーザーが目で眺めていても、そのことをスマホやパソコンは検知しないでしょう)。しかし実際にはユーザーが操作を行ったり(e.g. ボタンをクリックする)、 Web ページにちょっとした変化が起こったり(e.g. 途中だった画面の読み込みが完了する)といった様々な出来事が起きます。プログラマがこの出来事と処理を対応づけるために、出来事を管理する方法が提供されています。

ここでいくつか用語を導入します。発生する出来事を イベント といい、出来事が起きることを「イベントが 発火 する」といいます。たとえば「ユーザーがボタンをクリックした」場合であれば「 click イベントが発火する」といえます。イベントの発火と処理を結びつける方法は2つあります。ここではそのひとつ、イベントの発火時に実行する処理をあらかじめ登録しておき、発火を待ち受ける方法を紹介します。これを イベントリスナ といいます。

document
    .querySelector('#test-form')
    .addEventListener('submit', function(event) {
        event.preventDefault();
        /* 処理 */
        event.target.submit();
     });

先ほどのコードの一部です。 querySelector で指定した form タグに addEventListener メソッドでイベントリスナを登録します。第一引数の submit により、「 submit イベントの発生を待ち受ける」ことを指定し、第二引数の関数により、イベント発火時の処理を記載します。関数の引数には Event オブジェクトが渡されます。

preventDefault

event.preventDefault();

上記ではイベント発火時に行うべき処理を記載しました。しかし、開発者による明示的な処理をなにも書かずとも submit イベントの発火時には画面遷移が行われます( link タグの click イベントが発火したときもそうですね)。開発者が何もせずとも、あらかじめブラウザ( User Agent )に用意された既定の処理が実行されます。

preventDefault メソッドにはこの既定の処理を止める働きがあります。今回発火した submit イベントであれば、ページ遷移処理が取り消されます。

submit メソッド

event.target.submit();

evernt.target によってイベントが発火した HTML 要素への参照を取得できます。今回であれば form 要素です。 form 要素は JavaScript 上で HTMLFormElement クラスとして扱われます。 HTMLFormElement オブジェクトの submit メソッドを呼び出すと、フォームを送信させます。

submit ボタンの挙動

<button type="submit" name="button-id" value="123">go</button>

この submit ボタンがクリックされると button-id=123 がフォームのパラメータとして送信されます。ただし、 ボタン(とその値)がフォームの送信データに含まれるのは、そのボタン自身が送信のきっかけとなった場合のみです 。 preventDefault 後に関数内で submit() メソッドを呼び出しても、 submit ボタンの情報は送信されません。

A button (and its value) is only included in the form submission if the button itself was used to initiate the form submission.

https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element

submit ボタンの情報が送信されない理由

ここまでの話を整理すると、以下のようになります。

  1. submit ボタンのクリックによって submit イベントが発火される
  2. preventDefault によって 1. によるフォームの送信が取り消される
  3. submit() メソッド呼び出しによって( 1. とは別に新しく)フォームが送信される
  4. submit ボタンの情報は 3. では送信されない

背景等

以上、前から読むと「そんなの当たりまえ」と思われるかもしれません。わたしもそう思います。しかしあくまでも記載したサンプルは大幅に簡略化したものです。実際のコードは疑わしい箇所が多く、一瞬分からなくなってしまいました。

サブミットボタンの挙動について知りたかった点が MDN に載っておらず、 html.spec.whatwg.org から発見できて良かったです。ただ submit() メソッドの挙動の詳細は調べきれていません。私の予想では submit() では submit イベントが発火しないが requestSubmit() ならばするため、無限ループとなる はずなのですが、実際には無限ループは発生しませんでした。 event.submitter.click() でも無限ループは発生しませんでした。この点を理解したいです…。

最終的に、私が尋ねられた件ではそもそも preventDefault() と submit() を使う必要がありませんでした。が、この記事の目的は挙動の理由を理解することであり、どのように実装すべきかを検討することではないため、割愛します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?