FormData, the new formdata event, and HTML forms

Have you heard about the new formdata event?

It’s just a new DOM event, but every new addition to the web platform makes me always excited.

What is FormData?

Let’s clarify what is FormData before getting into more details. For those new to web development, HTML forms are able to emit events. This is a feature of almost any HTML element.

Consider the following form:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>HTML forms and JavaScript</title>
</head>
<body>
<form>
    <label for="name">Name</label>
    <input type="text" id="name" name="name" required>

    <label for="description">Short description</label>
    <input type="text" id="description" name="description" required>

    <label for="task">Task</label>
    <textarea id="task" name="task" required></textarea>

    <button type="submit">Submit</button>
</form>
</body>
<script src="form.js"></script>
</html>

To follow along you can create an HTML file, copy over my example. When the form is submitted, that is, when the user fills the fields and clicks the “Submit” button, an event named submit is dispatched.

That means we can listen to the submit event with an event listener:

// form.js
const form = document.forms[0];

form.addEventListener("submit", function(event) {
  event.preventDefault();
});

Calling preventDefault() prevents a page refresh, convenient when you don’t want to send the form fields on the backend.

Now, there are a couple ways to get the actual data from the form. You could inspect event.target.elements which in this case yields all the form elements.

Or even better you can use FormData, a DOM interface, as a constructor. It needs the form as an argument:

const form = document.forms[0];

form.addEventListener("submit", function(event) {
  event.preventDefault();
  const data = new FormData(form);
});

From now on you can do all sort of things on the FormData object. More on this later. Now let’s explore the formdata event.

Getting to know the formdata event

The formdata event is a newer, nice addition to the web platform. As a boost to FormData the event is fired any time you call new FormData(). Now consider the following example:

const form = document.forms[0];

form.addEventListener("submit", function(event) {
  event.preventDefault();
  new FormData(form);
});

form.addEventListener("formdata", event => {
  // event.formData grabs the object
  console.log(event.formData);
});

In the first event listener we build a new FormData from the form. This time there’s no need to save the result in a variable.

In response to this call the new object fires up the formdata event, on which we register another listener.

In this second listener we can grab the actual data from event.formData.

This pattern helps decoupling the first event listeners from any other callback that was supposed to handle the actual form data (making API calls and stuff).

In the next section we’ll see how to get data from a FormData object.

Grabbing data from a FormData object

If you want to snitch into a FormData object visit the example HTML form in a browser and place a breakpoint on console.log(event.formData).

Fill and submit the form with the browser’s console opened and save the object as a global variable:

Grabbing data from a FormData object (the formdata event)

You should be able to access the object (temp1) in Chrome. As you’ll see it has a bunch of methods. To extract an array of values run:

const values = [...temp1.values()]
// sample output
// ["Liz", "Trip to London", "Trip to London"]

To extract an array of entries run:

const entries = [...temp1.entries()]

In our example we can get all the data in various shapes from the FormData object:

const form = document.forms[0];

form.addEventListener("submit", function(event) {
  event.preventDefault();
  new FormData(form);
});

form.addEventListener("formdata", event => {
  const data = event.formData;

  // get the data
  const entries = [...data.entries()];
  console.log(entries);

  const values = [...data.values()];
  console.log(values);
});

A word of warning: FormData relies on form fields name attributes to build the mapping between fields and values. That means the following elements won’t yield anything:

<!-- bad -->
<input type="text" id="name" required>
<input type="text" id="description" required>

Always provide a name for your fields:

<!-- good -->
<input type="text" id="name" name="name" required>
<input type="text" id="description" name="description" required>

Adding data to a FormData object

It’s common practice to have hidden inputs in HTML forms for saving additional data in the submission phase:

<!-- no more hidden fields -->
<input type="hidden" id="someInfo" name="someSecretInfo" value="someSecreteInfo">

Hidden inputs don’t show up in the rendered HTML (but are still accessible from the developer console).

In addition to reading form fields from a FormData object, it’s also possible to add new key/value pair with append:

// omitted for brevity

form.addEventListener("formdata", event => {
  const data = event.formData;

  // append more fields
  data.append("anHiddenKeyA", "anHiddenValueA");
  data.append("anHiddenKeyB", "anHiddenValueB");

  // get the data
  const entries = [...data.entries()];
  console.log(entries);

  const values = [...data.values()];
  console.log(values);
});

This is convenient for avoiding hidden input fields in HTML forms.

Being a newer addition to the platform formdata event is not available in older browsers, use it with caution.

Thanks for reading and stay tuned for more!

Resources

FormData objects on MDN

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.