Events
onload | event handler for responding to when the entire page has completed loading
Table of Contents
Event Propagation
This is the blanket term for both event bubbling and event capturing.
- Event propagation occurs when an event is fired on a DOM element. The event is also triggered by the parent elements.
- There’s the bubbling phase, where the event bubbles up from the originating node to the parent element, grandparent, and all the way up to window.
- Then there’s the capturing phase, where the event starts from window all the way down to the originating element that triggers the event.
Altogether, there’re 3 phases:
capturing phase — event starts from window then goes down all the way to child elements until it reaches the target element. target phase — event has reached the target element. bubbling — event bubbles up from the target element and goes up all the way to the window.
Event Bubbling
Event bubbling is a mechanism in JavaScript where events that occur on nested elements (such as a button inside a div) are propagated up the DOM tree and trigger events on their ancestor elements (such as the div).
ev.stopPropagation();
What is Event Bubbling?
This is the situation where events start from the element where the event originates from, and then event bubbles up to the parent, grandparent, etc., until it reaches the window object.
Event delegation
allows you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent. That event listener analyzes bubbled events to find a match on child elements.
Event Target
document.querySelector("my-element").addEventListener("click", e => { console.log(e);
}
Consider the typical markup to build a list of linked images, for a thumbnails gallery for example:
<ul>
<li><a href="a"><img src="a" alt="" /></a>
<li><a href="a"><img src="a" alt="" /></a>
abc
<li><a href="a"><img src="a" alt="" /></a>
</ul>
A click on an image does not only generate a click event for the corresponding IMG element, but also for the parent A, for the grandfather LI and so on, going all the way up through all the element’s ancestors, before terminating at the window object.
In DOM terminology, the image is the event target, the innermost element over which the click originated.
- Listen for events
- React to events
- Browser Events
- Document Loading Events
- Interactive Form Events
- Keyboard Events
- Mouse Events | Mouse Event Handlers
- Node Events
event listeners
attach event listeners to buttons, text, or images on the page in order to perform some action when the user interacts with the element
window.addEventListener()
Event Attachment
on();
off();
debounce
- event performance
- use debouncing with
scroll,resize,key*event - The debounce function will not allow a callback to be used more than once per given time frame. This is especially important when assigning a callback function to frequently-firing events.
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
// Usage
var myEfficientFn = debounce(function() {
// All the taxing stuff you do
}, 250);
window.addEventListener('resize', myEfficientFn);
poll
As I mentioned with the debounce function, sometimes you don't get to plug into an event to signify a desired state -- if the event doesn't exist, you need to check for your desired state at intervals:
// The polling function
function poll(fn, timeout, interval) {
var endTime = Number(new Date()) + (timeout || 2000);
interval = interval || 100;
var checkCondition = function(resolve, reject) {
// If the condition is met, we're done!
var result = fn();
if(result) {
resolve(result);
}
// If the condition isn't met but the timeout hasn't elapsed, go again
else if (Number(new Date()) < endTime) {
setTimeout(checkCondition, interval, resolve, reject);
}
// Didn't match and too much time, reject!
else {
reject(new Error('timed out for ' + fn + ': ' + arguments));
}
};
return new Promise(checkCondition);
}
// Usage: ensure element is visible
poll(function() {
return document.getElementById('lightbox').offsetWidth > 0;
}, 2000, 150).then(function() {
// Polling done, now do something else!
}).catch(function() {
// Polling timed out, handle the error!
});
Polling has long been useful on the web and will continue to be in the future!