EthicsComputerCourses
Join training +91 90532 10052

Forms & Serialization

jQuery · Lesson 19 of 36 Intermediate 6 min read Updated

Forms are where users give you data: registrations, orders, feedback, search. With JavaScript you can check the data before it is sent, send it without reloading the page, and show the result in place. jQuery made this popular with two methods that turn a whole form into data in one line: .serialize() and .serializeArray().

In this lesson you will handle the submit event correctly, serialize forms, send them with AJAX, validate them using the browser's built-in rules, and see the modern equivalents: FormData, URLSearchParams and fetch().

Handle submit, not click

Listen for the form's submit event, not the button's click. Submit also fires when someone presses Enter in a text field, and it is where the browser's validation happens. Call event.preventDefault() to stop the normal page reload, then do your own work:

JavaScript
$("#signup").on("submit", function (event) {
  event.preventDefault();
  const data = $(this).serialize();
  // ...send data with AJAX
});

// Plain JavaScript
document.querySelector("#signup").addEventListener("submit", (event) => {
  event.preventDefault();
  const data = new FormData(event.currentTarget);
});

serialize() and serializeArray()

.serialize() turns a form into a URL-encoded string, the same format a browser sends for a normal form: name=Meera%20K&city=Kochi. .serializeArray() gives an array of { name, value } objects instead.

Both include only successful controls, the same ones a real form submission would send:

  • the control must have a name attribute;
  • it must not be disabled;
  • checkboxes and radio buttons only when they are checked;
  • file inputs and the submit button are left out.

Fill in this form and submit it to compare jQuery's output with the modern API:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Serializing a form</title>
  <style>
    form { display: grid; gap: 0.5rem; max-inline-size: 26rem; }
    pre { background: #f3f5f7; padding: 0.5rem; white-space: pre-wrap; word-break: break-all; }
  </style>
</head>
<body>
  <form id="admission">
    <label>Name <input name="name" value="Meera Krishnan" required></label>
    <label>City
      <select name="city">
        <option>Jaipur</option>
        <option selected>Kochi</option>
        <option>Pune</option>
      </select>
    </label>
    <fieldset>
      <legend>Subjects</legend>
      <label><input type="checkbox" name="subjects" value="Maths" checked> Maths</label>
      <label><input type="checkbox" name="subjects" value="Biology"> Biology</label>
      <label><input type="checkbox" name="subjects" value="Computer Science" checked> Computer Science</label>
    </fieldset>
    <label>Admission number (filled by office) <input name="admNo" value="A-1042" disabled></label>
    <button>Submit</button>
  </form>
  <h4>jQuery .serialize()</h4>
  <pre id="s1"></pre>
  <h4>jQuery .serializeArray()</h4>
  <pre id="s2"></pre>
  <h4>Plain: URLSearchParams(FormData) and getAll()</h4>
  <pre id="s3"></pre>

  <script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
  <script>
    $("#admission").on("submit", function (event) {
      event.preventDefault();

      $("#s1").text($(this).serialize());
      $("#s2").text(JSON.stringify($(this).serializeArray()));

      const formData = new FormData(this);
      $("#s3").text(
        new URLSearchParams(formData).toString() + "\n" +
        "subjects: " + JSON.stringify(formData.getAll("subjects"))
      );
    });
  </script>
</body>
</html>

The disabled admission number and the unticked subject are missing in every version. Spaces appear as %20 in jQuery's string and + in URLSearchParams; servers read both the same way.

Turning form data into an object

Neither serialize method gives you a simple object. Use the array, or FormData with Object.fromEntries(). Watch out for fields that can have several values, like the subjects checkboxes:

JavaScript
// jQuery
const obj = {};
$.each($("#admission").serializeArray(), function (i, field) {
  if (field.name in obj) obj[field.name] = [].concat(obj[field.name], field.value);
  else obj[field.name] = field.value;
});

// Plain JavaScript
const formData = new FormData(document.querySelector("#admission"));
const data = Object.fromEntries(formData);      // keeps only the LAST value of "subjects"
data.subjects = formData.getAll("subjects");    // so read multi-value fields with getAll()

The reverse of .serialize() is $.param(object), which builds a query string from an object. By default it adds [] to array names (subjects%5B%5D=Maths), the format PHP expects; pass true as the second argument for the plain subjects=Maths&subjects=CS style.

Sending a form with AJAX

$.post() with .serialize() sends exactly what a normal form submit would, so the server code does not need to change. The modern version passes the form data to fetch():

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AJAX form</title>
</head>
<body>
  <form id="feedback" action="https://jsonplaceholder.typicode.com/posts" method="post">
    <label>Your name <input name="name" value="Farhan" required></label><br>
    <label>Rating
      <select name="rating"><option>5</option><option>4</option><option>3</option></select>
    </label><br>
    <label>Comment <input name="comment" value="Clean classrooms in the Lucknow centre"></label><br>
    <button name="via" value="jquery">Send with jQuery</button>
    <button name="via" value="fetch">Send with fetch</button>
  </form>
  <p id="result"></p>

  <script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
  <script>
    $("#feedback").on("submit", async function (event) {
      event.preventDefault();
      const form = this;
      const via = event.originalEvent.submitter.value;   // which button was pressed
      $(form).find("button").prop("disabled", true);
      $("#result").text("Sending...");

      try {
        let saved;
        if (via === "jquery") {
          saved = await $.post(form.action, $(form).serialize());
        } else {
          const response = await fetch(form.action, { method: "POST", body: new URLSearchParams(new FormData(form)) });
          if (!response.ok) throw new Error("HTTP " + response.status);
          saved = await response.json();
        }
        $("#result").text("Saved by " + via + " as #" + saved.id + ": " + saved.name + " gave " + saved.rating + " stars");
      } catch (error) {
        $("#result").text("Could not send feedback.");
      } finally {
        $(form).find("button").prop("disabled", false);
      }
    });
  </script>
</body>
</html>

event.submitter (reached through originalEvent in jQuery) tells you which submit button was used. Reading form.action keeps the URL in the HTML, so the form still has a sensible target if JavaScript fails to load.

Validating with the browser's rules

Before writing validation code, use HTML attributes: required, type="email", minlength, min, max and pattern. The browser checks them on submit and shows messages in the user's language. JavaScript can ask for the result:

JavaScript
const form = document.querySelector("#signup");
form.checkValidity();     // true or false, no messages shown
form.reportValidity();    // true or false, and shows the browser's messages

const phone = form.elements.phone;
phone.setCustomValidity(/^[6-9]\d{9}$/.test(phone.value) ? "" : "Enter a 10-digit Indian mobile number");

setCustomValidity("") marks the field valid again; any other text marks it invalid with that message. In jQuery code you will often see the jQuery Validation plugin doing this job; covered in Using & Writing Plugins.

Common mistakes

  • Listening to the button's click instead of the form's submit. Pressing Enter skips your code and the page reloads.
  • Forgetting the name attribute. Fields without a name are left out of .serialize() and FormData.
  • Expecting disabled fields to be sent. Use readonly for values the user must not edit but the server needs.
  • Using Object.fromEntries(formData) with multi-value fields. Only the last value survives; use getAll().
  • Trusting client-side checks. Anyone can bypass JavaScript. The server must validate again.

Key points

  • Handle the form's submit event and call event.preventDefault().
  • .serialize() gives a URL-encoded string and .serializeArray() an array of { name, value }; only named, enabled, checked controls are included.
  • Modern code uses new FormData(form), new URLSearchParams(formData) and formData.getAll().
  • Send with $.post(form.action, $(form).serialize()) or fetch(form.action, { method: "POST", body: ... }).
  • Validate with HTML attributes, checkValidity(), reportValidity() and setCustomValidity(), and always validate on the server too.

Exercise

Build a "Book a cricket net" form with name (required), phone (pattern for a 10-digit number starting 6 to 9), date and a "with coach" checkbox. On submit, prevent the reload, and if this.checkValidity() is false call this.reportValidity() and stop. Otherwise show the .serialize() string in a paragraph and the number of fields sent (from .serializeArray().length).

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Net booking</title>
</head>
<body>
  <form id="booking" novalidate>
    <label>Name <input name="name" required></label><br>
    <label>Phone <input name="phone" pattern="[6-9][0-9]{9}" required></label><br>
    <label>Date <input name="date" type="date" required></label><br>
    <label><input type="checkbox" name="coach" value="yes"> With coach</label><br>
    <button>Book</button>
  </form>
  <p id="out"></p>
  <script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
  <script>
    $("#booking").on("submit", function (event) {
      event.preventDefault();
      if (!this.checkValidity()) {
        this.reportValidity();
        return;
      }
      const fields = $(this).serializeArray();
      $("#out").text($(this).serialize() + " (" + fields.length + " fields)");
    });
  </script>
</body>
</html>

novalidate stops the browser from blocking the submit by itself, so your handler decides when to show the messages with reportValidity(); the unticked coach box is not sent, so the count is 3 or 4.

Quick Quiz

1. Which fields does .serialize() include?

2. What is the modern equivalent of $(form).serialize()?

3. Why handle the form's submit event rather than the button's click?

4. Object.fromEntries(new FormData(form)) is used on a form with two ticked "subjects" checkboxes. What happens?

Learn jQuery with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call