JavaScript in the browser uses an event-driven programming model.
Usually things start by responding to an event.
The event could be the DOM is loaded, or an asynchronous request that finishes fetching, or a user clicking an element or scrolling the page, or the user types on the keyboard.
In this lesson we’ll analyze user activated events coming from the mouse or touch devices, like mouse clicks or tap events on mobile devices.
Event handlers
You can respond to any event using an Event Handler, which is a function that’s called when an event occurs.
You can register multiple handlers for the same event, and they will all be called when that event happens.
JavaScript offer three ways to register an event handler:
Inline event handlers
This style of event handlers is very rarely used today, due to its constraints, but it was the only way in the JavaScript early days:
<a href="#" onclick="alert('link clicked')">A link</a>
DOM on-event handlers
This is common when an object has at most one event handler, as there is no way to add multiple handlers in this case:
document.querySelector('a').onclick = () => {
alert('link clicked')
}
You can check if an handler is already assigned to an element using
if ('onclick' in document.querySelector('a')) {
alert('onclick handler already registered')
}
Using addEventListener()
This is the modern way. This method allows to register as many handlers as we need, and it’s the one you will find mostly used in the wild:
window.addEventListener('load', () => {
//window loaded
})
Listening on different elements
Sometimes addEventListener is called on window, sometimes on a specific DOM element. Why?
It’s a matter of determining how large of a net you want when you are looking at intercepting events.
You can listen on window to intercept “global” events, like the usage of the keyboard, and you can listen on specific elements to check events happening specifically on them, like a mouse click on a button.
The Event object passed to the event handler
An event handler gets an Event object as the first parameter:
const link = document.getElementById('my-link')
link.addEventListener('click', event => {
// link clicked
})
This object contains a lot of useful properties and methods, like:
target, the DOM element that originated the eventtype, the type of eventstopPropagation(), called to stop propagating the event in the DOM
and more. You can see the full list here.
Each specific kind of events, like a mouse click, a touch event, a keyboard event, all implement an event that extend this base Event object. We are talking about mouse and touch events in this lesson, so we are interested in these 2:
Mouse events
When looking at mouse events we have the ability to interact with
mousedownthe mouse button was pressedmouseupthe mouse button was releasedclicka click eventdblclicka double click eventmousemovewhen the mouse is moved over the elementmouseoverwhen the mouse is moved over an element or one of its child elementsmouseenterwhen the mouse is moved over an element. Similar tomouseoverbut does not bubble (more on this soon!)mouseoutwhen the mouse is moved out of an element, and when the mouse enters a child elementsmouseleavewhen the mouse is moved out of an element. Similar tomouseoutbut does not bubble (more on this soon!)contextmenuwhen the context menu is opened, e.g. on a right mouse button click
Events overlap. When you track a click event, it’s like tracking a mousedown followed by a mouseup event. In the case of dblclick, click is also fired two times.
mousedown, mousemove and mouseup can be used in combination to track drag-and-drop events.
Be careful with mousemove, as it fires many times during the mouse movement. We need to apply throttling, which is something we’ll talk more when we’ll analyze scrolling.
When inside an eventh handler we have access to lots of properties.
For example on a mouse event we can check which mouse button was pressed by checking the button property of the event object:
const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
// mouse button pressed
console.log(event.button) //0=left, 2=right
})
Here are all the properties we can use:
altKeytrue if alt key was pressed when the event was firedbuttonif any, the number of the button that was pressed when the mouse event was fired (usually 0 = main button, 1 = middle button, 2 = right button). Works on events caused by clicking the button (e.g. clicks)buttonsif any, a number indicating the button(s) pressed on any mouse event.clientX/clientYthe x and y coordinates of the mouse pointer relative to the browser window, regardless of scrollingctrlKeytrue if ctrl key was pressed when the event was firedmetaKeytrue if meta key was pressed when the event was firedmovementX/movementYthe x and y coordinates of the mouse pointer relative to the position of the last mousemove event. Used to track the mouse velocity while moving it aroundregionused in the Canvas APIrelatedTargetthe secondary target for the event, for example when movingscreenX/screenYthe x and y coordinates of the mouse pointer in the screen coordinatesshiftKeytrue if shift key was pressed when the event was fired
Touch events
Touch events are those events that are triggered when viewing the page on a mobile device, like a smartphone or a tablet.
They allow you to track multitouch events.
We have 4 touch events:
touchstarta touch event has started (the surface is touched)touchenda touch event has ended (the surface is no longer touched)touchmovethe finger (or whatever is touching the device) moves over the surfacetouchcancelthe touch event has been cancelled
Every time a touch event occurs we are passed a touch event:
const link = document.getElementById('my-link')
link.addEventListener('touchstart', event => {
// touch event started
})
Here are all the properties we can access on that event
identifieran unique identifier for this specific event. Used to track multi-touch events. Same finger = same identifier.clientX/clientYthe x and y coordinates of the mouse pointer relative to the browser window, regardless of scrollingscreenX/screenYthe x and y coordinates of the mouse pointer in the screen coordinatespageX/pageYthe x and y coordinates of the mouse pointer in the page coordinates (including scrolling)targetthe element touched
Event bubbling and event capturing
Bubbling and capturing are the 2 models that events use to propagate.
Suppose you DOM structure is
<div id="container">
<button>Click me</button>
</div>
You want to track when users click on the button, and you have 2 event listeners, one on button, and one on #container. Remember, a click on a child element will always propagate to its parents, unless you stop the propagation (see later).
Those event listeners will be called in order, and this order is determined by the event bubbling/capturing model used.
Bubbling means that the event propagates from the item that was clicked (the child) up to all its parent tree, starting from the nearest one.
In our example, the handler on button will fire before the #container handler.
Capturing is the opposite: the outer event handlers are fired before the more specific handler, the one on button.
By default all events bubble.
You can choose to adopt event capturing by applying a third argument to addEventListener, setting it to true:
document.getElementById('container').addEventListener(
'click',
() => {
//window loaded
},
true
)
Note that first all capturing event handlers are run.
Then all the bubbling event handlers.
The order follows this principle: the DOM goes through all elements starting from the Window object, and goes to find the item that was clicked. While doing so, it calls any event handler associated to the event (capturing phase).
Once it reaches the target, it then repeats the journey up to the parents tree until the Window object, calling again the event handlers (bubbling phase).
Stopping the propagation
An event on a DOM element will be propagated to all its parent elements tree, unless it’s stopped.
<html>
<body>
<section>
<a id="my-link" ...>
A click event on a will propagate to section and then body.
You can stop the propagation by calling the stopPropagation() method of an Event, usually at the end of the event handler:
const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
// process the event
// ...
event.stopPropagation()
})