Our textbook, Eloquent JavaScript, sets up the following scenario…
You'd have to repeatedly ask (read) the button for its state (at a very tiny time interval), and then perform the desired action.
Another paradigm for dealing with events is to have an API that allows functions to be called as a reaction to an event.
The API that JavaScript in the browser offers allows us to:
All of this is done through a method called addEventListener →
Where does this addEventListsener
come from, and what kind of object can you call it on (let's try it out)? →
Remember that Node objects have a prototype of EventTarget… and all elements are just nodes in the DOM
let ele = document.getElementsByTagName('div')[0];
while (Object.getPrototypeOf(ele)) {
console.log(Object.getPrototypeOf(ele));
ele = Object.getPrototypeOf(ele);
}
So… that means every DOM element has addEventListener, and you can use it to listen for events on that specific element.
Here's a quick example of using addEventListsener
: →
The markup:
<button>Hello</button>
Print hello
to the console whenever the button is clicked:
const b = document.querySelector('button');
b.addEventListener('click', sayHello);
function sayHello(evt){
console.log('hello');
}
So… some things to note about addEventListener
… →
It takes two arguments, an event (as a string), and a callback
click
and DOMContentLoaded
A few more details about the callback →
removeEventListener
(we'll see this a little later)removeEventListener('eventName', nameOfCallback);
this
for the element…Great, let's see some of this in action →
Make all of the paragraphs clickable… and change the text of the paragraph so that it displays the x and y position of the mouse click using the event object →
<style>p {border: 1px solid #000}</style>
<p>FOO</p> <p>BAR</p> <p>BAZ</p>
function handleClick(event) {
this.textContent = event.x + ',' + event.y;
}
const paragraphs = document.querySelectorAll('p');
paragraphs.forEach((p) => {
p[i].addEventListener('click', handleClick);
});
So, now that you have code: →
What are some criteria for where this stuff should live? →
DOMContentLoaded
event, right?
function main() {
console.log('THE DOM IS RED E');
}
document.addEventListener('DOMContentLoaded', main);
Again we'll be using these two events types (out of the many that are available - check out the mdn docs): →
Some other events that may be useful in your projects include:
blur
- when an element loses focusfocus
- when an element receives focuskeydown
- when a key is pressed downmousemove
- when the mouse movesmouseover
- when the mouse hovers over an elementThe callback to addEventListener
is called with an object that represents the event that occurred →
Depending on the event, the object may have the following properties
target
- the element that received the eventx
- the x coordinate of a mouse clicky
- the y coordinate of a mouse clickkey
- the key pressed (the character or a text description, such as ArrowDown
Using an example from the previous slides, let's remove the event listener on click so that it only says hello on the first click… and does nothing afterwards. We'll also log out some event object properties →
const b = document.querySelector('button');
b.addEventListener('click', sayHello);
function sayHello(evt){
console.log('hello');
}
console.log(evt.x, evt.y, evt.which);
this.removeEventListener('click', sayHello);
So… what happens if you have two elements nested within each other, and both have event listeners? →
Imagine that both the div
and h2
have event listeners. What happens when the h1
is clicked?
<div>
I have an event listener
<h1>So do I</h1>
</div>
Let's try nesting two elements (maybe a button in an article), add adding event listeners to both. →
<article>
<h1>About Events</h1>
<button>Click to Say Hello</button>
</article>
// in js
const a = document.querySelector('article');
const b = document.querySelector('button');
a.addEventListener('click', function(evt) {
console.log('article!');
});
b.addEventListener('click', function(evt) {
console.log('button!');
});
You can also prevent events from bubbling up by calling stopPropagation()
on the event object. Let's try it with the previous example to stop the paragraph event listener from being triggered. →
// modify your previous button event listener
b.addEventListener('click', function(evt) {
console.log('button!');
// the event won't bubble up!
evt.stopPropagation();
});
Most events have default actions on them. That is, there are some elements that react to events already. Can you think of any? →
But… what if the default action was not your intention? →
Use the preventDefault() method on the event object!
Create a link… but add an event listener to stop the browser from going to the page linked to… →
<a href="http://nyu.edu">a link to nyu</a>
// in js
const a = document.querySelector('a');
a.addEventListener('click', function(evt) {
console.log('link clicked!');
evt.preventDefault();
});
Let's make this face spin when we click it →
<div id="face">
🙅
</div>
Some styles:
#face {
font-size: 15em;
display: inline-block;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.dizzy {
animation: spin 5s linear infinite;
}
Simply toggle the dizzy class →
document.addEventListener('DOMContentLoaded', main);
function main() {
const face = document.querySelector('#face');
face.addEventListener('click', function clicked(evt){
this.classList.toggle('dizzy');
});
}