DOM events and callbacks

The DOM in a web page generates a multitude of events (e.g. click, keydown, load, etc.) for web apps to respond to. The developer can write JavaScript functions (i.e. “callbacks”) and attach them to DOM events such that the callback runs every time that event fires.

Simple Event Callback

Here’s a simple example:

  1. Create a button somewhere on your page with id of btn1. Make sure it is a standalone button, and not a part of a form.
  2. Add the following JavaScript code to the page. It must run after the button is loaded into the page.
const btn1 = document.getElementById("btn1"); // there must be a button on the page with this id
let counter = 0; // a counter to count clicks
btn1.addEventListener("click", function(event) { // the callback gets the DOM `event` as parameter
  const target = event.target; // the DOM element that is the "target" of the event (button that was clicked)
  counter++; // increment the counter
  const message = `You clicked ${target.id} ${counter} time${counter>1 ? 's' : ''}`;
  target.innerText = message; // update DOM
});
  1. Test it. It should work.
  2. Now wrap the button in a form tag, like this:
<form>
  <button id="btn1">Click Me!</button>
</form>
  1. Test it again. This time you should see something strange. The button text does change for a brief moment, but then goes back to the original (“Click Me!”) soon after.
  2. The reason is that since this button is a part of a form, right after executing your callback, it performs the button’s default action, which is to submit the form. And since the form is getting submitted, the whole page refreshes.
  3. To fix this, call event.preventDefault() on the event before returning.
btn1.addEventListener("click", function(event) {
  event.preventDefault(); // don't perform the default action of this event
  // ... code to respond to the event ...
});

Form Submit Example

In modern JavaScript apps, it is very common to convert a traditional form from submitting normally (and refreshing the whole page) to intercepting the submission, performing client-side validations, and then sending form inputs to server using AJAX and handling the response, all without refreshing the page.

<!-- input -->
<form id="test-form">
  <input name="firstName" type="text" placeholder="First Name" required>
  <input name="lastName" type="text" placeholder="Last Name" required>
  <input name="dob" type="date" placeholder="Date of Birth">
  <select name="employment" required>
    <option value="">Employment Status</option>
    <option>Salaried</option>
    <option>Self-Employed</option>
    <option>Retired</option>
    <option>Unemployed</option>
  </select>
  <div>
    <button>Submit</button>
    <button type="reset">Reset</button>
  </div>
</form>

<!-- output -->
<fieldset>
  <legend>Submissions</legend>
  <ol id="submission-list">
    <!-- submissions will appear here -->
  </ol>
</fieldset>
const submissions = document.getElementById("submission-list");
document.getElementById("test-form").addEventListener("submit", function(e) {
  e.preventDefault(); // prevent submission (default action)
  const form = e.target;
  const formData = new FormData(form);
  const data = Object.fromEntries(formData.entries());
  // client-side validation
  if(data.firstName.length < 3 || data.lastName.length < 3) {
    alert("First Name and Last Name must be at least 3 characters long");
    return; // Validation failed. Abort.
  }
  const li = document.createElement("LI");
  li.innerText = JSON.stringify(data);
  submissions.append(li);
});

Note that:

  • We are attaching to the submit event of the form and not click event of the button.
  • We call preventDefault to prevent the full page refresh.
  • We construct a FormData object, which extracts all the input values from the form.
  • We perform client-side validation on the submitted data, and abort if validation fails.

References:
  1. MDN: DOM events
  2. MDN: FormData API