Submission formats

The FormData object

Read a form into JavaScript, inspect its entries, preserve repeated values, and append or replace fields before submission.

FormData is the JavaScript version of what the browser builds when it submits a form. Same name-value pairs, same rules about which controls count. You get to look at them and change them before anything is sent.

Create it from a form

Inside a submit handler, pass the form to the constructor. If a button started the submission, pass it too:

const data = event.submitter
  ? new FormData(form, event.submitter)
  : new FormData(form)

for (const [name, value] of data) {
  console.log(name, value)
}

The loop prints one line per entry. For a form with a name field, two checked topics, and a file, you’d see:

displayName Ada
topic html
topic css
screenshot File {name: 'login.png', …}

The entries follow the successful-control rules from earlier in the course. Unnamed and disabled fields are missing. Unchecked checkboxes are missing. File inputs give you File objects, not strings.

The second argument matters when a form has several submit buttons. It adds the clicked button’s name and value, so action=publish ends up in the data just like it would with a native submission. event.submitter is null when nothing triggered it through a button, for example when you call form.requestSubmit() from code. That’s why the fallback uses the one-argument form.

Read values

Use get() for a field that has one value. Use getAll() when several controls share a name:

data.get('displayName') //'Ada'
data.getAll('topic') //['html', 'css']

get('topic') would return only 'html'. That’s the trap with checkboxes and multiple selects.

Change values

append() adds another entry under a name. set() replaces every entry under that name:

data.append('topic', 'javascript') //now three topics
data.set('topic', 'css') //now only css

I use append() when I’m adding something the form didn’t have, like a token from JavaScript. I use set() when I want to be sure a name has exactly one value.

Be careful with Object.fromEntries

It’s tempting to turn the data into a plain object:

const values = Object.fromEntries(data)

An object holds one property per key. With two topic entries, values.topic is 'css' and 'html' is gone. Only do this when repeated names are impossible in that form.

Send it

You can pass the object straight to fetch() as the body. The browser encodes it as multipart and writes the header with the boundary for you. If your endpoint wants JSON instead, build the JSON yourself from the entries, and remember that a File can’t go into JSON.stringify(). Files need multipart or a separate upload.

Try this: put a disabled input, an unchecked checkbox, two checked topics and a file input in a form, then print the entries. Compare the output with what you see on screen. The gap between the two is what this lesson is about.

Lesson completed