Dom Events

Learning Objectives
Students will be able to: |
---|
Add event listeners for events such as click |
Explore the event object |
Explain event bubbling |
Use event bubbling to implement event delegation |
Stop an event from bubbling |
Road Map
- Setup
- What are DOM events?
- What's an Event Listener?
- Our first Event Listener
- The Event Object
- Adding a New Comment
- Event Bubbling
- Event Delegation
- Removing Event Listeners
- Essential Questions
- Further Study
Videos
1. Setup
Once again, we will use an actual project structure instead of working within Replit.
Create the Project Files
- Move in your
code
folder/directory:cd ~/code
- Create a new directory named
dom-events
:mkdir dom-events
- Move into the new directory:
cd dom-events
- Create an
index.html
file:touch index.html
- Open the directory in VS Code:
code .
- Open
index.html
in the editor and use! [tab]
to create the HTML boilerplate - Create a
js
directory and touch ajs/main.js
file - Add a
<script>
tag to includemain.js
in the<head>
:
<head>
...
<title>DOM Events</title>
<script defer src="js/main.js"></script>
</head>
The
defer
attribute ensures the DOM is ready before the script executes.
- Finally, let's add an
<h1>
inside of the<body>
as follows:
...
<body>
<h1 id="title" class="main-title">DOM Events</h1>
</body>
</html>
View index.html
in Live Server
Click "Go Live" in the status bar at the bottom of VS Code.
Live Server should automatically open index.html
in a new browser tab:
2. What are DOM Events?
DOM events are the bedrock of interactivity on web pages.
DOM events enable us as developers to implement event-driven programming. This programming paradigm is such that much of our code runs in response to events being triggered during run-time (usually due to user interaction).
Lots of events are being generated within the browser, for example, when:
- A user moves or clicks the mouse
- A user presses a key
- When a form is submitted
- When the page has finished loading or has been resized
- etc.
Take a peek here at the sheer number of events.
3. What's an Event Listener?
An event listener is a function, more specifically, a callback function, that is called when an event fires.
Event listeners may also be referred to as event handlers.
How Are Event Listeners Are Added to DOM Elements?
The best practice approach to register an event listener is to use the addEventListener() method.
Here is the syntax for attaching an event listener for a given event:
element.addEventListener('event-name', <callback>);
- event-name is the name of the event: - EX:
'click'
- callback is the function we want executed when the event happens. When called by the JS engine, it will be passed an event object as an argument.
- From now on, in our examples we will refer to this event object as either:
evt
ore
.
- From now on, in our examples we will refer to this event object as either:
4. Our first Event Listener
Add Additional HTML
Let's add the following HTML between the <body>
tags in index.html
:
<h3>Comments</h3>
<ul>
<li>SEI Rocks!</li>
</ul>
<input>
<button>Add Comment</button>
Listen to the click
Event on the <button>
We can add a click
event listener to pretty much any element - not just buttons. However, buttons are pre-styled to look and act clickable 😃
We're going to use an anonymous callback function in this first example:
// Select the button
const btn = document.querySelector('button');
// Attach event listener to our button
btn.addEventListener('click', function(evt) {
// testing!
console.log(evt);
});
If all goes well, clicking the button should log out the event object.
Congrats, attaching your first event listener!
❓ What's the name of the method used to attach event listeners to elements?
addEventListener()
❓ Name three events that might be triggered in the browser.
click
, submit
, change
, mousemove
, etc.
5. The Event Object
Examining the event object that was provided as an argument to our event listener reveals lots of useful information about the event!
Of special interest are:
-
Several
...X
and...Y
properties that provide where the click occurred. -
The
target
property, which holds a reference to the DOM element that triggered (dispatched) the event.
The target
property will certainly be the one to remember as it will be used very often moving forward.
6. Adding a New Comment
Application Logic
When we click the [Add Comment]
button, we'll need our event listener function to do the following:
- Create a new
<li>
element - Set the
<li>
element'sinnerText
to that of the text entered in the<input>
- Append the
<li>
to its parent, the<ul>
- Finally, clear the text from the
<input>
Creating a New <li>
Element
If we want to add a new comment to the DOM, we're going to need to create a new <li>
element.
Here's how we can do it using the document.createElement
method:
btn.addEventListener('click', function(evt) {
// Create a new <li> element
const newCommentEl = document.createElement('li');
console.log(newCommentEl)
});
Note: At this point, the element is "in memory" only and is not part of the DOM (yet).
Okay, we have a new <li>
element created and assigned to a variable named newCommentEl
, but it has no content...
Getting/Setting the Text of an <input>
We'll need to access the text the user has typed into the <input>
element in order to set the innerText
of newCommentEl
.
Since <input>
elements are empty elements, i.e., elements with no content, innerText
and innerHTML
properties do not exist.
Instead, we get and set the text within an <input>
using the value
property.
NOTE: The
value
property maps to thevalue
attribute in HTML.
Because this app needs to access <input>
every time the <button>
is clicked, it would be more efficient to select/declare <input>
outside of the event handler function. This way, the element is only declared once, it's placed in cache - a developer term for 'remember' or 'store' - and we aren't selecting it again with each click:
// Cached elements
const inputEl = document.querySelector('input');
btn.addEventListener('click', function(evt) {
const newCommentEl = document.createElement('li');
// Access the input's text
const commentText = inputEl.value;
console.log(commentText)
});
🤔 For future reference, it's worthwhile to remember that we use the value
property to get/set the text of an <input>
element.
Setting the Content of the <li>
So, now we can set the innerText
of the new <li>
:
// Cached elements
const inputEl = document.querySelector('input');
btn.addEventListener('click', function(evt) {
const newCommentEl = document.createElement('li');
const commentText = inputEl.value;
// Set newComment's text
newCommentEl.innerText = commentText;
});
Now the new <li>
is ready to be added to the DOM...
Adding the <li>
to the DOM
❓ Which element do we we want to add the <li>
to?
<li>
to?The <ul>
There are a few ways to add DOM elements to the document using JavaScript.
One common way to add new elements to another element is by using the append() method like this:
// Cached elements
const inputEl = document.querySelector('input');
// Remember the <ul> too!
const ulEl = document.querySelector('ul');
btn.addEventListener('click', function(evt) {
const newCommentEl = document.createElement('li');
const commentText = inputEl.value;
newCommentEl.innerText = commentText;
// Add the new li as the ul's last child
ulEl.append(newCommentEl);
});
Test it out - nice!
Clearing the Text in the <input>
The new comment has been added, but if we want to improve the UX, we have one more task - clear out the <input>
.
👉 YOU DO: Improve the UX (1 min)
-
Clear the text in the
<input>
by adding one line of code.Hint: What's the property that we used to get the text?
7. Event Bubbling
When an event occurs on an element, that event bubbles up through the DOM, all the way up to the document
object.
All event listeners attached for the same event, such as click
, will be invoked along the path to the document
element - unless one of those listeners calls the event object's stopPropagation() method.
How can our apps benefit from this event bubbling? Let's see...
8. Event Delegation
What is Event Delegation
Imagine a web app, like a game perhaps, with lots of elements that need to respond to a click. It's possible there could be tens, hundreds or more of these elements.
That would be a lot of event listeners, wouldn't it - not very efficient at all.
Plus, every time a new element is added, an event listener would also have to be attached 🤢
We can avoid this predicament by using a technique know as event delegation.
Event delegation allows us to attach an event listener to a single DOM element that can respond to events triggered by any of its descendant DOM elements. Much more efficient!
Implementing Event Delegation
Let's attach an event listener (this time we'll use a named function) on the <ul>
that can respond to clicks on any of its nested <li>
elements:
ulEl.addEventListener('click', handleClick);
// Naming the function handleXxxxx is a great practice
function handleClick(evt) {
console.log(evt.target);
}
Important: The event object's
target
property will be set to the actual element that was clicked!
Not only is event delegation more efficient, by it's very design, it's dynamic - as descendants are added, they too will be listened to!
👉 YOU DO: Event Delegation (2 mins)
Now that we have a delegated event listener in place, let's:
- Write the code to change the color of the text of a clicked comment to a color of your choosing.
Hint: DOM elements have a
style
property that's an object with the CSS properties (named using camel-casing), e.g.,someElement.style.fontSize
.
9. Removing Event Listeners
Although not usually necessary, it's possible to remove an event listener, but only if a named function was used as the callback.
This is how we could detach the event listener from the <button>
:
btn.removeEventListener('click', handleClick);
10. ❓ Essential Questions
(1) What is the argument that JS passes to an event listener when it calls it?
The event object
(2) What is the name of the property available on the above argument that represents the DOM element that triggered/dispatched the event?
target
(3) Let's say we needed to have an event listener respond to a click
event on the <td>
elements within a <table>
- would we have to add event listeners to each <td>
? Support your answer.
click
event on the <td>
elements within a <table>
- would we have to add event listeners to each <td>
? Support your answer.No. Thanks to Event Delegation we could add the event listener on either the <tbody>
or <table>
element
11: Further Study
Less Useful Ways to Add Event Listeners
In addition to the addEventListener()
method, there are two other ways to register event listeners:
- In the HTML (inline):
<button id="reset-btn" onclick="reset()">
- Assigning to DOM elements' properties:
resetBtn.onclick = reset;
Using the HTML approach (onclick="reset()"
) is typically frowned upon because it requires that the function be in the global scope. In addition, this - like inline styling - breaks the separation of concerns design principle.
The DOM element approach (resetBtn.onclick = reset;
) is a little better because the function does not have to be in global scope.
We want to make you aware of both of these approaches so you know to avoid them as they are not considered best practice.