{ Introduction to Events. }

Objectives:

By the end of this chapter, you should be able to:

  • Explain what browser events are
  • Compare and contrast event capturing and bubbling
  • Describe what the event object is and name a few commonly used properties that it includes

Throughout this chapter we'll be using the following HTML as our working example. Feel free to copy and paste this text into your text editor, then open the page in Google Chrome.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <button class="first_button" onclick="firstClick()">Click me first!</button>
    <button class="second_button" >Click me second!</button>
    <button class="third_button">Click me third!</button>
</body>
</html>

What's an event?

From MDN

DOM Events are sent to notify code of interesting things that have taken place. Each event is represented by an object which is based on the Event interface, and may have additional custom fields and/or functions used to get additional information about what happened. Events can represent everything from basic user interactions to automated notifications of things happening in the rendering model.

In a nutshell, events are things we can trigger by interacting with the browser. Here are some potential events we can listen (and then execute some code) for:

  • clicking on something
  • hovering over something with the mouse
  • pressing certain keys
  • when the DOM has loaded
  • when a form is submitted

You can see a full list here.

Adding an event listener

There are three ways that we can add event listeners to our code. Given an element we want to listen to, and a function we want to execute, we can either attach the name of the function to the element in HTML, in JavaScript, or we can use the addEventListener method.

Here's some JavaScript code that highlights each one of these approaches:

// Option 1: - directly in HTML. Note that in your HTML,
// the first button makes reference to a function called firstClick
// in the onclick attribute
function firstClick(){
    alert("you clicked the first button!");
}

// Option 2 - attach the function to the element
let secondButton = document.querySelector('.second_button');
secondButton.onclick = function(){
    alert("you clicked the second button!");
}
// Option 3 - use addEventListener
let thirdButton = document.querySelector('.third_button');
thirdButton.addEventListener("click", function(){
    alert("you clicked the third button!");
});

So which one is best?

It is often best to either use the second or third option, as these are a bit more customizable, but it is good to know all of your options. In this course, we will primarily be using addEventListener.

Let's go back to our initial example, remove the onclick attribute from our first button, and add some event listeners to our buttons.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <button class="first_button">Click me first!</button>
    <button class="second_button" >Click me second!</button>
    <button class="third_button">Click me third!</button>
</body>
</html>

Just like when changing multiple elements, we need to iterate through each one - we cannot just add an event listener to an array-like object of element nodes.

let buttons = document.getElementsByTagName("button");

// this will NOT work - what kind of error do you get?
buttons.addEventListener("click", function(){
    alert("You just clicked a button");
});

// we have to add the event listener to each button
for(let i=0; i<buttons.length; i++){
    buttons[i].addEventListener("click", function(){
        alert('You just clicked on a button!');
    });
}

Removing an event listener

Sometimes we want to stop listening for events. To do that we use the removeEventListener method, but it has some quirks you should be aware of. Assuming you've still got those alert messages being triggered when you click on a button, let's take a look at the following code:

let buttons = document.getElementsByTagName("button");

// this will NOT work
buttons.removeEventListener("click", function(){
    alert("You just clicked a button");
});

// we have to remove the event listener to each button but this STILL won't work! That is because we are using an annonymous function
for(let i=0; i<buttons.length; i++){
    buttons[i].removeEventListener("click", function(){
        alert('You just clicked on a button!');
    });
}

In order to successfully remove an event listener, the callback that we pass in can't be an anonymous function. Let's clear out all the JavaScript and start from scratch. The code below should work; if you run it, event listeners will be added and then removed, so that nothing happens when you click on a button.

// In order to remove, we have to name our function before adding it instead of adding an anonymous function
function alertData(){
    alert("You just clicked a button");
}

for(let i=0; i<buttons.length; i++){
    buttons[i].addEventListener("click", alertData);
}

// since we have named our function, we know which one to remove
for(let i=0; i<buttons.length; i++){
    buttons[i].removeEventListener("click", alertData);
}

Adding an event to wait for the DOM to load

Another issue that we may face is when we have code like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script>
        let container = document.getElementById("container");
        container.innerText = "Hello World"; // This throws an error!
    </script>
</head>
<body>
    <div id="container">

    </div>
</body>
</html>

What's going on here?? Well, since our script tag is running before the DOM has loaded, it has no idea what the <div id="container"></div> is! What we can do is wait for the DOM to load before executing any JavaScript. This can be done either with the load event or the DOMContentLoaded event. You can read about the difference between them here.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script>
        document.addEventListener("DOMContentLoaded", function(){
            let container = document.getElementById("container");
            container.innerText = "Hello World"; // This works now!
        });
    </script>
</head>
<body>
    <div id="container">

    </div>
</body>
</html>

You should get in the habit of always waiting for the DOM content to load before you try to manipulate anything on the page with JavaScript.

When you're ready, move on to Events Continued

Continue

Creative Commons License