FormData オブジェクトの使用
FormData
オブジェクトは、フェッチまたは XMLHttpRequest API を使用して送信するためのキーと値のペアの集合をコンパイルできます。本来はフォームデータの送信に使用することを想定していましたが、キーのついたデータを伝送するためにフォームとは独立して使用することもできます。伝送されるデータは、フォームのエンコードタイプが multipart/form-data
に設定されている場合に、submit()
メソッドで送信する際に使用するデータと同じ形式です。
ゼロから FormData
オブジェクトを作成する
以下のように FormData
オブジェクトはあなた自身で作成でき、インスタンス化したら append()
メソッドを呼び出すことでフィールドに付加します。
const send = document.querySelector("#send");
send.addEventListener("click", async () => {
const formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456);
// file 型の <input> 要素
const avatar = document.querySelector("#avatar");
formData.append("avatar", avatar.files[0]);
// JavaScript のファイル風オブジェクト
const content = '<q id="a"><span id="b">hey!</span></q>';
const blob = new Blob([content], { type: "text/xml" });
formData.append("webmasterfile", blob);
const response = await fetch("http://example.org/post", {
method: "POST",
body: formData,
});
console.log(await response.json());
});
メモ: "avatar"
および "webmasterfile"
フィールドはどちらも、ファイルを含んでいます。フィールド "accountnum"
に与えた数値は FormData.append()
メソッドにより直ちに文字列へ変換されます(フィールドの値として Blob
、 File
、文字列のいずれかを取ることができます。値が Blob
でも File
でもない場合は、文字列に変換されます)。
この例では、 "username"
, "accountnum"
, "avatar"
, "webmasterfile"
というフィールドの値を含む FormData
インスタンスを構築し、 fetch()
を使用してフォームのデータを送信します。 "webmasterfile"
フィールドは Blob
です。 Blob
オブジェクトは、不変的な生データのファイルのようなオブジェクトを表します。 Blob は、必ずしも JavaScript に適した形式ではないデータを表します。 File
インターフェイスは Blob
をベースにしており、 Blob の機能を継承し、ユーザーのシステム上のファイルをサポートするように拡張されています。 Blob
を作成するには、 Blob()
コンストラクターを呼び出します。
HTML フォームから FormData
オブジェクトを取り出す
既存の <form>
のデータを含む FormData
オブジェクトを構築するには、 FormData
オブジェクトの作成時にその form 要素を指定します。
メモ: FormData
は name
属性を使用する入力フィールドのみを使用します。
const formData = new FormData(someFormElement);
例:
const send = document.querySelector("#send");
send.addEventListener("click", async () => {
// <form> 要素
const userInfo = document.querySelector("#user-info");
const formData = new FormData(userInfo);
const response = await fetch("http://example.org/post", {
method: "POST",
body: formData,
});
console.log(await response.json());
});
以下のように、FormData
オブジェクトをフォームより取得してから送信するまでの間に、追加のデータを付加することもできます。
const send = document.querySelector("#send");
send.addEventListener("click", async () => {
const userInfo = document.querySelector("#user-info");
const formData = new FormData(userInfo);
formData.append("serialnumber", 12345);
const response = await fetch("http://example.org/post", {
method: "POST",
body: formData,
});
console.log(await response.json());
});
これにより、必ずしもユーザーが編集可能である必要がない追加情報を含めるために、送信前にフォームデータを拡張することができます。
FormData オブジェクトを使用したファイルの送信
FormData
を使用してファイルを送信することもできます。type が "file" である <input>
要素を、<form>
に含めます。
<form enctype="multipart/form-data" method="post" name="fileinfo" id="fileinfo">
<p>
<label
>Your email address:
<input
type="email"
autocomplete="on"
name="userid"
placeholder="email"
required
size="32"
maxlength="64" />
</label>
</p>
<p>
<label
>Custom file label:
<input type="text" name="filelabel" size="12" maxlength="32" />
</label>
</p>
<p>
<label
>File to stash:
<input type="file" name="file" required />
</label>
</p>
<p>
<input type="submit" value="Stash the file!" />
</p>
</form>
そして、以下のようなコードを使用して送信できます。
const form = document.querySelector("#fileinfo");
form.addEventListener("submit", async (event) => {
const formData = new FormData(form);
formData.append("CustomField", "This is some extra data");
const response = await fetch("stash.php", {
method: "POST",
body: formData,
});
event.preventDefault();
});
メモ:
フォームへの参照を渡した場合は、 open()
の呼び出しで指定したリクエストメソッドよりもフォームで指定したメソッドを優先します。
警告:
FormData を使用して、XMLHttpRequest
またはフェッチ API を使用して、 multipart/form-data
の Content-Type で POST リクエストを送信する場合(ファイルや Blob をサーバーにアップロードする場合など)、リクエストの Content-Type
ヘッダーを明示的に設定しないでください。そうすると、ブラウザーがリクエスト本文のフォームフィールドの区切りに使用する境界の表現で Content-Type ヘッダーを設定することができなくなります。
以下のように、直接 File
や Blob
を FormData
オブジェクトへ追加することもできます。
data.append("myfile", myBlob, "filename.txt");
append()
メソッドを使用する際は、オプションの第 3 引数を使用して、Content-Disposition
ヘッダーに含めるファイル名を渡すことができます。これはサーバーへ送信されます。ファイル名を指定しない(あるいは引数がサポートされない)場合は、 "blob" という名前が使用されます。
formdata イベントの使用
FormData
オブジェクトよりも新しくプラットフォームに追加されたのが formdata
イベントです。これは、フォームのデータを表すエントリーのリストが作成された後に HTMLFormElement
オブジェクトで発行されます。このイベントは、フォームが送信されたときに発行されますが、 FormData()
コンストラクターが呼び出されたときにも発行されます。
これにより、 FormData
オブジェクトを formdata
イベントの発行を受けてすばやく取得することができるようになり、自分でまとめる必要がなくなります。
例えば、 JavaScript では次のようにフォームを参照できます。
const formElem = document.querySelector("form");
submit
イベントのハンドラーでは、 preventDefault
を使用して既定のフォーム送信を停止してから、 FormData
コンストラクターを呼び出して formdata
イベントを発行させます。
formElem.addEventListener("submit", (e) => {
// フォーム送信時に既定の動作を抑止
e.preventDefault();
// FormData オブジェクトを作成し、 formdata イベントを発行
new FormData(formElem);
});
formdata
イベントが発行されると、 FormData
オブジェクトに FormDataEvent.formData
を使ってアクセスし、必要な処理を行うことができます(以下では、 XMLHttpRequest
を使ってサーバーに送信しています)。
formElem.addEventListener("formdata", (e) => {
console.log("formdata fired");
// イベントオブジェクトから形式データを取得します。
const data = e.formData;
for (const value of data.values()) {
console.log(value);
}
// fetch() でデータを送信
fetch("/formHandler", {
method: "POST",
body: data,
});
});
分かりましたか
FormData
オブジェクトは、無効になっているフィールドや無効になっているフィールドセットのデータを含めることはできません。