Introduction into browser events

  1. Assigning event handlers
    1. Using a attribute of HTML-tag
      1. When to use this method
    2. The element is this
    3. Using a DOM-object property
      1. When to use
    4. Special methods
      1. Microsoft solution
      2. Handlers assignment by W3C standard
    5. Handlers order
    6. A cross-browser way of assigning event handlers
  2. Summary

Most JavaScript-applications perform actions as a response to events.

An event is a signal from the browser that something has happened.

There are many types of events.

  • DOM events, which are initiated by DOM-elements. For instance, a click event happens when an element is clicked, a mouseover - when a mouse pointer comes over an element,
  • Window events. For instance, resize - when a browser window is resized,
  • Other events, like load, readystatechange. They are used in AJAX and for other needs.

DOM events connect JavaScript code with the document, providing the means for building dynamical interfaces.

Assigning event handlers

For a script to react on the event, there should be a function assigned to it.

Functions which react on events are called event handlers. They are usually named like "on+event type", for instance: onclick.

JavaScript event handling is single-threaded, so handlers are executed sequentially. That means, if two events happen simultanteously, for example mouseover (mouse has come over an element) and mousemove (mouse moved over an element), their handlers will be executed one after another.

There are several ways of assigning an event handler. All of them are given in details below.

Using a attribute of HTML-tag

A handler can be set directly in the markup, right into the attribute named onevent.

For example, to process a click event on the input button, it is possible to assign an onclick handler like this:

<input id="b1" value="Click me" onclick="alert('Thanks!');" type="button"/>

In action:


The last example uses single quotes inside double quotes. An often newbie mistake is to forget that the code is inside an attribute.

Using them like onclick="alert("Click")" won’t work. If you really need it, try onclick="alert(&quot;Click&quot;)". But usually you don’t. Read on for more event handling methods.

It is also possible to call a function for the event handling.
The example below runs a function count_rabbits() if a button is clicked.

<!DOCTYPE HTML>
<html>
  <head>
    *!*
    <script type="text/javascript">
      function count_rabbits() {
        for(var i=1; i<=3; i++) {
          alert("Rabbit "+i+" out of the hat!")
        }
      }
    </script>
    */!*
 </head>
 <body>
    <input type="button" onclick="count_rabbits()" value="Count rabbits!"/>
 </body>
</html>

Please recall that HTML-tag attribute names are case-insensitive, so oNcLiCk will work same as onClick or onclick.

But it is generally considered a good style to use lowercase.

When to use this method

This way of assigning handlers is very convenient - it’s simple and all-inline, that’s why it is sometimes used for really simple tasks.

There are certain drawbacks of this method. When a handler becomes longer than one line - readability suffers greatly.

But, after all, no one writes somewhat complex handlers in HTML. Instead of it, use JavaScript-only ways which are described in the next subsection.

  • A simple way for simple tasks
  • Mixed JavaScript-code and HTML-markup
  • Difficult to write complex handlers

The element is this

Although usage of this event-binding method is not recommended, let’s demonstrate the value of this with it.

Inside an event handler, this references the current element. It can be used to get properties on modify the element.

Below, the button outputs it’s contents using this.innerHTML:

<button onclick="alert(this.innerHTML)">Click me to see me</button>

Using a DOM-object property

A closest relative of the way described above - is an assignment using the property named onevent.

All you need is:

  1. To get an element
  2. To assign a handler to the property onevent

Here is an example of setting a click handler to the element with id="myElement":

<input id="myElement" type="button" value="Press me"/>
<script>
document.getElementById('myElement').onclick = function() {
    alert('Thanks')
}
</script>

In action:

Please, note the two details:

  1. It is a property, not an attribute. The name of the property is onevent, case-sensitive and must be lowercased. onClick won’t work.
  2. The handler must be a function, not a string.

When the browser meets an on... attribute in HTML-markup - it basically creates a function from its contents and assigns it to the property.

So these two codes do the same:

  1. Only HTML:
    <input type="button" onclick="alert('Click!')" value="Button"/>
    
  2. HTML + JS:
    <input type="button" id="button" value="Button"/>
    <script>
     document.getElementById('button').onclick = function() {
         alert('Click!')
     }
    </script>
    

If there is a handler set in markup, the script overwrites it. In the example below, JavaScript replaces a markup handler with a new one.

<input type="button" onclick="alert('Before')" value="Press me"/>
<script>
document.getElementsByTagName('input')[0].onclick = function() {
  alert('After')
}
</script>

Of course, it is possible to use an existing function:

function doSomething() {
  alert('Thanks!')
}

document.getElementById('button').onclick = doSomething

An often newbie mistake

Please, note that the function should be assigned, namely doSomething, not doSomething():

document.getElementById('button').onclick = doSomething

doSomething() - is a result of function execution, and because there is no return in it, the result will be undefined.

Compare it against an attribute. Brackets are required there:

<input type="button" id="button" onclick="doSomething()"/>

The difference is easy to explain. When the browser comes across onclick attribute, it automatically creates a function from its contents. So the last example is basically same as:

document.getElementById('button').onclick = function() {
  doSomething()  // an autocreated function
}

When to use

Assiging handlers using a property is a very simple and popular way.

It has a problem: only one handler for a certain event type can be set.

For example:

input.onclick = function() { alert(1) }
// ...
input.onclick = function() { alert(2) } // replaces the previous handler

  1. A convenient and reliable way, works in JavaScript
  2. A single handler per event

Of course, it’s possible to copy old handler and run it manually inside a new one. But it is better to use more advanced methods of assignment.

Special methods

In a complex JavaScript application, it’s fairly ok that different interface components may be interested in handling the same event.

A classical example is a “document loaded” event and many graphical components which wait for it to initialize themselves.

Microsoft solution

The solution provided by Microsoft and used only in Internet Explorer less than 9.

It is also supported by Opera for compatibility, but no one uses it there, because Opera also supports another standard-compliant method (see in the next section).

Assigning a handler:

element.attachEvent( "on"+event, handler)

Removing a handler:

element.detachEvent( "on"+event, handler)

For instance:

var input = document.getElementById('button')
function handler() {
    alert('Thanks!')
}
input.attachEvent( "onclick" , handler) // assign the handler
// .... 
input.detachEvent( "onclick", handler) // remove the handler

An often newbie mistake

Please, note - setting and removal methods need the same handler object to operate correctly.

This would be wrong:

input.attachEvent( "onclick" ,
   function() {alert('Thanks')}
)
// .... 
input.detachEvent( "onclick", 
   function() {alert('Thanks')}
)

In the example below, there are actually two different function objects.

So if it is planned to remove the handler sometime, the reference to it should be stored somewhere.

Using attachEvent, it is possible to assign multiple handlers to the same event on same element. The example below will work only in IE and Opera:

<input id="myElement" type="button" value="Press me"/>

<script>
  var myElement = document.getElementById("myElement")
  var handler = function() {
    alert('Thanks!')
  }
 
  var handler2 = function() {
    alert('Thanks again!')
  }

  myElement.attachEvent("onclick", handler)
  myElement.attachEvent("onclick", handler2)
</script>

attachEvent does not pass `this`

The exception is attachEvent method. Handlers assigned with attachEvent do not have this!

Handlers assignment by W3C standard

W3C or official event handler assignment works in all modern browsers and for IE9.

Assigning a handler:

element.addEventListener( event, handler, phase)

Removing a handler:

element.removeEventListener( event, handler, phase)

Please, note that the event name goes without the “on” prefix.

Another difference from the Microsoft syntax is the third parameter - phase, which is usually not used and set to false.

The usage is generally same as attachEvent:

// ... declare a function called handler ...
elem.addEventListener( "click" , handler, false) // assign the handler
// .... 
elem.removeEventListener( "click", handler, false) // remove the handler

So, there is a one big plus and one minus of the special methods:

  1. As many handlers as you want
  2. Cross-browser incompatibilities

The incompatibilities is not just different syntax, but there are few other differences. We’ll return to it in the next sections and discuss a cross-browser method of event handling.

Handlers order

Special methods allow to assign multiple handlers to the same event on single object.

Browser does not guarantee the order in which they execute.

Generally, the order of assignment is not related with the order of execution. The order may happen to be same, or inversed or random.

A cross-browser way of assigning event handlers

The task is not so simple as it seems.

There simplest and mostly working solution is to create custom functions which add and remove event handlers using special methods:

if (document.addEventListener) {
    var addEvent = function(elem, type, handler) {
        elem.addEventListener(type, handler, false)
    }
    var removeEvent = function(elem, type, handler) {
        elem.removeEventListener(type, handler, false)
    }
} else {
    var addEvent = function(elem, type, handler) {
        elem.attachEvent("on" + type, handler)
    }
    var removeEvent = function(elem, type, handler) {
        elem.detachEvent("on" + type, handler)
    }
}

...
addEvent(elem, "click", function() { alert('hi') })

It works good in most cases, but the handler will lack this in IE, because attachEvent doesn’t provide this.

Fixing this problem may look easy, but it actually isn’t, because of advanced topics like IE<8 memory leaks.

But you don’t need this and don’t care about memory leaks, then the solution is simple and works well.

Use JavaScript to make the button hide the element with id="hide" when clicked. Demo:

The source document is here.

Open solution
Solution

The solution is demonstrated here: tutorial/browser/events/task/hideOther.html.


Create an input button which hides itself when clicked.

Like this:

Open solution
Solution

The solution is to use this in the handler to hide the current element.

<input type="button" onclick="this.style.display='none'" value="Click to Hide"/>


Create a menu which opens/closes on click, like this:

The source and images to start from are at tutorial/browser/events/sliding-src/index.html.

Open hint 1
Hint 1
Open solution
Solution

The initial CSS:

.menu ul {
    margin: 0;
    list-style: none;
    padding-left: 20px;
    
    display: none;
  }
  
  .menu .title {
    padding-left: 16px;
    font-size: 18px;
    cursor: pointer;
    
    background: url(arrow-right.png) left center no-repeat;       
  }

Open menu overrides:

.menu-open .title {
    background: url(arrow-down.png) left center no-repeat; 
  }
  
  .menu-open ul {
    display: block;
  }

You can find the full solution at tutorial/browser/events/sliding/index.html.


There is a message list. Add a delete button to each message to remove it.

The result:

The source is here.

Open hint 1
Hint 1
Open hint 2
Hint 2
Open hint 3
Hint 3
Open solution
Solution

The solution is shown here.

Summary

There are 3 ways of assigning event handlers: markup, onevent and special methods.

Tutorial

Donate

Donate to this project