We can quickly turn a FormData
object into a plain object with Object.fromEntries()
, which was added as part of ES2019 spec1 and is available in Node since 12.x2 as well as in all modern browsers:
const f = Object.fromEntries(formData);
console.log(f);
// {
// name: "Jon Doe",
// country: "USA",
// email: "[email protected]"
// }
Web primitives are cool most of the time. For example, if you have a form like the following:
<form id="contact-form">
<input name="name" aria-label="Name" />
<select name="country" aria-label="Country">
<option value="usa" selected>USA</option>
</select>
<input name="email" type="email" aria-label="Email" />
<button type="button">Submit</button>
</form>
and want to easily get the values of form controls embedded inside it from JavaScript, you could use FormData
:
const formData = new FormData(document.getElementById("contact-form"));
console.log("Name is", formData.get("name"));
console.log("Email is", formData.get("email"))
console.log("Country is", formData.get("country"))
Note that you need to provide name
attributes to your form controls in order to query the FormData
object.
This API is pretty cool and we should be using it more instead of resorting to painfully extracting value from each and every field. But one thing that nagged me about this API is that there is no .toPlainObject()
method that gives me a POJO which is usually what most of us want.
Luckily, Object.fromEntries()
has our back. It takes an array or an iterator of tuples (an array with two elements) and returns an object with key:value
corresponding to first and second element of each tuple:
const jon = Object.fromEntries([
["name", "Jon"],
["age", 30],
["country", "USA"]
]);
console.log(jon);
// {
// name: "Jon",
// age: 30,
// country: "USA"
// }
You might be wondering: “But wait, FormData
is definitely not an array of tuples so how are we able to use it with Object.fromEntries()
?”.
Have a look at that description again:
… It takes an array or an iterator of tuples…
What the heck is an iterator? In JavaScript land, that’d be any object that implements the Symbol.iterator
interface, which is something our FormData
does. I don’t want to delve into how this works or how you can implement a custom iterator since I blabbed on long enough but you can check the linked MDN article for more details.
And there you go. FormData
implements Symbol.iterator
and by iterating it, we get each and every form control’s name
and associated value in a tuple, which is then promptly converted to an object by Object.fromEntries()
.
The iterator returned is actually the same one we get by calling formData.entries()
, a tidbit to remember.