FormData is a useful interface for collecting data from a form. But it can be tricky to convert to JSON.
The FormData
interface is a super convenient way to collect data from a <form>
element. This makes the process of submitting form requests asynchronously a total walk in the park.
Most of the time.
It works really great out of the box if you're able to send your request using the multipart/form-data
encoding type. But what often happens is the service that is receiving that data isn't setup to work with that encoding. That's because it's not as easy to work with. It's often a cleaner approach to be able to accept JSON on the server side and use that to (do whatever) with the form data.
Let's say we have a super simple form, with one field to collect a name:
<form onsubmit="submitForm(event)">
<label>Name</label>
<br />
<input type="text" name="name" required />
<br /><br />
<input type="submit" value="Submit" />
</form>
Don't actually use onsubmit
to call a global function in production. Here are a couple alternate patterns worth considering.
We could then submit the data through some JavaScript function:
function submitForm(event) {
// Prevent the form from submitting.
event.preventDefault();
// Set url for submission and collect data.
const url = "https://example.com/...";
const formData = new FormData(event.target);
// Submit the data.
const request = new XMLHttpRequest();
request.open("POST", url);
request.send(formData);
}
That works great if your server (or serverless function) can process the data directly.
Now here's the weird thing. If you inspect formData
from the function above, it looks like there's nothing there.
Let's adjust our function:
function submitForm(event) {
// Prevent the form from submitting.
event.preventDefault();
// Set url for submission and collect data.
const url = "https://example.com/...";
const formData = new FormData(event.target);
// Log the data.
console.log(formData);
}
This will result in a log to the console like this:
FormData {}
Coooool. That's not helpful.
Instead, we actually have to iterate over the field individually and build an object manually.
function submitForm(event) {
// Prevent the form from submitting.
event.preventDefault();
// Set url for submission and collect data.
const url = "https://example.com/...";
const formData = new FormData(event.target);
// Build the data object.
const data = {};
formData.forEach((value, key) => (data[key] = value));
// Log the data.
console.log(data);
}
Now fill in the field with something like "My Name" and submit the form. You'll see the object logged to the console:
{
name: "My Name";
}
That will solve for many cases, but not all. This StackOverflow answer offers a solution for handling multi-select lists. Check out the demo.
References: