Skip to content
Topic 5 of 5
Theory

Forms and Delegation

Forms

A form is a <form> with fields and a button. When the user presses the button or Enter in a field, the submit event happens, and by default the browser sends the form and reloads the page. On modern websites this is almost always cancelled and the data is handled in JavaScript:

const form = document.querySelector("#signup");

form.addEventListener("submit", (e) => {
  e.preventDefault();               // no reload
  const name = form.querySelector("#name").value.trim();
  console.log("Signing up", name);
  form.reset();                     // clear all form fields
});

Listen for submit on the form, not click on the button: this way both the button and Enter will work.

Validating fields

Before sending, the data is checked and an error is shown next to the field:

form.addEventListener("submit", (e) => {
  e.preventDefault();
  const age = Number(form.querySelector("#age").value);
  const error = form.querySelector(".error");
  if (!Number.isInteger(age) || age < 1 || age > 120) {
    error.textContent = "Age must be a whole number from 1 to 120";
    return;
  }
  error.textContent = "";
  console.log("All good");
});

trim() removes spaces at the edges — otherwise a string of only spaces would pass the "not empty" check.

Event bubbling

An event that happened on an element then bubbles up: the handlers of its parent fire, then of its parent, and so on up to document. A click on a button inside <div id="toolbar"> is also a click on #toolbar, and on body.

e.target is the deepest element where it all started, and e.currentTarget is the one whose handler is running right now.

Delegation

Instead of a handler on each of a hundred buttons, you attach one — to the common parent — and in it you check which button was clicked:

document.querySelector("#menu").addEventListener("click", (e) => {
  const btn = e.target.closest("button");
  if (!btn) return;                 // the click missed the buttons
  console.log("Action:", btn.dataset.action);
});

closest(selector) looks for the nearest matching element, starting with e.target itself and going up. This matters: if there is a <span> or an icon inside the button, e.target will be that, but closest will still find the button.

Advantages of delegation:

  • one handler instead of many;
  • elements added later (new to-dos in the list) work by themselves — their handler is already on the parent;
  • after a render() that recreates all the li, nothing needs to be subscribed again.

State + render + delegation

Almost all small interfaces in plain JavaScript are built like this:

let items = [];                  // 1. the data — the single source of truth

function render() {              // 2. the page is built only from the data
  // clear and create elements from items
}

list.addEventListener("click", (e) => {   // 3. events change the data…
  // find the element via closest, change items
  render();                               // …and redraw the page
});

Never keep something important "only in the HTML" (for example, whether a to-do is done — only in the element's class): after a redraw it will be lost. The data lives in the array, the HTML is its reflection.

Summary

  • submit + e.preventDefault() — handle a form without a reload, form.reset() — clear it.
  • Events bubble: a click on a button is also a click on all its parents.
  • Delegation: one handler on the parent + e.target.closest(...).
  • Data in variables → render() builds the page → events change the data and call render().

Login Without Reload

Easy+10 XP

Handle the submission of the #login form: the page must not reload, and #msg shows the text Welcome, followed by what was typed into the #email field (without spaces at the edges).

If the field is empty, #msg shows Enter email.

typed " ann@mail.com " → Welcome, ann@mail.com
empty                  → Enter email

Connect the connector to solve tasks

Task code runs on your own computer — faster and more reliable than in the browser. This needs the free CodeWithMe connector app. You only connect it once.

Looking for the connector on this computer…

  1. 1
    Download the connector for your system (Windows, macOS or Linux).Download the connectorOn the download page pick the file with your system in its name, e.g. windows-amd64.
  2. 2Run it and choose a folder for your solutions. It will install Python and Node.js there by itself when needed.
  3. 3
    Enter below the 6-digit code shown in the connector window (“Code for CodeWithMe”). If the browser asks about local network access — allow it.

The connector is open source (on GitHub), works only on your computer and runs code only after you enter the pairing code.