Types of Events
Before covering the 3 primary ways of handling events, it’s worth knowing what types of events there are. MDN has the one of the easiest to read resources on this. If you go there, you’ll see there’s a ton of different event types! WebMonkey has a nice categorization of them:
- Page Events
- Form Events
- Keyboard Events
- Mouse Events
I think those are mostly self-explanatory and can help you chunk the events better. You don’t need to know every event in the spec by heart. The big takeaway here is that we can track and respond to just about everything a user might do on a webpage. So what are the primary ways that we can do this? Read on.
Method #1: Event Handlers
Event handlers are the first way that developers respond(ed) to events. Event handlers are also called inline event handlers. That’s because they are put right into the html elements. You’ve probably seen them in the form on onclick or onload. Here’s the syntax:
As you can see here, the onClick handler is put right onto the the anchor element. It will alert ‘welcome’ if it is clicked. Seems pretty straightforward, so what are the disadvantages of this approach?
- Mixing markup with functionality
- You can only put one handler per element
If you need to respond to other types of events on that element, too bad.
- HTML file size
Putting event handlers in your HTML is going to make your pages a lot heavier.
- Difficult code maintenance
- Polluting Global Scope
So event handlers were what came first and they work but there’s many drawbacks. Event listeners offer us a much better way to do this.
Method #2: Event Listeners (Observer pattern)
This event pattern relies on something called the “observer model”. The observer is the browser. The developer registers event listeners with the browser and says “hey browser, listen up. If this particular action happens, do this (aka run this function)”.
An Element, a Method, an Event, a Function…
The syntax for registering an event listener is pretty simple. Check out this jsfiddle that shows you which event is currently occurring on a page. Here’s an example from that fiddle.
Another way to understand this is imagine the developer is saying “Hey Browser, listen for when someone mouses over the document (the entire page). When they do that, call the sendOutput function. Note: you can register event listeners on any DOM nodes, not just HTML elements.
So event listeners are clearly an improvement over events handlers. So what are the downsides of using them?
Event listeners are not free. Your page/app will slow down when you have to attach Event Listeners to several hundred or thousand nodes.
It takes a lot of extra work and maintenance to register and track so many event listeners in an HTML document. What if you have list items or particular DOM nodes that are coming and going and changing a lot? With event listeners, you’re going to have to be constantly attaching and removing listeners as the DOM changes.
Event listeners give us a much better syntax but they are also not without their drawbacks.
A note about Bubbling and Capturing
You now need to know a bit about the phases of events. This can be a bit of a rabbit hole so we’ll try to keep this simple and high-level.
An event does not just occur on the element itself. It also occurs on all of its ancestors (parents and grandparents and so on). Let me show you with a code demo or we’ll get lost here otherwise.
What’s happening there? The term is event propagation, which includes capturing and bubbling. Capturing starts at the highest level of the DOM and fires/propagates the event on every ancestor until it hits the exact element where the event occurs. It then does the reverse in a process called bubbling.
Capturing makes a sound like this:
Bubbling, however, sounds like this:
Capturing/Bubbling are a rabbit hole like I said. They have to do with Netscape vs. Microsoft in the 90s and compromises and the chaotic evolution of the technologies that make up our beloved Internet. But we don’t need to go there.
Instead, let’s just focus on bubbling. Bubbling is where an event on a child (e.g. <li>) will propagate up to it’s parents, their parents, and their parents, all the way to the root of the document. Bubbling is what allows us to do event delegation.
Method #3 – Event Delegation
We know events are going to bubble up the DOM. So imagine we have some HTML like this:
<li id="li_1"><button id="button_1">Button A</button></li>
<li id="li_2"><button id="button_2">Button B</button></li>
<li id="li_3"><button id="button_3">Button C</button></li>
Now imagine that someone clicks on one of those buttons. If we were to use Method #2 (Event Listeners), we’d have to register a separate event listener onto each of those buttons (bleck).
But we know the event will bubble up from the <li> to the <ul> parent. What if we register an event listener on the <ul> and have it figure out which of its children got clicked? This is event delegation in a nutshell. The key is listen on the parents, not the children. Here’s the syntax.
Here’s the code in action. I’m going to use jQuery and explain why later.
jQuery excels at simplifying event delegation. You can, of course, do it in vanilla js but it takes roughly 4-5x as many lines.
In that particular example, I’m logging the event.target.nodeName. But try logging the event.target or just the event to get a sense for what other types of properties the event objects contain.
Here’s another really cool demo I found on CodePen where you can learn more about Bubbling through play: