In this article, we’ll take a look at events in JavaScript.

What are events in JavaScript Image by codingexercises

Events are things that are constantly happening in our browser, including, but not limited to:

  • A user clicking on an element
  • A mouse hovering over a button
  • A form being submitted
  • A web page loads

There are many, many other events: browser window being resized, all the mouse movements on a page, user scrolling down the page, user pressing the keys…

With JavaScript, you have an easy way to get notified when an event happens. This is called listening for events.

You can also do something when an event happens. This is known as handling events.

Using JavaScript, we can run functions when an event happens. This is done with the help of event handlers.

To listen for an event, we use the addEventListener method.

How do we handle an event? Where do we specify the event handler?

An event handler is placed as the second argument when we call the addEventListener method. The first argument is the event that we are listening for.

Great, now we have all the necessary ingredients to capture an event, and run an event handler on it!

Here is our snippet’s code:

document.body.addEventListener('click', function() { alert('Click!') });

Run the above code inside the console, then click on the page’s body. For any click anywhere in the body element, you’ll get back an alert.

What happened here?

  1. We added an event listener on the document’s body element
  2. We specified that the event we are listening for is the click event
  3. We specified the event handler, in the form of an anonymous function. The event handler was just a simple alert().

How might we improve this simple event handler, and make it more reusable?

We could make our code more modular by putting our anonymous function in a variable, like this:

var eventHandler = function() { alert('Click!') };
document.body.addEventListener('click', eventHandler);

This is useful, because if we wanted to update our event handler, we could do it easier than in the first example.

Let’s look at a more fun example to see this in practice.

let chosenColor = prompt('Type one of these colors: "orange", "yellow", "tomato" ');

console.warn(`
    You picked "${chosenColor}".
    Now click on the web page to color it in your chosen color!
`);

var eventHandler = function() { document.body.style = `background: ${chosenColor}` }

document.body.addEventListener('click', eventHandler);

Congratulations! You’ve just listened for an event, and handled it when it occured. You now know how to program events in JavaScript!

Inline Event Handlers

The earliest way to deal with JavaScript events was using the onclick HTML attribute.

This is not the suggested best practice*, but it’s good to know it’s there.

Asterisk: Actually, it’s a bit more complicated than that. There was a time when this was a good practice, then it wasn’t, and now it’s again used extensively. For example, in Angular we can have this code: <p (click)="someFunction()">. While obviously, Angular is a TypeScript framework, a lot of the stuff there is basically JavaScript. So inline click events are, I guess, accepted.

Here’s a quick example of an inline click event:

<div onclick="alert('You clicked this div!')">
    Just a simple div
</div>

Let’s add a snipept which will dynamically add this onclick HTML attribute to any web page, so that we can quickly see it in practice, without too much setup.

function addInlineEventHandler() {
    let a = document.body;
    a.setAttribute("onclick", "alert('You clicked the body')");
}

addInlineEventHandler();

Let’s now look at how JavaScript deals with events.

How JavaScript Deals with Events

JavaScript is always on the lookout for events occuring on any element in the document.

When an event indeed happens, JavaScript will handle that event if we told it to do so - i.e if we attached an event handler to the element in question.

We might say that JavaScript is checking if there are event handlers on any of the elements on the page, and it performs these checks all the time.

Event Propagation

Let’s say we add the following (simplified) structure to our web page:

document.body.innerHTML = `
    <div id="one" onclick="alert('Click one')">
        <div id="two" onclick="alert('Click two')">
            <ul id="three" onclick="alert('Click three')">
                <li onclick="alert('Click four')"
                    id="four"
                    style="height:100px;
                    width:100px;
                    background:aliceblue">
                        four
                </li>
                <li onclick="alert('Click five')"
                    id="five"
                    style="height:100px;
                    width:100px;
                    background:yellowgreen">
                        five
                </li>
            </ul>
        </div>
    </div>
`;

What does the above code do?

It dynamically overrides the contents of the body element, and adds the HTML structure that consists of several levels of tags.

There are two li tags wrapped up by a ul tag, which, in turn, is wrapped up with two div tags.

We also have inline event handlers in the form of onclick attributes on each of these dynamically added elements.

What will happen when we click on the li with the id=”four”?

Interestingly, we will get the following alerts:

  • Click four
  • Click three
  • Click two
  • Click one

What is the conclusion?

A click event on a child element will be registered on all the parent elements of that child element.

What we saw above is an example of event bubbling. Event bubbling is simply the way the browser orders events on the document.

Thus, we can conclude that event bubbling is browser behavior in which events are ordered with the inside-out approach.

The event that happened on the innermost tag is dealt with first, then the event that happened on the tag that wraps the innermost tag gets handled, and so on, all the way up to the html tag, which wraps all the other tags.

There are actually two ways to order events in JavaScript. We’ve seen the first one, called event bubbling.

There’s another one, called event capturing.

Event capturing starts with the html element, and then goes into the nested children elements. It digs down into the nested structure until it reaches the most deeply-nested element on which an event occured. Then it goes back the same way it came.

Event bubbling first checks the deeply-nested element, and then bubbles up the document all the way to the html element.

Let’s rewrite the previous code example using the addEventListener method. This time, we’ll create a whole new HTML file, with a script tag right above the closing body tag. This script tag will hold our addEventListener methods.

We’ll start with the DOCTYPE, html, and head tags:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        /* to be added */
    </style>
</head>

Inside the style tags, we’ll add the styles to color each nested element on the page differently:

<style>
        #one {
            background-color: #dedede;
            padding: 20px;
            border: 1px solid #abcabc
        }

        #two {
            background-color: #cecece;
            padding: 30px;
            border: 1px solid #789789
        }

        #three {
            background-color: #ababab;
            padding: 10px;
            border: 1px solid #456456
        }

        #four {
            height: 100px;
            width: 100px;
            background: aliceblue;
            border: 2px solid blue
        }

        #five {
            height: 100px;
            width: 100px;
            background: yellowgreen;
            border: 2px solid green
        }
</style>

Now we can add the body element:

<body>
    <div id="one">one
        <div id="two">two
            <ul id="three">three
                <li id="four" style="height:100px;
                    width:100px;
                    background:aliceblue">
                    four
                </li>
                <li id="five" style="height:100px;
                    width:100px;
                    background:yellowgreen">
                    five
                </li>
            </ul>
        </div>
    </div>

    <script>
        document.getElementById('one').addEventListener('click', function () {
            alert('Clicked on one');
        });

        document.getElementById('two').addEventListener('click', function () {
            alert('Clicked on two');
        });

        document.getElementById('three').addEventListener('click', function () {
            alert('Clicked on three');
        });

        document.getElementById('four').addEventListener('click', function () {
            alert('Clicked on four');
        });

        document.getElementById('five').addEventListener('click', function () {
            alert('Clicked on five');
        });
    </script>
</body>
</html>

Like any other time, we could improve on our code. But this is not the time to refactor.

Instead, I want to show you how to use the third argument that the addEventListener method can expect.

That argument can either be set to true or false.

If it is set to true, we instruct the browser to order events using event capturing - i.e to order the events from the outermost to the innermost tag.

Alternatively, if it is set to false, we instruct the browser to order events from the innermost to the outermost tag.

Thus, let’s update our code with true set on all addEventListener methods. The updated script tag will now look as follows:

<script>
    document.getElementById('one').addEventListener('click', function () {
        alert('Clicked on one');
    }, true);

    document.getElementById('two').addEventListener('click', function () {
        alert('Clicked on two');
    }, true);
    document.getElementById('three').addEventListener('click', function () {
        alert('Clicked on three');
    }, true);
    document.getElementById('four').addEventListener('click', function () {
        alert('Clicked on four');
    }, true);
    document.getElementById('five').addEventListener('click', function () {
        alert('Clicked on five');
    }, true);
</script>

If we ran the above code now, event propagation will be flipped. Here are the alerts, as they will appear, based on the third argument in the addEventListened method set to true:

  • Clicked on one
  • Clicked on two
  • Clicked on three
  • Clicked on four (or “Clicked on five”)

However, if you look at the code above, there is a lot of repetition! How can we fix that?

Stopping Event Propagation

Rather than having to add five event listeners on all the different places in the document, it would be much better to have one single place where we’ll capture the event.

We can achieve that by stopping event propagation, with the help of the stopPropagation method.

So, let’s update our previous code by adding the stopPropagation method on the li with id="five".

We will also turn on the event bubbling order of events; in other words, we’ll revert to the default behavior.

The only changes to the previous code will again be made inside the script tags, as follows:

<script>
    document.getElementById('one').addEventListener('click', function () {
        alert('Clicked on one');
    }, false);

    document.getElementById('two').addEventListener('click', function () {
        alert('Clicked on two');
    }, false);
    document.getElementById('three').addEventListener('click', function () {
        alert('Clicked on three');
    }, false);
    document.getElementById('four').addEventListener('click', function () {
        alert('Clicked on four');
    }, false);
    document.getElementById('five').addEventListener('click', function (event) {
        alert('Clicked on five');
        event.stopPropagation();
    }, false);
</script>

Test your code by running it in a webpage with the updated file name: addEventListeners-stopPropagation.html.

Now click on the li with id="four". This is the order of alerts:

  • Clicked on four
  • Clicked on three
  • Clicked on two
  • Clicked on one

Next, click on the green li tag. This time, the only thing that was alerted is:

  • Clicked on five

In our event handler for the li with id="five", we called the stopPropagation method on the event object that we passed into the event handler function. Indeed, stop propagating it did - the event never bubbled up to the outermost element, like it did when we clicked on the li with id="four".

What is this event object that we just used? We haven’t seen it before. We’ll discuss it soon, but before we do, to avoid information overload and make sure not to jump any staircase, let’s write a few more event handlers first.

We’ll begin by adding an event handler to our page dynamically. The event handler we’ll code is going to add a div whenever we click on the body tag of our web page.

Add an Event Handler to our Page Dynamically

Similar to the approach we used in the previous chapter, and in order to practice what we’ve learned, let’s create a new snippet, and call it “Dynamic Onclick Event Handler”.

This is the code to add to our new code snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function addDivElement() {
    var div = document.createElement('div');
    div.innerHTML = `
        <div class="dynamic" style="width:100px;height:100px;background:#dedede">
        I was triggered by a click event!
        <br>
        That click event happened on the body element!
        </div>
        `;

    document.body.appendChild(div);

}

var body = document.getElementsByTagName('body');

for (i = 0; i < body.length; i++) {
    body[i].addEventListener("click", addDivElement);
}

Looking at the code above, it should be easy understanding lines 1-14, based on what we’ve learned so far.

However, there are still a couple of staircases we’re missing in order to get to the level at which we can comforably understand the code above. So let’s pick it apart.

The code on line 15 runs the getElementsByTagName method on the document object. When you run this methdo and pass it any element, what you get back is an HTML Collection. For now, it’s enought to know that an HTML Collection is an array-like data structure in JavaScript. It is basically list a list of variables grouped together under a common label. In our case, that common label is body, and each individual memeber of this HTML collection can be accessed by using the following syntax:

  • to get the first member, we run body[0]
  • to get the second member, we run body[1]
  • to get the third member, we run body[2]

A quick little exercise to understand this concept better:

  1. Go to a popular website such as yahoo.com.
  2. Open the browser console. It is likely there will be some junk in the console, so let’s run a built-in browser function to clear the console. The function we need to run is: clear().
  3. Next, type the following code:
var divs = document.getElementsByTagName('div');
divs[0];
divs[1];
divs[2];
divs[3];

When you run the above code, the console will return something similar to the following:

<div id="UH">...</div>

Of course, the id attribute of each of the divs will be slightly different.

Are you wondering how many div elements are there on the page?

I’m glad you asked, because finding the answer to this question is as easy as running a piece of code multiple times.

In JavaScript (and many other computer languages), running a piece of code many times is referred to as looping.

There are many ways to loop over a block of code - i.e run a block of code multiple times. One of those ways is the for loop.

Running a Block of Code Multiple Times with a For Loop

Still on the Yahoo homepage, clear the console again by running clear().

Next, run the following for loop to see how many divs are there on the page:

var divs = document.getElementsByTagName('div');

for (i=0; i< divs.length; i=i+1) {
    console.log(i)
}

Yay, you’ve just written your first for loop! Press the ENTER key to see it count all the divs. When I did it on Yahoo homepage, I got back 376. Pretty large number alright! Then again, Yahoo is a large website with a large homepage.

Ok, so, before we get back to understanding our event handler code, let’s build the for loop staircase.

Since our for loop is there to loop over a block of code X amount of times, we are basically setting up the counter that will keep track of how many times the code has been run.

The for loop can have three distinct pieces of code, separated by semi-colons. The first piece of code is the counter’s initial value. That’s the i=0 part.

The next important piece of code is the exit condition. Our exit condition in the above for loop is i<divs.length. The length attribute on our HTML collection counts the number of members this collection has. It is starting from 1. Contrary to that, the actual HTML collections (and arrays too!) get counted from zero. This allows us to have this nice piece of code that says: keep on looping the code for as long as the value of i is less than the number of members in the divs HTML collection. When the value of i is the exact same number as the number of divs in the HTML collection, that means that the exit condition has already been satisfied.

The third important piece of code is the variable update, that is, it answers the question of “What do we do with a variable once a single loop has been completed?”. The answer in our example is this: “Once a loop has been completed, increase the value of i by one, and assign that value to i. In other words, we are telling JavaScript to increase i by 1 on each loop.

Once we have these 3 pieces of information, we simply add our block of code:

{
    console.log(i);
}

What the above block of code does is, it just logs out the current value of i on each loop.

Since I ended up with the number 376 as the last number logged out to the console, I can safely say that my for loop looped over the above block of code for precisely 376 times.

And it did that really, really fast, much faster than I was able to follow it.

Wow, this was a pretty long explanation!

Luckily, this explanation has de-mystified the code of our event handler. Let’s look at it again. This time, it should be a lot easier to understand:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function addDivElement() {
    var div = document.createElement('div');
    div.innerHTML = `
        <div class="dynamic" style="width:100px;height:100px;background:#dedede">
        I was triggered by a click event!
        <br>
        That click event happened on the body element!
        </div>
        `;

    document.body.appendChild(div);

}

var body = document.getElementsByTagName('body');

for (i = 0; i < body.length; i++) {
    body[i].addEventListener("click", addDivElement);
}

On line 1, we define a new function, called addDivElement.

On line 2, we create a div, and we bind this place in memory with a label called ‘div’.

On line 3, we set the innerHTML value on our div object to the code on lines 4, 5, and 6.

On line 7, we close the template literal with a closing backtick and a semi-colon.

On line 9, we append our new div as a child of the body element.

On line 13, we run the getElementsByTagName method on our document object, and we pass it body as its argument. JavaScript stores the result of me running this method in memory, and I assign that result - an HTML collection - to the variable called body. At this point, as a side note, it might be interesting to mention that there should always be a single body element on an HTML page (unless there are iframes in it too). So feel free to run this command in your console: body[0], body[1], body[2], and see what comes up.

Finally, on line 15, we run a for loop, using the counter variable of i. The number of times the block of code on line 16 will be run depends on the length of the body HTML collection. Out of curiosity, to see how many times it was looped over, we added the console.log(i) on line 17 inside the block of code that’s being looped over.

This brings us to the answer of what will happen if we, for example, type out body[2] to the console.

The answer is simple: for anything but the first member of HTML collection - body[0] - you will get back the value of undefined. That’s why the snippet will only log out a zero to the console. The zero is the temporary value of the i variable, which is supposed to change based on how many times the for loop was ran. However, since the for loop only gets run once - because there is only one member in the body HTML collection - only a zero will be logged out to the console.

Let’s shift our focus to the last three lines of our dynamic event handler code snippet.

for (i = 0; i < body.lenght; i++) {
    body[i].addEventListener("click", addDivElement);
}

What we need to focus on is the built-in addEventListener method. This method accepts two parameters. The first one is the event that will trigger the handler function. The second one is the actual event handler function: the function that will be run to handle the event that happens.

What other events are available to us?

Some Commonly Used Events

At this stage, we’ll only list four events in JavaScript. There are many more events, but we will focus on these three for now, because we need to use them immediately and have some small wins, to keep up our dopamine levels and help us plow through the book easier.

The events we’ll be covering right now are:

  • mouseover,
  • mouseout,
  • keydown, and
  • oncontextment

Let’s practice using each one of them, by saving a number of snippets. Here are the new snippet names:

  • Practicing onmouseover event
  • Practicing onmouseout event

Practicing onmouseover Event

This first snippet will log out a message whenever we hover over an element with a mouse.

Here is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function addDivElement() {
    var div = document.createElement('div');
    div.innerHTML = `
        <div
        id="theDiv"
        class="dynamic"
        style="width:100px;height:100px;background:#dedede">
        Just another div
        </div>
        `;
    document.body.appendChild(div);
}

function changeDivColor() {
    var div = document.getElementById('theDiv');
    div.style = "width:100px;height:100px;background:yellow";
}

addDivElement();

var body = document.getElementsByTagName('body');

for (i = 0; i < body.length; i++) {
    body[i].addEventListener("mouseover", changeDivColor);
}

var reloadFn = function () {
    window.location.reload()
}

setTimeout(reloadFn, 5000);

Let’s run the above snippet. The script will first run the addDivElement function on line 19. Then it will assign the HTML collection into the body variable, and it will run the for loop on line 21.

Inside the for loop, on line 22, the event listener is waiting for the mouseover event to trigger the changeDivColor function.

Once you hover over the body element, the changeDivColor will be ran. We can see from its function definition that it sets the style property on the div object. The style property gets set to the exact same dimensions as before, except the color is changed from #dedede to yellow.

Finally, on the last three lines of code, we have some new concepts to explain. These new concepts are window.location.reload() and setTimeout.

The role of the window.location.reload() method is simple: when it’s run, it will refresh the browser. Why are we refreshing the browser? We are refreshing the browser so as to remove the changes we made to the document object by attaching our mouseover event handler - and of course, to learn how to refresh the browser using JavaScript.

The setTimeout function is also interesting. It’s an example of what’s sometimes called a facade function. A facade function is a function that looks like it’s part of JavaScript, but actually it’s not.

It’s a browser feature, i.e it’s a feature that exists outside of JavaScript, but that we can access via JavaScript nonetheless.

At this point, we won’t go into the details of what facade functions are. Suffice it to say that setTimeout, in our example, takes an anonymous function (a function without a name), and a number in milliseconds.

If you are at all confused by the term milliseconds, simply remember this: in one second, there are one thousand milliseconds.

Thus, in the last two lines of code in the above code snippet, we first add a label to a place in memory that stores the anonymous function which refreshes the browser, and we call this label the reloadFn variable.

Then, we run the setTimeout() facade function, and we pass it two parameters: the reloadFn function, and the number 5000.

Effectively, translated to plain English, we are telling the browser to set a timer and count for 5 seconds. Once these five seconds are up, run the reloadFn function (which will refresh the browser, as we already explained).

Practicing a mouseover and a mouseout Event

Let’s add another snipept to our Chrome browser. This time we’ll capture and handle both a mouseover and a mouseout event.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function addDivElement() {
    var div = document.createElement('div');
    div.innerHTML = `
        <div
        id="theDiv"
        class="dynamic"
        style="width:100px;height:100px;background:#dedede">
        Just another div
        </div>
        `;
    document.body.appendChild(div);
}

function changeDivColorToYellow() {
    var div = document.getElementById('theDiv');
    div.style = "width:100px;height:100px;background:yellow";
}

function changeDivColorToGray() {
    var div = document.getElementById('theDiv');
    div.style = "width:100px;height:100px;background:#dedede";
}

addDivElement();
    var body = document.getElementsByTagName('body');
    for (i = 0; i < body.length; i++) {
    body[i].addEventListener("mouseover", changeDivColorToYellow);
    body[i].addEventListener("mouseout", changeDivColorToGray);
}

If you run the above code as a snippet, you’ll notice that the moment you move your mouse over from the DevTools onto the web page, the background color of the div will change from gray to yellow, and vice-versa. We got ourselves a hover effect!

Although it is easy to do a hover effect in CSS, now you also know how to do it in plain vanilla JavaScript, using events. It’s a great feeling knowing how you can actually achieve this effect without CSS, in vanilla JavaScript!

Finally, we are ready to discuss the Event Object.

The Event Object

When we capture an event, this event gets returned as an object. The contents of the event object varies based on the kind of event that was captured.

Let’s now see what the event object looks like, by running a new snippet, which we’ll call The Event Object Practice.

1
2
3
document.body.addEventListener('mouseover', function(event) {
    console.log(event);
});

Pay attention to the JavaScript console when you run this event. Whenever you move the mouse over the document’s body, you will get new information logged to the console, such as:

MouseEvent {isTrusted: true, screenX: 475, screenY: 660, clientX: 475...}

If you click the little triangle on the left of the MouseEvent, you’ll get the detailed listing of this event object. There are a number of different properties and methods, listed in alphabetical order:

altKey, bubbles, button, buttons, cancelBubble, cancelable, clientX, clientY, composed,
ctrlKey...

This is the contents of an actual event object that we are listening for. The data stored inside the object is very useful. For example, if you locate the value of the defaultPrevented property, you’ll see that it’s set to false.

Try running a slightly different version of the code above:

1
2
3
4
document.body.addEventListener('mouseover', function (e) {
    e.preventDefault();
    console.log(e);
});

There are two things to observe in the updated code.

First, JavaScript doesn’t care what you call the captured event object when you pass it as the argument to the anonymous event handler function. You can call it event, whatever, or, what lots of people do, simply call it e.

Second, if you locate the defaultPrevented property on the event object, you’d find that it is now set to true.

You can check this programmatically, rather than digging through the returned event object in the console:

1
2
3
4
document.body.addEventListener('mouseover', function (e) {
    e.preventDefault();
    console.log(e.defaultPrevented);
});

Now, instead of the entire object, you’ll keep getting back true, whenever the event gets triggered, or like they say, when it gets “fired”.

Let’s try a more practical example, using a submit button on a regular HTML page.

We’ll begin our example with the DOCTYPE, and the html and head tags:

1
2
3
4
5
6
7
8
9
10
11
12
 <!DOCTYPE html>
 <html lang="en">

 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <title>Document</title>

     <style>
     </style>
 </head>

Next, we’ll add the body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body>
    <h1>Prevent a form from being submitted</h1>
    <form id="formToValidate">
        <input 
            type="text" 
            id="inputField" 
            placeholder="Please type 'abc' (without quotes)" 
            size="35" />
        <button type="submit">Submit</button>
    </form>
    <script>
    </script>
</body>

</html>        

Now we can add the actual JavaScript code inside the script tags.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
var theForm = document.querySelector("#formToValidate")
theForm.addEventListener("submit", function (e) {
    if (validateForm() != "abc") {
        e.preventDefault(); //stop the default 'submit' behavior
        alert("Please input 'abc' only!");
    } else {
        alert("The form is valid and was submitted");
    }
});

function validateForm() {
    isValid = document.querySelector("#inputField").value;
    if (isValid == "abc") {
        return "abc";
    } else {
        return false;
    }
}    
</script>

Save the above code in a new file and call it preventSubmit.html.

Now run it in the browser.

If you type anything other than lowercase abc into the text field and press the Submit button, you’ll get this alert: Please input ‘abc’ only!

However, if you type abc and press Submit, you’ll be alerted with the following message: The form is valid and was submitted.