Spying on elements!
Definition
An event is a "message" sent by the browser to inform that the internal state of a DOM object has changed.
DOM objects concerned can be the window
or any element node of the DOM tree.
To get these "messages", you must use listeners.
This design pattern is know as the "observer pattern".
There are different ways of listening to events on elements of the DOM. The correct solution is to use the addEventListener
method directly on the element.
In order to keep the content/behaviour separation, you shouldn't use onclick
, onload
... attributes in your HTML code.
If you use IE before version 9, you'll have to deal with their specific method attachEvent
. Event names a prefixed by on
and the event object is not passed to your callback, it can be accessed with window.event
.
Add
<div id="james" onclick="bond()">
var james = document.getElementById('james');
james.onclick = bond;
james.addEventListener('click', bond, false);
james.attachEvent('onclick', bond);
var bond = function(ev) {
ev = ev != null ? ev : window.event;
console.log(ev);
console.log('My Name is Bond...');
setTimeout(function() { console.log('...James Bond.'); }, 800);
}
Remove
Same remarks as for adding event listeners, use the W3C standard when you can. Note that you must use the same function
reference to remove an event listener. Removing an anonymous function
won't work.
var james = document.getElementById('james');
div.onclick = null;
div.removeEventListener('click', bond, false);
div.dettachEvent('onclick', bond);
Example
Try to click on the actors with or without maintaining the ctrl
key down.
Common properties
When you receive an event with your listener, you can access the event
object. It has several useful properties like target
or type
. Some of them are used in special conditions like bubbling, capturing or cancelling. See reference for more details.
target
type
timeStamp
eventPhase
bubbles
currentTarget
cancelable
defaultPrevented
isTrusted
UI Events
UI Events are special kind of events important for window, resources like images or just simple HTML elements.
load
unload
abort
error
resize
scroll
select
Example : scroll
Scroll the window with your mouse or using the scrollbars!
Mouse
Mouse events are really popular when dealing with web applications. There's a lot of events available. Understanding the differences between them is not so simple.
When you reveive a mouse event with a listener, you can access mouse specific properties such as cursor position etc... See reference for more details.
Note that mouseenter
and mouseleave
are only supported by IE and Opera.
Events
click
dblclick
mousedown
mouseenter
mouseleave
mouseup
mouseover
mousemove
mouseout
Properties
screenX
screenY
clientX
clientY
ctrlKey
shiftKey
relatedTarget
altKey
metaKey
button
Keyboard
Except for input
and textarea
, it is often better to listen to keyboard events on the window object. See bubbling/propagation below for more details.
When you reveive a keyboard event with a listener, you can access keyboard specific properties to know which key was pressed etc... See reference for more details.
DOM Event specification level 3 deprecates widely used properties such as keyCode
or charCode
. They are replaced by key
and char
but have a different behaviour. See reference for more details.
Events
Properties
altKey
ctrlKey
char
& charCode
key
& keyCode
location
metaKey
shiftKey
repeat
locale
Example : Keyboard events
Focus
Focus events are often used on HTML forms. Note that getting and losing focus is not only done by mouse clicks. The order in which those different events are fired is not consistent over each browsers. See reference for more details.
Events
blur
focus
focusin
focusout
DOMFocusIn
DOMFocusOut
Properties
Example : Focus events
Click on the two gray input text!.
Forms
These events are specific to HTML forms and are not part of the DOM 3 specification. See reference for more details...
Events
There's more...
Mutation events were a DOM Events level 2 specification. There's a few reason for its deprecation in DOM Events level 3. There's a work in progress to find a replacement. See reference for more details.
In order to go further from just handling simple keyboard events, the textinput
event is added to handle new ways to input text : speech, handwriting... See reference for more details.
Composition events are also added to handle specific and special text input. See reference for more details.
- Touch gestures
- Device orientation
- Custom events
- Drag n drop
- History
- Message
- Mutation
- TextInput
- Composition
- Wheel
Principle
When an event is fired on an element of the DOM, the event registered listeners are invoked. After this step, most events “bubble” up the DOM tree.
This behaviour can be used to improve performances. Instead of adding N listeners for N sibling elements, just listen to their parent. Because of event propagration your unique listener set on the parent will still receive events fired on children elements.
You can determine if the event you're dealing with has been bubbled to your listener or not with eventPhase
property.
You can prevent an event from bubbling up the DOM tree by calling stopPropagation()
on the event.
Bubbling is also called propagation.
console.log(ev.eventPhase === Event.BUBBLING_PHASE);
ev.stopPropagation();
Cancellation / prevent default
Principle
A lot of events have a default behaviour. The most common example is clicks on links.
You can determine if the default behaviour of an event can be cancelled using the cancelable
property.
You prevent an event from firing default behaviour after being handled by your listener by calling preventDefault()
on the event.
console.log(ev.cancelable);
ev.preventDefault();
Principle
When you listen to events on a given element using the W3C standard addEventListener
method, you can specify if you want to capture events.
A listener with capture will receive events from children elements BEFORE they receive it themselves.
james.addEventListener('click', bond, true);
console.log(event.eventPhase === Event.CAPTURING_PHASE);
How jQuery helps
In general jQuery makes the code easier to read when dealing with events. It's incredibly easier to implement event delegation. It also helps a lot to deal with IE strange way to manipulate events.
Classic on/off
Since jQuery 1.7, all event listening are done using on
and off
methods. If you were used to use bind/unbind
, delegate/undelegate
or live/die
, you should stop and prefer on
and off
.
For example a classic addEventListener
like this :
var james = document.getElementById('james');
james.addEventListener('click', bond, false);
Would be replaced by this jQuery code :
$('#james').on('click', bond);
It also works for many elements.
var lis = document.querySelectorAll('#actors li');
for (var i = 0; i < lis.length; i++) {
lis[i].addEventListener('click', callback, false);
}
$('#actors li').on('click', callback);
The code above creates as many listeners as li
elements in the DOM. It's usually bad. Be sure to prefer a syntax that leverage event delegation.
You could also use shortcuts like that. There's almost one shortcut for each event type.
$('#actors li').click(callback);
When you wanna removeEventListener
, just call off
method.
$('#actors li').off('click', callback);
Event delegation
The new on
method eases event delegation. Just select the node you want to delegate events to using $
and pass the targeted children selector as second argument of on
.
This example would be easy to change to use event delegation.
$('#actors li').on('click', callback);
Now that's better.
$('#actors').on('click', 'li', callback);
It's almost the same as doing that :
var ul = querySelector('#actors');
ul.addEventListener('click', function(ev) {
if (ev.target.nodeName === 'LI') {
callback(ev);
}
}, false);