FormData オブジェクトの使用

FormData オブジェクトは、XMLHttpRequest を使用して送信するためのキーと値のペアのセットを収集可能にします。本来はフォームデータの送信に使用することを想定していましたが、キーのついたデータを伝送するためにフォームとは独立して使用することもできます。伝送されるデータは、フォームのエンコードタイプが multipart/form-data に設定されている場合に、submit() メソッドで送信する際に使用するデータと同じ形式です。

ゼロから FormData オブジェクトを作成する

以下のように FormData オブジェクトはあなた自身で作成でき、インスタンス化したら append() メソッドを呼び出すことでフィールドに付加します:

const formData = new FormData();

formData.append("username", "Groucho");
formData.append("accountnum", 123456); // 数値 123456 は直ちに文字列 "123456" へ変換されます

// HTML の file input でユーザーが選択したファイル
formData.append("userfile", fileInputElement.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 request = new XMLHttpRequest();
request.open("POST", "http://foo.com/submitform.php");
request.send(formData);

メモ: フィールド "userfile" および "webmasterfile" はどちらも、ファイルを含んでいます。フィールド "accountnum" に与えた数値は FormData.append() メソッドにより直ちに文字列へ変換されます (フィールドの値として BlobFile、または文字列をとることができます。値が Blob でもファイルでもない場合は、文字列に変換されます)。

この例では、 "username", "accountnum", "userfile", "webmasterfile" というフィールドの値を含む FormData インスタンスを構築し、 XMLHttpRequest のメソッド send() を使用してフォームのデータを送信します。 "webmasterfile" というフィールドは Blob です。 Blob オブジェクトは、不変的な生データのファイルのようなオブジェクトを表します。 Blob は、必ずしも JavaScript に適した形式ではないデータを表します。 File インターフェースは Blob をベースにしており、 Blob の機能を継承し、ユーザーのシステム上のファイルをサポートするように拡張されています。 Blob を作成するには、 Blob() constructor コンストラクターを呼び出します。

HTML フォームから FormData オブジェクトを取り出す

既存の <form> のデータを含む FormData オブジェクトを構築するには、 FormData オブジェクトの作成時にその form 要素を指定します。

メモ: FormData は name 属性を使用する入力フィールドのみを使用します。

const formData = new FormData(someFormElement);

例:

const formElement = document.querySelector("form");
const request = new XMLHttpRequest();
request.open("POST", "submitform.php");
request.send(new FormData(formElement));

以下のように、FormData オブジェクトをフォームより取得してから送信するまでの間に、追加のデータを付加することもできます。

const formElement = document.querySelector("form");
const formData = new FormData(formElement);
const request = new XMLHttpRequest();
request.open("POST", "submitform.php");
formData.append("serialnumber", serialNumber++);
request.send(formData);

これにより、必ずしもユーザーが編集可能である必要がない追加情報を含めるために、送信前にフォームデータを拡張することができます。

FormData オブジェクトを使用したファイルの送信

FormData を使用してファイルを送信することもできます。type が "file" である <input> 要素を、<form> に含めます。

<form enctype="multipart/form-data" method="post" name="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>
<div id="output"></div>

そして、以下のようなコードを使用して送信できます。

const form = document.forms.namedItem("fileinfo");
form.addEventListener(
  "submit",
  (event) => {
    const output = document.querySelector("#output");
    const formData = new FormData(form);

    formData.append("CustomField", "This is some extra data");

    const request = new XMLHttpRequest();
    request.open("POST", "stash.php", true);
    request.onload = (progress) => {
      output.innerHTML =
        request.status === 200
          ? "Uploaded!"
          : `Error ${request.status} occurred when trying to upload your file.<br />`;
    };

    request.send(formData);
    event.preventDefault();
  },
  false
);

メモ: フォームへの参照を渡した場合は、 open() の呼び出しで指定したリクエストメソッドよりもフォームで指定したメソッドを優先します。

警告: FormData を使用して、XMLHttpRequest または Fetch_API を使用して、 multipart/form-data の Content-Type で POST リクエストを送信する場合 (Files や Blob をサーバーにアップロードする場合など)、リクエストの Content-Type ヘッダーを明示的に設定しないでください。そうすると、ブラウザーがリクエスト本文のフォームフィールドの区切りに使用する境界の表現で Content-Type ヘッダーを設定することができなくなります。

以下のように、直接 FileBlobFormData オブジェクトへ追加することもできます。

data.append("myfile", myBlob, "filename.txt");

append() メソッドを使用する際は、オプションの第 3 引数を使用して、Content-Disposition ヘッダーに含めるファイル名を渡すことができます。これはサーバーへ送信されます。ファイル名を指定しない (あるいは引数がサポートされない) 場合は、 "blob" という名前が使用されます。

formdata イベントの使用

FormData オブジェクトよりも新しくプラットフォームに追加されたのが formdata イベントです。これは、フォームのデータを表すエントリーのリストが作成された後に HTMLFormElement オブジェクトで発行されます。このイベントは、フォームが送信されたときに発行されますが、 FormData() コンストラクターが呼び出されたときにも発行されます。

これにより、 FormData オブジェクトを formdata イベントの発行を受けてすばやく取得することができるようになり、自分でまとめる必要がなくなります。

一般的には、シンプルな formdata イベントのデモのように、 JavaScript でフォームを参照して使用します。

const formElem = document.querySelector("form");

submit イベントのハンドラーでは、 preventDefault を使用して既定のフォーム送信を停止してから、 FormData コンストラクターを呼び出して formdata イベントを発行させます。

formElem.addEventListener("submit", (e) => {
  // on form submission, prevent default
  e.preventDefault();

  // construct a FormData object, which fires the formdata event
  new FormData(formElem);
});

formdata イベントが発行されると、 FormDataEvent.formData を使って FormData オブジェクトにアクセスし、必要な処理を行うことができます (以下では、 XMLHttpRequest を使ってサーバーに送信しています)。

formElem.addEventListener("formdata", (e) => {
  console.log("formdata fired");

  // Get the form data from the event object
  const data = e.formData;
  for (const value of data.values()) {
    console.log(value);
  }

  // submit the data via XHR
  const request = new XMLHttpRequest();
  request.open("POST", "/formHandler");
  request.send(data);
});

メモ: formdata イベントと FormDataEvent オブジェクトは、 Chrome ではバージョン 77 (および同等の Chromium) から、 Firefox ではバージョン 72 から利用可能です (Firefox 71 で dom.formdata.event.enabled を設定することで初めて利用可能になりました)。

FormData オブジェクトを使用せずに AJAX でフォームやファイルを送信する

FormData オブジェクトを使用せずに、AJAX でシリアライズしたり送信したりする方法を知りたい場合は、 こちらの節を参照してください。

分かりましたか

FormData オブジェクトは、無効になっているフィールドや無効になっているフィールドセットのデータを含めることはできません。

関連情報