DevNotes

DevNotes

@devnotes ·

JavaScript Part 9: Clicks, typing and forms

Every click, key press and form submit fires an event, and JavaScript can listen for any of them.

Listening for a click

HTML
<button id="like">Like</button><span id="count">0</span>
JavaScript
const button = document.querySelector("#like");const count = document.querySelector("#count");let likes = 0;
button.addEventListener("click", () => {  likes++;  count.textContent = likes;});

addEventListener takes the event's name and a function. The browser holds on to the function and calls it every time the event happens. You hand the function over, and the browser decides when to run it. That's why functions as values (JavaScript Part 5) matter so much.

You'll also see onclick="..." written in HTML. It works, but it mixes your JavaScript into your HTML. Keep them apart.

The event object

The browser passes your function an object describing what happened:

JavaScript
document.addEventListener("keydown", (event) => {  console.log(event.key);  // "a", "Enter", "ArrowUp"...});

event.target is the element the event happened on. You'll use it a lot.

Reacting to typing

The input event fires on every change to a text box:

JavaScript
const bio = document.querySelector("#bio");const left = document.querySelector("#left");
bio.addEventListener("input", () => {  left.textContent = `${160 - bio.value.length} characters left`;});

bio.value is whatever is in the box right now. That's a live character counter in a few lines.

Handling a form

HTML
<form id="signup" novalidate>  <label for="email">Email</label>  <input type="email" id="email" name="email">  <button type="submit">Sign up</button>  <p id="message"></p></form>
JavaScript
const form = document.querySelector("#signup");const message = document.querySelector("#message");
form.addEventListener("submit", (event) => {  event.preventDefault();
  const email = form.elements.email.value.trim();  if (!email.includes("@")) {    message.textContent = "That email doesn't look right.";    return;  }  message.textContent = `Thanks! We'll write to ${email}.`;});

Listen for submit on the form rather than click on the button. One submit listener catches every way the form gets sent: a tap on the button, Enter in a box, or any other submit button.

event.preventDefault() stops what the browser would normally do, which for a form is sending it and reloading the page. Now your code decides what happens. Remember the reload from HTML Part 4? This is how you stop it.

form.elements.email is the input with name="email" inside the form.

novalidate on the form turns off the browser's own checks, like the email one, so your code does the checking. Without it, the browser stops a bad address before your code runs, and your message never shows.

One listener for many items

Say you have a list of 50 tasks, each with a delete button. Instead of adding 50 listeners, add one to the list and check what was clicked:

JavaScript
const tasks = document.querySelector("#tasks");
tasks.addEventListener("click", (event) => {  if (event.target.matches(".delete")) {    event.target.closest("li").remove();  }});

A click travels up from the button through every element around it, so the list hears clicks on all its buttons. closest("li") walks up from the button to the task it belongs to. This also works for tasks you add later, which separate listeners wouldn't.

Try it

Build a dark mode switch: a button that toggles a dark class on the <body>, and CSS that changes the background and text colours when body.dark is set. Then make the button's text switch between "Dark mode" and "Light mode".


Next: JavaScript Part 10: Load data with fetch

javascriptwebdevbeginners

Join WIK to like and reply to DevNotes and see more like this.