Modern Web design calls for separating behavior, display, and content. To facilitate separation of behavior, event handler binding should be done in JavaScript instead of in the HTML. This can lead to issues with legacy sites or sites with more than one developer especially when linking external JavaScript files each binding events.

This How-to creates functions, addEvent and removeEvent, to handle the details of binding handlers to events under a wide variety of conditions.

Situation: You're writing new JavaScript to be used throughout a large site. Its functionality requires event handlers to be added or removed through script without stepping on existing handlers.

Let's define some of the terms as used in this article.

Binding
Connecting or attaching an event handler to an event or an object's event property. Event properties are usually name onevent; e.g. onclick.
Event
An event is a user action or system status change captured by the operating system and signaled to the application. For this how-to, an event is either the action such as a mouse click or the property of an object to which the handler is bound. Context will determine which meaning is intended. This usage is not precise, but aids in readability of the text and sufficent for our needs.
Event Handler (or simply Handler)
Is a function written by the developer, in this case using JavaScript, that is bounded to the event, and performs the required action in response to the event. It is sometimes called an event listener.

There are three ways to bind functions you've written to events.

Inline or Assignment to an HTML Attribute
Handlers can be assigned to HTML element attributes within the HTML. This is called inline binding or inline attachment; e.g., onclick="return eventHandler();". This is the oldest and most common method.
Assignment to an object's event property
Handlers can be bound by assigning the function to an object's event property. For example, window.onload = eventHandler;
Built-in methods to attach events
Methods like attachEvent or addEventListener and their opposites detachEvent and removeEventListener, which are built-in methods of DOM objects, can be used to bind handlers to events. This is the newest method and preferred method. For example, window.addEventListener("load", fx, false).

Inline and assignment both attach the handlers to an object's event property. The handlers can be accessed by object.eventname.toString(). This is NOT the case with addEventListener or attachEvent. These later methods attach the event handlers to another mechanism, which ignores handers bound by other methods, and they cannot be accessed like the other binding methods.

The last two binding methods are consistent with separating behavior from the other elements of Web design.

Inline binding is really the same as assignment to the object's event, only for inline binding the browser creates a wrapper function. This Demo1 link, for example, has the following inline handler for the click event.

onclick="this.innerHTML = (this.innerHTML == 'link demo1'? 'Demo1 link' : 'link demo1'); return false;"

Click the button below to see how the browser has wrapped the code into an event handler.


Browsers wrap the inline code in a function. Some use function onclick(event), while others use function anonymous().

Only one function can be bound to an event by assignment--you can't assign two values to a variable, right? To bind multiple handlers, the handlers need to be wrapped in a single function that is bound to the event. The browser does this for multiple inline event handlers. If you attempt to assign multiple functions without a wrapper function, only the last one will responded to the event. Handlers attached inline replace those attached by assignment.

This is a problem when adding functionality to a page by including multiple JavaScript files that each bind handlers to the same event. This situation commonly occurs for the window.onload event that runs initiation routines. Only one routine, the last one bound, will run. If there is an inline handler, that is the last one bound. So if a developer adds onload="alert('hi');" to the body tag the other initiation routines won't run and the code will be broken. Generally, however, the added functionality will be broken by the other JavaScript files or old inline event handlers. Then a page by page review has to be done to fix the problem.

The built-in functions allow binding multiple handlers to one event without any extra steps; although, they only allow binding a handler once to any event. And, they don't provide anyway to deal with legacy bindings. That is they leave legacy bindings—both inline and by assignment—alone and execute after the legacy handlers.

The addEvent code shown later is designed to deal with this situation. Instead of reviewing and updating every page in your site, just include this script in the page header and use its functions to bind or release handlers. It adds new handlers with the old. The script has six functions; three of which are user APIs, and three are internal to the process. The functions are:

addEvent
Binds an event handler to an event. It takes 4 arguments: HTML object, event name (without 'on' prefix), event handler, and an optional flag to force binding by assignment.
removeEvent
Removes handlers when the method of binding is known. It takes 4 arguments: HTML object, event name (without 'on' prefix), event handler, and an optional flag to force removal of handlers bound by assignment.
removeBinding
Removes handlers without knowing how they were bound. It takes 3 arguments: HTML object, event name (without 'on' prefix), and event handler. It attempts to remove the handler from the object's property (binding by assignment or inline) first. If the handler isn't found, it uses the function detachEvent or removeEventListener depending on the browser.
_bindEvent
Internal to process
_unbindEvent
Internal to process
_removeWrapper
Internal to process