Event management in JavaScript

It is possible to create his own event handlers with the addEventListener function and objects as Event, EventListener, DocumentEvent.

This replaces predefined event handlers shaped as attributes of HTML or XML such as onClick, onMouseOver, etc. ...

And this is part of the Document Object Model Level 2 Events, a specification that describes an interface for events, ie to user actions, allowing to dynamically add event handlers to HTML or XML.

A function is linked to an action with addEventListener

This method associates an event handler to any element of an HTML page, dynamically after its loading.
The syntax:

EventTarget.addEventListener(DOMString type, EventListener fun, boolean)

Example:

x.addEventListener('click', function, false)

The parameters are in order:

  1. The type of the event.
  2. The name of a function called when the event is triggered.
  3. true for the capture mode or false for bubbling mode (see definitions at bottom).

Any tag has en EventTarget interface

A EventTarget interface is inherited by any element in an HTML page. This allowsto associate three methods:

In our example, the  x tag is de facto, as any tag, a EventTarget.

addEventListener may be associated to a document, a node (a tag), the document itself (document), a window (window name or window), the XMLHttpRequest object.

Several functions may be linked to an event on a same element:

x.addEventListener('click', function1, false);
x.addEventListener('click', function2, false);

The type of an event is a DOMString

The DOMString argument is a string that contains the name of a standard event. The supported events for mouse are:

For the keyboard (DOM 3):

DOM 3 recognizes other types of events, see links below.

The function in second parameter is a EventListener

The listener may be a function defined by the user or an object implementing the EventListener interface.
To pass parameters to the function, use an anonymous function.

The third parameter is a boolean: capturing the event or not

It concerns the capture of the event type. Use false if you do not want it.
If the value is true, all events of the specified type here will be passed first to the EventListener here before being passed to other EventTarget of inner tag in the document. Clearly the propagation of the event will go from container tags to tags they contain. By default it is the opposite.

Directly attaching the event to the object

Instead of using addEventListener we may attach directly the event to the object representing the tag in the DOM.

For example:

var x = documentGetElementById("mytag");
x.onclick = function(evt) { ... }

or:

function clickHandler(evt) { ... };
x.onclick = clickHandler;

It works with all browsers. There is always bubbling of events in this case, we can not choose the mode of propagation.

Propagation, how to stop it

If a type of event, for example onkeydown is attached to an element, and that the same event is also attached to the container of this element, when a key is pressed into the element, the event is triggered in this element at first, and then in the container.

To avoid bubbling of the event in other tags, we use the stopPropagation method which works with IE9 and all other browsers.

function keyhandler(evt)
{
  evt.stopPropagation();
  ... event management for x ...
}

x.onkeydown = keyhandler(evt);

For IE8 and earlier you may use instead:

evt.cancelBubble = true;   

Some key combinations are used by the browser itself, it is the case of CTRL-C, CTRL-U, CTRL-S, etc. ... These events are intercepted before processing the DOM of the content of the document so that the event handlers you created are never reached.
To get these events in your page, you can disable their treatment by the browser with the preventDefault method.

document.onkeydown=function(evt)
{
var code = (evt.keyCode || evt.which);
if(evt.ctrlKey) switch(code) { case 67: // ctrl-c case 85: // ctrl-u
evt.preventDefault(); evt.returnValue = false; .. processing.. break;
} }

These events which are managed by default at document level are not transmitted to inner elements, that is normal since the propagation is from the content to the containers (in bubbling mode). Removing their default management allows propagation when a contained element has the focus. If this is the document that has the focus, which is the case when we use the keyboard and no element is selected, there is no propagation to the event handlers of the elements of the document.
This problem does not exist with the mouse because it is always moved over or clicked on an element that so has the focus.

You can always give focus to an inner item:

document.getElementById("mytag").focus(); 

And then events associated with the element whose id is "mytag" will be processed first before being triggered on containers.

Demo addEventListener replaces HTML event handlers by dynamic code

For example, we'll see how to replace the HTML onClick attribute by addEventListener.

Normally the event handler is associated with an object, a button for example:

<input type="button" id="mybutton" value="Submit" onClick="myfunction()">

This calls a JavaScript function declared in a script:

function myfunction()
{
alert("Clicked");
}

The event handler onClick is removed:

<input type="button" id="mybutton" value="Submit">

It is replaced by a call to addEventListener:

function addOnClick()
{
var x = document.getElementById("mybutton");
x.addEventListener("click", myfunction, false);
}
window.onload=addOnClick;

The action "click" may be replaced with one of the other types listed above.

For compatibility with Internet Explorer 8 and earlier versions, you must use attachEvent:

function myfunction()
{
  alert("Clicked!");
}

function addOnClick()
{
var x = document.getElementById("mybutton");
if (x.addEventListener)
{
x.addEventListener('click', myfunction, false);
}
else
{
x.attachEvent('onclick', myfunction);
}
}

attachEvent has as first parameter the HTML event handlers in contrast to addEventListener.

Using addEventListener seems more complicated for an elementary action, as in this example, that the HTML attribute, but it opens the door to a much broader range of possibilities.
We can add an event handler in a JavaScript loop to an overall type of elements in the page.

Example with onClick

HTML code:

<input type="button" id="button1" value="Submit" onClick="myfunction()">

The JavaScript code is just the function defined above.

With addEventListener

Using addEventListener we can suppress the onClick in the HTML code.

HTML code:

<input type="button" id="button2" value="Submit">

The JavaScript code is that given above.

Dynamically creating code and adding an event handler

We create an img element to which is assigned an image that is then displayed, and an event manager that calls the function imageclick when you click on the image.
Note that the called function, the listener, can have a parameter with the use of an anonymous function as parameter of addListener.

Source code:

<div id="imgstorage"></div>
<script>
function imageclick(fruit)
{
alert("This is the image of: " + fruit);
}
var s = document.getElementById("imgstorage");
var i = document.createElement("IMG");
i.src="http://www.xul.fr/images/apple.jpg";
s.appendChild(i);
if(i.addEventListener)
{
i.addEventListener('click', function(){imageclick('Apple');}, false);
}
else
{
i.attachEvent('onclick', function(){imageclick('Apple');});
}
</script>

Appendix: Definitions

Capturing and bubbling

We speak of capture when an event is processed by the container tag before being passed to the tag contained. When talking about the reverse bubbling occurs, which is the standard when you do not specify anything in the code. Because the addEventListener property has a parameter to decide the order. If the third parameter is true, it is in capture mode, false if it is bubbling mode.

See also

References

© 2010-2012 Xul.fr