JavaScript によるフォームの送信
ユーザーが HTML フォームを送信する場合、例えば送信ボタンをクリックすると、ブラウザーはHTTP リクエストを送信してフォーム内のデータを送信します。しかし、この宣言的な手法ではなく、ウェブアプリでは、フォーム送信を期待するエンドポイントにプログラムでデータを送信するために、fetch()
などの JavaScript API を使用することがあります。この記事では、この手法が重要なユースケースである理由と、その方法について説明します。
なぜ JavaScript を使用してフォームデータを送信するのか
標準の HTML フォーム送信は、フォームデータの送信に関するこの記事で説明されているように、データが送信された URL を読み込みます。つまり、ブラウザーウィンドウが全ページ読み込みでナビゲートされるということです。
しかし、多くのウェブアプリ、特にプログレッシブウェブアプリや単一ページアプリは、サーバーからデータをリクエストし、ページの関連部分を更新するために JavaScript API を使用しており、ページ全体を読み込むオーバーヘッドを避けています。
このため、これらのウェブアプリケーションがフォームデータを送信しようとする場合、ユーザーからの入力の収集のみに HTML フォームを使用し、データ送信には使用しません。ユーザーがデータを送信しようとすると、アプリケーションがコントロールを引き継ぎ、fetch()
などの JavaScript API を使用してデータを送信します。
JavaScript フォーム送信の問題
ウェブアプリがフォームデータを送信するサーバーエンドポイントがウェブアプリ開発者の制御下にある場合、開発者はフォームデータを任意の方法で送信できます。例えば、 JSON オブジェクトとして送信できます。
しかし、サーバーエンドポイントがフォームの送信を期待している場合、ウェブアプリはデータを具体的な方法でエンコードする必要があります。例えば、データがテキストのみの場合、 URL エンコード方式でキーと値の組が掲載されているリストを作成し、Content-Type
をapplication/x-www-form-urlencoded
として送信します。フォームにバイナリーデータが含まれている場合、multipart/form-data
コンテンツタイプを使用して送信する必要があります。
FormData
インターフェイスは、データのエンコード処理をこのように行います。この記事の残りの部分では、FormData
の概要を簡単に説明します。詳細は、FormData オブジェクトの使用ガイドをご覧ください。
FormData
オブジェクトを手動で構築
FormData
オブジェクトは、オブジェクトのappend()
メソッドを追加したいすべてのフィールドについて呼び出し、フィールドの名前と値を設定することによって構築できます。値は、テキストフィールドの場合は文字列、バイナリーフィールドの場合はBlob
(File
オブジェクトを含む)となります。
次の例では、ユーザーがボタンをクリックすると、フォーム送信という形でデータを送信します。
async function sendData(data) { // FormData インスタンスを構築 const formData = new FormData(); // テキストフィールドを追加 formData.append("name", "Pomegranate"); // ファイルを追加 const selection = await window.showOpenFilePicker(); if (selection.length > 0) { const file = await selection[0].getFile(); formData.append("file", file); } try { const response = await fetch("https://example.org/post", { method: "POST", // FormData インスタンスをリクエスト本体として設定 body: formData, }); console.log(await response.json()); } catch (e) { console.error(e); }}const send = document.querySelector("#send");send.addEventListener("click", sendData);
最初に新しい、空の
FormData
オブジェクトを構築します。次に、
append()
を 2 回呼び出し、FormData
オブジェクトに 2 つのアイテムを追加します。テキストフィールドとファイルです。最後に、
fetch()
API を使用してPOST
リクエストを行い、リクエスト本体としてFormData
オブジェクトを設定します。
Content-Type
ヘッダーを設定する必要がないことに注意してください。FormData
オブジェクトをfetch()
に渡すと、正しいヘッダーが自動的に設定されます。
FormData
オブジェクトと<form>
の関連付け
送信するデータが現実の<form>
から来る場合は、フォームをFormData
コンストラクターに渡すことで、FormData
インスタンスを生成することができます。
HTML で<form>
要素を宣言しているとします。
<form> <p> <label for="username">名前を入力してください:</label> <input type="text" name="username" value="Dominic" /> </p> <p> <label for="avatar">アバターを選択してください</label> <input type="file" name="avatar" required /> </p> <input type="submit" value="Submit" /></form>
フォームには、テキスト入力、ファイル入力、送信ボタンが含まれます。
JavaScript は次のとおりです。
const form = document.querySelector("#userinfo");async function sendData() { // FormData オブジェクトをフォーム要素に関連付ける const formData = new FormData(form); try { const response = await fetch("https://example.org/post", { method: "POST", // FormData インスタンスをリクエスト本体として設定 body: formData, }); console.log(await response.json()); } catch (e) { console.error(e); }}// フォーム送信を引き継ぐform.addEventListener("submit", (event) => { event.preventDefault(); sendData();});
フォーム要素に送信イベントハンドラーを追加します。最初の呼び出しでは、ブラウザーの組み込みフォーム送信を防ぐためにpreventDefault()
が呼び出され、その後、フォーム要素を取得してそれをFormData
コンストラクターに渡すsendData()
が呼び出されます。
その後、fetch()
を使用して、 HTTP のPOST
リクエストとしてFormData
インスタンスを送信します。
関連情報
学習コース
上級トピック
- JavaScript によるフォームの送信
- カスタムフォームコントロールの作成方法
- 古いブラウザーでの HTML フォーム
- フォームへの高度なスタイル設定