JavaScriptを学習中です。日報を送信するフォームを作っていて、入力欄が増えるほど値を1個ずつ取り出すのが面倒だと感じました。調べたら FormData を使うとまとめて取れたので、整理しておきます。
作ったフォーム(HTML)
名前・作業内容・コメントの3項目です。ポイントは、各入力欄に name 属性を付けているところ(あとで効いてきます)。
<form class="form" id="js-form">
<label for="name">Name:</label>
<input type="text" id="name" name="name">
<label for="work">Work:</label>
<input type="text" id="work" name="work">
<label for="comment">Comment:</label>
<textarea id="comment" name="comment" rows="4" cols="50"></textarea>
<button type="submit">Submit</button>
</form>
面倒なやり方:1個ずつ .value で取る
最初はこう書いていました。入力欄の数だけ querySelector(...).value が並びます。
const name = document.querySelector("#name").value;
const work = document.querySelector("#work").value;
const comment = document.querySelector("#comment").value;
3つならまだしも、項目が増えるほど行が増えて面倒です。
FormData でまとめて取る
フォーム要素を FormData に渡すと、入力値をまとめて持ってくれます。個別の値は .get("name属性の名前") で取り出します。
const form = document.querySelector("#js-form");
form.addEventListener("submit", (event) => {
event.preventDefault(); // 送信によるページ再読み込みを止める
const formData = new FormData(event.target);
console.log(formData.get("name")); // Nameの入力値
console.log(formData.get("work")); // Workの入力値
console.log(formData.get("comment")); // Commentの入力値
});
event.target は送信されたフォームそのもの。それを new FormData(...) に渡すだけです。
つまずき①:取り出すキーは id ではなく name
ここが一番ハマりました。FormData が値を管理するキーは、id ではなく name 属性です。
<input type="text" id="name" name="user-name">
このときの値は formData.get("user-name") で取ります(id の "name" ではありません)。name 属性を付け忘れると、その入力欄は FormData に入ってこない、というのも落とし穴です。
つまずき②:preventDefault() を忘れるとリロードされる
type="submit" のボタンを押すと、フォームはデフォルトでページを再読み込みします。event.preventDefault() を書かないと、console.log した瞬間にページが更新されて「値が取れてない?」と勘違いしがちです。
まとめてオブジェクトにする
全部まとめて1つのオブジェクトにしたいときは、Object.fromEntries が便利です。
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
console.log(data); // { name: "...", work: "...", comment: "..." }
このオブジェクトは、そのままサーバーに送るデータとしても使いやすいです。
まとめ
- フォームの値は
new FormData(フォーム要素)でまとめて取れる - 個別の値は
.get("name属性")で取り出す(キーはidではなくname) -
type="submit"のときはevent.preventDefault()を忘れずに - 全部まとめたいときは
Object.fromEntries(formData)でオブジェクトにできる
ちなみにコメント欄は <textarea> を使っていますが、これも name 属性さえ付けておけば FormData でまとめて取れます。
まだ学習中の身なので、誤りや、もっと良い書き方があればコメントで教えていただけると嬉しいです。最後まで読んでいただきありがとうございました。