この章では、HTMLフォームの送信について説明します。ファイルの有無、追加フィールドなどについてです。
FormDataオブジェクトは、その際に役立ちます。ご想像のとおり、HTMLフォームデータを表すオブジェクトです。
コンストラクタは次のとおりです。
let formData = new FormData([form]);
HTMLのform
要素が提供されている場合、そのフィールドは自動的にキャプチャされます。
FormData
の特別な点は、fetch
などのネットワークメソッドが、FormData
オブジェクトを本文として受け入れることができることです。エンコードされ、Content-Type: multipart/form-data
で送信されます。
サーバーの観点からは、通常のフォーム送信のように見えます。
単純なフォームの送信
まずは単純なフォームを送信してみましょう。
ご覧のとおり、ほぼ1行で記述できます。
<form id="formElem">
<input type="text" name="name" value="John">
<input type="text" name="surname" value="Smith">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
この例では、サーバーコードは私たちの範囲外であるため、提示されていません。サーバーはPOSTリクエストを受け取り、「ユーザーが保存されました」と返信します。
FormDataのメソッド
FormData
のフィールドは、以下のメソッドで変更できます。
formData.append(name, value)
– 指定されたname
とvalue
でフォームフィールドを追加します。formData.append(name, blob, fileName)
–<input type="file">
であるかのようにフィールドを追加します。3番目の引数fileName
は、ユーザーのファイルシステムのファイル名であるかのように、ファイル名(フォームフィールド名ではありません)を設定します。formData.delete(name)
– 指定されたname
のフィールドを削除します。formData.get(name)
– 指定されたname
のフィールドの値を取得します。formData.has(name)
– 指定されたname
のフィールドが存在する場合、true
を返し、そうでない場合はfalse
を返します。
フォームは技術的には同じname
を持つ複数のフィールドを持つことが許可されているため、append
を複数回呼び出すと、同じ名前のフィールドが追加されます。
append
と同じ構文を持つset
メソッドもあります。違いは、.set
は指定されたname
を持つすべてのフィールドを削除してから、新しいフィールドを追加することです。そのため、そのようなname
を持つフィールドは1つだけになり、残りはappend
と同じです。
formData.set(name, value)
,formData.set(name, blob, fileName)
.
また、for..of
ループを使用してformDataフィールドを反復処理することもできます。
let formData = new FormData();
formData.append('key1', 'value1');
formData.append('key2', 'value2');
// List key/value pairs
for(let [name, value] of formData) {
alert(`${name} = ${value}`); // key1 = value1, then key2 = value2
}
ファイル付きフォームの送信
フォームは常にContent-Type: multipart/form-data
として送信されます。このエンコーディングにより、ファイルを送信できます。そのため、<input type="file">
フィールドも通常のフォーム送信と同様に送信されます。
そのようなフォームの例を次に示します。
<form id="formElem">
<input type="text" name="firstName" value="John">
Picture: <input type="file" name="picture" accept="image/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let response = await fetch('/article/formdata/post/user-avatar', {
method: 'POST',
body: new FormData(formElem)
});
let result = await response.json();
alert(result.message);
};
</script>
Blobデータ付きフォームの送信
Fetchの章で見たように、動的に生成されたバイナリデータ(例:画像)をBlob
として送信するのは簡単です。 fetch
パラメータbody
として直接渡すことができます。
ただし、実際には、画像を個別に送信するのではなく、「名前」やその他のメタデータなどの追加フィールドとともにフォームの一部として送信すると便利な場合があります。
また、サーバーは通常、生のバイナリデータではなく、multipartエンコードされたフォームを受け入れる方が適しています。
この例では、FormData
を使用して、<canvas>
からの画像を他のいくつかのフィールドとともにフォームとして送信します。
<body style="margin:0">
<canvas id="canvasElem" width="100" height="80" style="border:1px solid"></canvas>
<input type="button" value="Submit" onclick="submit()">
<script>
canvasElem.onmousemove = function(e) {
let ctx = canvasElem.getContext('2d');
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
};
async function submit() {
let imageBlob = await new Promise(resolve => canvasElem.toBlob(resolve, 'image/png'));
let formData = new FormData();
formData.append("firstName", "John");
formData.append("image", imageBlob, "image.png");
let response = await fetch('/article/formdata/post/image-form', {
method: 'POST',
body: formData
});
let result = await response.json();
alert(result.message);
}
</script>
</body>
画像Blob
がどのように追加されるかに注目してください。
formData.append("image", imageBlob, "image.png");
これは、フォームに<input type="file" name="image">
があり、訪問者がファイルシステムからデータimageBlob
(2番目の引数)を持つ"image.png"
(3番目の引数)という名前のファイルを送信した場合と同じです。
サーバーは、通常のフォーム送信であるかのように、フォームデータとファイルを読み取ります。
まとめ
FormDataオブジェクトは、HTMLフォームをキャプチャし、fetch
または別のネットワークメソッドを使用して送信するために使用されます。
HTMLフォームからnew FormData(form)
を作成するか、フォームなしでオブジェクトを作成し、メソッドを使用してフィールドを追加できます。
formData.append(name, value)
formData.append(name, blob, fileName)
formData.set(name, value)
formData.set(name, blob, fileName)
ここで2つの特異点を挙げておきましょう。
set
メソッドは同じ名前のフィールドを削除しますが、append
は削除しません。それが唯一の違いです。- ファイルを送信するには、3つの引数を持つ構文が必要です。最後の引数はファイル名で、通常は
<input type="file">
のユーザーファイルシステムから取得されます。
他のメソッドは次のとおりです。
formData.delete(name)
formData.get(name)
formData.has(name)
以上です!
コメント
<code>
タグを使用し、複数行の場合は<pre>
タグで囲み、10行を超える場合はサンドボックス(plnkr、jsbin、codepen…)を使用してください。