An event is something that happens.
An event object is an object containing properties such as its type (click, open, changed, keypress, etc.), the time at which it was generated, how it should behave (e.g., should it propagate), and type-specific information such as the window coordinates for a click event.
Events are dispatched to event targets. You register event listeners (also called event handlers) with the targets. Listeners are functions that execute when the event lands at the target.
This is getting complicated, so we need to write programs. But first, let’s see which events are out there.
Here are some of the standard events in browser land:
Ambient Light | devicelight |
---|---|
Battery status | chargingchange chargingtimechange dischargingtimechange levelchange |
CSS Animations | animationstart animationiteration animationend |
CSS Transitions | transitionrun transitionstart transitionend transitioncancel |
Clipboard | cut copy paste |
Device Orientation | devicemotion deviceorientation |
Drag and Drop | dragstart dragend dragenter dragleave drag dragover drop |
Focus | focus blur |
Form | reset submit |
Gamepad | gamepadconnected gamepaddisconnected |
History | pagehide pageshow popstate |
IndexedDB | complete success error abort versionchange upgradeneeded blocked |
Input | change input abort |
Keyboard | keydown keypress keyup |
Media | seeking seeked suspend pause play waiting ended playing durationchange loadeddata emptied loadedmetadata ratechange timeupdate canplaythrough canplay stalled volumechange |
Media Capture | devicechange |
Misc | languagechange invalid input hashchange |
Mouse | click dblclick mouseup mousedown mousemove mouseover mouseenter mouseout mouseleave wheel select contextmenu show |
Network | online offline |
Notifications | notificationclick |
Page | visibilitychange |
Pointer | lostpointercapture gotpointercapture pointerenter pointerleave pointermove pointerdown pointercancel pointerup pointerover pointerout pointerlockerror pointerlockchange |
beforeprint afterprint | |
Progress | loadstart load progress timeout abort error loadend |
Proximity | deviceproximity userproximity |
Push | pushsubscriptionchange push |
Resource | load beforeunload unload cached error abort |
Resource Timing | resourcetimingbufferfull |
SVG | beginEvent endEvent repeatEvent SVGLoad SVGUnload SVGResize SVGScroll SVGZoom SVGError SVGAbort |
Screen Orientation | orientationchange |
Selection | selectstart selectionchange |
Server Sent | open message error |
Service Workers | message |
Text Composition | compositionstart compositionend compositionupdate |
Touch | touchstart touchend touchmove touchcancel |
Update | noupdate obsolete updateready downloading checking error |
View | resize scroll fullscreenchange fullscreenerror |
Web App Manifest | appinstalled |
Web Audio | audioprocess complete ended |
Web Messaging | message |
Web Speech | resume error error soundstart soundend speechstart speechend voiceschanged start end nomatch result mark boundary audioend audiostart start end pause |
Web Storage | storage |
Web Sockets | open message error close |
Web Workers | message |
XMLHttpRequest | readystatechange |
Many browsers, and their plugins, will create tons of additional non-standard events. You should checkout the Event Reference page at MDN, which lists well over 100 standard and non-standard events.
See the Pen Transition Demo by Ray Toal (@rtoal) on CodePen.
In the browser, the possible event targets are:
window
object
document
object
The methods on event targets are: addEventListener
, removeEventListener
and dispatchEvent
.
Here’s the simplest case: We attach an event handler for the click
event to a <p>
element. When the event happens, the handler is called with the event object as the argument.
<body>
<p id="theP">Hello click me.</p>
<script>
document.getElementById('theP').addEventListener('click', (e) => {
console.log(e.type, e.target.tagName, e.clientX, e.clientY, e.isTrusted);
});
</script>
</body>
When you click on the paragraph, you will see something like:
click P 28 16 true
But wait. That <p>
element was nested inside a <body>
element, so doesn’t the body element get the event, too? If so, which one—the inner or outer element—would get the event first?
Actually all of the possible targets get the event...twice! If you click on the paragraph element, a click event is sent first to the window, then to the document, then to the body, then to the paragraph, then to the paragraph again, then the body again, the document again, and finally to the window again. Did you notice how this event propagation happens in two phases? First, the event propagates outside-to-inside in the capturing phase, then inside-to-outside in the bubbling phase. Let’s explore:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Exploring Events</title> <style> body, div, p, span {margin: 20px; padding: 8px} body {background-color: #eeffee} div {background-color: #ffffee} p {background-color: #eeffff} span {background-color: #ffeeff} </style> </head> <body id="thebody"> <div id="thediv"> Before <p id="theparagraph">Hello you can <span id="thespan">click here</span></p> After </div> <script src="events.js"></script> </body> </html>
function say(arrow, e, name) { console.log(`${arrow} ${name} received ${e.type} during ${e.eventPhase}`); } function addListeners(el, name) { el.addEventListener('click', e => say('⬇︎', e, name), true); el.addEventListener('click', e => say('⬆︎', e, name), false); } document.querySelectorAll('[id]').forEach(el => addListeners(el, el.id)); addListeners(document, 'The document'); addListeners(window, 'The window');
Note the third argument to addEventListener
: if true
, the handler kicks in during the capture phase; if false
, in the bubbling phase. We’ve added capture and bubble listeners to the document and all four elements, allowing us to see the propagation in action. Here’s what we see when we click on the innermost span:
This example shows off some properties of the event object:
type
: a string such as 'click'
, 'touchStart'
, or 'load'
.
target
: the entity responsible for the event in the first place; generally the innermost element.
currentTarget
: the entity currently handling the event.
eventPhase
: 1 if in the capture phase, 2 if at the target, and 3 if in the bubble phase. (The 2 can be confusing because you still get a capture event and a bubble event when in phase 2. I compensated for that above by logging arrows in my handler.)
Get the complete details at MDN or the DOM Living Standard.
Within a handler, you can call e.stopPropagation()
. It does just what you think it does.
You can programmatically fire events yourself with dispatchEvent
. Such events are not trusted. This is best learned with an example. Trusted clicks come from your mouse, trackpad, or other real device, while a timer in our code dispatches nontrusted click events every few seconds:
<body>
<p id="theP">Hello click me.</p>
<script>
const p = document.getElementById('theP');
p.addEventListener('click', (e) => {
console.log(e.isTrusted ? 'REAL CLICK' : 'FAKE CLICK!!');
});
// Send fake clicks every five seconds
setInterval(() => p.dispatchEvent(new Event('click')), 5000);
</script>
</body>
TODO
TODO
TODO
Now that we know a bit about events,
TODO
TODO
TODO
Node.js is a JavaScript runtime system that provides access to files, processes, memory buffers, the console, the network, timers, etc.: all kinds of things for which event-driven programming shines.
Official documentation on Node.js Events.
TODO