UIZE JavaScript Framework

GUIDES Javascript Dom Events

1. Introduction

The UIZE JavaScript Framework provides versatile features for managing the wiring and unwiring of event handlers for DOM events of HTML elements.

1.1. DOM events vs. UIZE events

DOM events are events that originate from HTML elements / DOM nodes in a document.

DOM events are different from UIZE events that can be fired by any instance of a Uize.Class subclass, or by Uize.Class subclasses themselves. DOM events are unique to the Web browser environment, whereas UIZE events are supported in any environment that is supported by the UIZE JavaScript Framework, such as Microsoft's Windows Script Host and Adobe's ExtendScript environments. For more information on UIZE events, consult the guide JavaScript Event System.

Some examples of DOM events are...

click - fired when the user clicks on a DOM node
mouseover - fired when the user mouses over a DOM node
mouseout - fired when the user mouses out of a DOM node
load - fired by the window object when the document has loaded, and by img nodes when their image completes loading
keypress - fired by text input and textarea nodes when the user presses down on a key of the keyboard

1.2. The Benefits of Abstraction

Different browsers implement DOM event support in different ways, and so the DOM event management methods of the UIZE JavaScript Framework abstract these differences to produce one API to provide cross-browser support.

1.2.1. A Single Interface

Cross-browser support means that you don't have to worry about the differences in how different browsers treat DOM events.

You can author Web applications using one interface and leave it to the framework to hide the differences for you. As browsers change, the abstraction may need to change, but your application code can be insulated from these disruptive changes.

1.2.2. A Sweeter Interface

The DOM event management methods of the UIZE JavaScript Framework provide a sweeter interface to managing DOM events than what browsers provide.

Versatile methods ease wiring and unwiring of multiple handlers for multiple DOM nodes - in a single method call. All handlers for a specific event of a DOM node can be unwired, without knowing the original handler functions. All handlers for all events of a DOM node can be unwired, without knowing which handlers were wired to which events.

1.2.3. Fixing Problems

The DOM event methods of the UIZE JavaScript Framework fix certain problems that afflict the event systems of certain browsers.

For one thing, UIZE deals with the issue of circular reference memory leaks that occurs as a result of closures in Internet Explorer 6 by implementing a CRIS (Circular Reference Isolation System). This system isolates the closure's scope from the event handler, effectively breaking the circular references.

1.2.4. Extended Capabilities

The framework's DOM event management methods also provide extended capabilities beyond what is offered by the DOM event systems of the browsers.

An example of this is the mouserest virtual DOM event. This event is not a real DOM event - it is implemented by UIZE. Using this event, you can wire handlers that will be executed when the user rests their mouse over a DOM node for a specifiable amount of time - you get to decide how long. This and other virtual DOM events are implemented in various modules under the Uize.Dom.VirtualEvents namespace, such as the Uize.Dom.VirtualEvents.Remain and Uize.Dom.VirtualEvents.ModClick modules.

2. Event Wiring Basics

In this section we will take a look at the basics of wiring and unwiring event handlers for DOM nodes.

2.1. Wiring an Event

Wiring an event handler for a DOM node is easy, using the Uize.Dom.Basics.wire static method of the Uize.Dom.Basics module.

EXAMPLE

Uize.Dom.Basics.wire ('myLinkTag','click',function () {alert ('You Clicked Me!')});

In the above example, we are wiring a handler for the click event of the link tag that has the id of "myLinkTag". The first parameter of the Uize.Dom.Basics.wire method call specifies the DOM node, the second parameter specifies the event, and the third parameter specifies the handler function. After the above statement has been executed, clicking on our wired link tag will pop up a JavaScript alert dialog with the message "You Clicked Me!".

2.1.1. Event Naming

The DOM event management methods of the UIZE JavaScript Framework opt to name events using the standardized names established in the DOM Level 2 Event Model and DOM Level 3 Event Model specifications - without the "on" prefix that is used with the reflected properties of DOM nodes (e.g. onclick, onmouseover, onmouseout, etc.).

OLD SCHOOL

document.getElementById ('myLinkTag').onclick = function () {alert ('You Clicked Me!')};

NEW SCHOOL

Uize.Dom.Basics.wire ('myLinkTag','click',function () {alert ('You Clicked Me!')});

The naming without the "on" prefix is consistent with the way that events are named in the type property of the event object. For example, an event fired when a key is pressed is called a "keypress" event, and the value for the type property of the event object for this event will be 'keypress', and in the UIZE JavaScript Framework's event management methods this event is also known as keypress.

2.1.1.1. Old School Naming Still Supported

While the advocated naming convention for events omits the "on" prefix, it is still permitted to specify events using this prefix with the event wiring and unwiring methods.

EXAMPLE 1

Uize.Dom.Basics.wire ('myLinkTag','click',function () {alert ('You Clicked Me!')});
Uize.Dom.Basics.wire ('myLinkTag','onclick',function () {alert ('You Really Clicked Me!')});

In the above example, two event handlers are being wired to the click event of the node with the id of "myLinkTag". While the value 'onclick' is specified for the event name when wiring the second handler, the Uize.Dom.Basics.wire method maps this to the click event. After the above code has executed, clicking on our link tag would produce two alert dialogs in succession.

EXAMPLE 2

Uize.Dom.Basics.wire ('myLinkTag','click',function () {alert ('You Clicked Me!')});
Uize.Dom.Basics.unwire ('myLinkTag','onclick');

In the above example, an event handler is being wired to the click event of the node with the id of "myLinkTag". While the value 'onclick' is specified for the event name when calling the Uize.Dom.Basics.unwire method, this method maps this event name to the click event, and so all handlers wired for the click event of this node are unwired. After the above code has executed, clicking on our link tag would not produce an alert dialog.

2.1.2. Getting the Event Object

Handlers that are wired to DOM node events using the Uize.Dom.Basics.wire method can expect to receive a single parameter, being a reference to the event object for the DOM event being handled.

EXAMPLE

Uize.Dom.Basics.wire ('myLinkTag','click',function (eventObj) {alert (eventObj.type)});

In the above example, we have named our parameter eventObj, but it really doesn't matter what you name this parameter in your handler functions. This time, in our handler we're using the eventObj to get the type of the event that is being handled, which is done by dereferencing the type property of eventObj. Clicking on our wired link tag will pop up a JavaScript alert dialog with the message "click".

Though we've wired the event by specifying the event name 'click', the type property of the DOM event object does not have the "on" prefix for event names (refer to the section Event Naming). Also note that, while you can get a reference to the DOM event object using the first parameter of your handler function, it is not necessary to declare this parameter if you won't be using the event object. And, more often than not you won't actually care about the event object.

2.1.3. Getting the Target DOM Node

Handlers wired to DOM node events using the Uize.Dom.Basics.wire method are called as instance methods on the DOM nodes for which they are wired.

EXAMPLE

Uize.Dom.Basics.wire ('myLinkTag','click',function () {alert (this.tagName)});

In the above example, we're using the this keyword inside our handler function's implementation to get a reference to the DOM node on which the click event was fired - the target of the event. Because this is a reference to a DOM node, we can dereference the tagName property to get the name of the tag for the node. It will be "A" in this case, because we have wired the click event of a link tag.

The behavior of calling handlers as instance methods on the DOM node for which they are wired is consistent with the behavior when using the old school approach of wiring handlers by assigning a function reference to the event handler property of DOM nodes, as in the example below...

OLD SCHOOL

document.getElementById ('myLinkTag').onclick = function () {alert (this.tagName)};

Of course, the old school approach has fallen out of favor because it does not facilitate interoperability with other code that might also wish to wire handlers for the same event on the same node. By contrast, the Uize.Dom.Basics.wire method allows multiple handlers to be wired for the same event of the same node.

2.1.4. Specifying a DOM Node By Reference

When wiring an event for a DOM node, you can specify the DOM node by id or by reference.

BY ID

Uize.Dom.Basics.wire ('myLinkTag','click',function (eventObj) {alert (eventObj.type)});

BY REFERENCE

Uize.Dom.Basics.wire (
  Uize.Dom.Basics.getById ('myLinkTag'),
  'click',
  function (eventObj) {alert (eventObj.type)}
);

Ok, so clearly in this case it is more concise to specify the DOM node by ID, but there may be other reasons why you would want to specify a DOM node by reference. For instance, you may have received a reference to a DOM node in some function parameter, or you may want to use a reference stored in some variable.

2.2. Unwiring an Event

Unwiring an event handler for a DOM node is just as easy as wiring one, using the Uize.Dom.Basics.unwire static method of the Uize.Dom.Basics module.

EXAMPLE

function clickHandler () {alert ('You Clicked Me!')}

Uize.Dom.Basics.wire ('myLinkTag','click',clickHandler);
Uize.Dom.Basics.unwire ('myLinkTag','click',clickHandler);

In the above example we are wiring a handler for the click event of the node with the id of "myLinkTag". Then, we are unwiring that exact same event handler. Therefore, after the code has executed, clicking on our link tag will not pop up the alert dialog. Notice how we are specifying the event handler function by reference, and how the function is defined outside of the wiring and unwiring statements. This is necessary in order for the Uize.Dom.Basics.unwire method call to exactly match the event wiring established by the Uize.Dom.Basics.wire method call. In order to successfully unwire the wiring, the DOM node, event name, and event handler function must match exactly. To illustrate this subtlety, consider the following example...

INCORRECT

Uize.Dom.Basics.wire ('myLinkTag','click',function () {alert ('You Clicked Me!')});
Uize.Dom.Basics.unwire ('myLinkTag','click',function () {alert ('You Clicked Me!')});

In the above example, we are specifying one handler function in the Uize.Dom.Basics.wire method call and a completely different handler function in the Uize.Dom.Basics.unwire method call. Yes, they do exactly the same thing and look identical, but they are totally different functions in the eyes of JavaScript - each one is its own anonymous function.

2.3. Wiring Multiple Events

The Uize.Dom.Basics.wire method of the Uize.Dom.Basics module makes it easy to wire handlers for multiple events of a DOM node in a single method call.

EXAMPLE

Uize.Dom.Basics.wire (
  'myDiv',
  {
    mouseover:function () {this.className = 'divHover'},
    mouseout:function () {this.className = 'divDefault'},
    click:function () {alert ('You Clicked Me!')}
  }
);

In the above example, we're wiring the mouseover, mouseout, and click events on a div tag with the id of "myDiv". Some browsers do not support the hover CSS pseudoclass for div tags, so we're wiring the mouseover and mouseout events here to achieve hover highlighting for the div by changing the value of its className property. We're still using the Uize.Dom.Basics.wire method, but the method's parameter signature is quite different than it is for wiring a single event handler (as shown in the section Wiring an Event). In this case the first parameter is the DOM node, and the second parameter is an object that contains mappings between event names and handler functions. You can specify as many event-name-to-handler mappings as you like in this object.

2.4. Unwiring Multiple Events

Handlers for multiple events can be unwired using the Uize.Dom.Basics.unwire method, just as easily as wiring multiple events using the Uize.Dom.Basics.wire method.

EXAMPLE

function setDivHoverClass () {this.className = 'divHover'}
function setDivDefaultClass () {this.className = 'divDefault'}
function showYouClickedMeAlert () {alert ('You Clicked Me!')}

Uize.Dom.Basics.wire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

Uize.Dom.Basics.unwire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

In the above example, we're using the form of the Wiring Multiple Events method that takes multiple event-name-to-handler mappings to unwire all of the event handlers wired in the previous call to the Uize.Dom.Basics.wire method. Notice how we are specifying the event handler functions by reference, and how the functions are defined outside of the wiring and unwiring statements, just as in the simple case of unwiring an event. After the above code has executed, our div will have no hover highlighting behavior and no alert dialog will pop up when it is clicked.

2.4.1. Storing Handlers, For Later Unwiring

In cases where you know that you might like to unwire a specific set of event handlers at a later stage, you can create a variable to store the event-name-to-handler mappings.

That way, you can use that variable when both wiring and unwiring the event handlers, as shown in the example below...

EXAMPLE

var divHandlers = {
  mouseover:function () {this.className = 'divHover'},
  mouseout:function () {this.className = 'divDefault'},
  click:function () {alert ('You Clicked Me!')}
};

Uize.Dom.Basics.wire ('myDiv',divHandlers);
Uize.Dom.Basics.unwire ('myDiv',divHandlers);

2.4.2. Wiring With Single Form, Unwiring With Multiple Form

Event handlers wired using the variation of the Uize.Dom.Basics.wire method that wires a single event can be unwired using the variation of the Uize.Dom.Basics.unwire method that takes multiple event-name-to-handler mappings, as shown in the example below...

EXAMPLE

Uize.Dom.Basics.wire ('myDiv','mouseover',setDivHoverClass);
Uize.Dom.Basics.wire ('myDiv','mouseout',setDivDefaultClass);
Uize.Dom.Basics.wire ('myDiv','click',showYouClickedMeAlert);

Uize.Dom.Basics.unwire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

2.4.3. Wiring With Multiple Form, Unwiring With Single Form

Event handlers wired using the variation of the Uize.Dom.Basics.wire method that takes multiple event-name-to-handler mappings can be unwired using the variation of the Uize.Dom.Basics.unwire method that unwires a single event, as shown in the example below...

EXAMPLE

Uize.Dom.Basics.wire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

Uize.Dom.Basics.unwire ('myDiv','mouseover',setDivHoverClass);
Uize.Dom.Basics.unwire ('myDiv','mouseout',setDivDefaultClass);
Uize.Dom.Basics.unwire ('myDiv','click',showYouClickedMeAlert);

2.5. Partial Unwiring

When unwiring events that were wired using the variation of the Uize.Dom.Basics.wire method that takes multiple event-name-to-handler mappings, and using the variation of the Uize.Dom.Basics.unwire method that takes multiple event-name-to-handler mappings to unwire them, it is not necessary to unwire all of the events initially wired up.

EXAMPLE

Uize.Dom.Basics.wire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

Uize.Dom.Basics.unwire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass
  }
);

In the above example, we're wiring handlers for the mouseover, mouseout, and click events of the div with the id of "myDiv". Then, we're using the Uize.Dom.Basics.unwire method to unwire the handlers for just the mouseover and mouseout events. After the above code has been executed, our div will have no hover highlighting behavior, but clicking on it will pop up the JavaScript alert dialog.

2.5.1. Partial Unwiring, Using Single Form

When partially unwiring handlers for a DOM node, handlers can be unwired using the variation of the Uize.Dom.Basics.unwire method that unwires a single event - even if the event handler being unwired was originally wired using the variation of the Uize.Dom.Basics.wire method that takes multiple event-name-to-handler mappings.

Consider the following example...

EXAMPLE

Uize.Dom.Basics.wire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

Uize.Dom.Basics.unwire ('myDiv','click',showYouClickedMeAlert);

After the above code has been executed, our div will no longer pop up a JavaScript alert dialog when clicked, but it will still have the hover highlighting behavior.

2.6. Wiring Multiple Handlers for the Same Event

The Uize.Dom.Basics.wire method can be used to wire multiple handlers for the same event of the same DOM node.

2.6.1. Handlers Executed in Order of Wiring

It's worth noting that event handlers wired for the same event of the same DOM node are executed in the order in which they are wired.

EXAMPLE

Uize.Dom.Basics.wire ('myDiv','click',function () {alert ('Click Alert 1')});
Uize.Dom.Basics.wire ('myDiv','click',function () {alert ('Click Alert 2')});
Uize.Dom.Basics.wire ('myDiv','click',function () {alert ('Click Alert 3')});

In the above example, we're wiring three different event handlers to the click event of the div tag with the id of "myDiv". After the above code has been executed, clicking on our div will produce a succession of three alert dialogs, displaying the messages "Click Alert 1", "Click Alert 2", and then "Click Alert 3".

2.6.2. Unwiring and Rewiring Changes Handler Order

The order of execution of handlers wired for the same event of the same node will be disrupted if any of the handlers are unwired and then rewired.

EXAMPLE

function clickAlert1 () {alert ('Click Alert 1')}
function clickAlert2 () {alert ('Click Alert 2')}
function clickAlert3 () {alert ('Click Alert 3')}

Uize.Dom.Basics.wire ('myDiv','click',clickAlert1);
Uize.Dom.Basics.wire ('myDiv','click',clickAlert2);
Uize.Dom.Basics.wire ('myDiv','click',clickAlert3);

Uize.Dom.Basics.unwire ('myDiv','click',clickAlert2);
Uize.Dom.Basics.wire ('myDiv','click',clickAlert2);

In the above example, we have wired up three handlers to the click event of the div tag with the id of "myDiv". Clicking on the div would produce three nicely ordered alert dialog messages, except that we're unwiring and then rewiring the clickAlert2 handler. This will have the effect of putting the rewired handler at the end in the order, so clicking the div will produce a succession of three alert dialogs with the messages "Click Alert 1", "Click Alert 3", and then "Click Alert 2".

2.7. Unwiring All Handlers for the Same Event

The Uize.Dom.Basics.unwire method provides a convenient way to unwire all event handlers for the same event of the same DOM node, simply by not specifying any handler function parameter.

EXAMPLE

Uize.Dom.Basics.wire ('myDiv','click',function () {alert ('Click Alert 1')});
Uize.Dom.Basics.wire ('myDiv','click',function () {alert ('Click Alert 2')});
Uize.Dom.Basics.wire ('myDiv','click',function () {alert ('Click Alert 3')});

Uize.Dom.Basics.unwire ('myDiv','click');

In the above example, we have wired up three handlers to the click event of the div tag with the id of "myDiv". Clicking on the div would produce a succession of three alert dialog messages, except that we've called the Uize.Dom.Basics.unwire method, specifying 'myDiv' as the DOM node, 'click' as the event name, but not specifying any handler function. With this variation of the Uize.Dom.Basics.unwire, all handlers wired for the click event of the DOM node with the id of "myDiv" would be unwired.

2.8. Unwiring All Handlers for All Events of a DOM Node

The Uize.Dom.Basics.unwire method provides a convenient way to unwire all event handlers for all events of a DOM node, simply by not specifying the event name and handler function parameters.

EXAMPLE

Uize.Dom.Basics.wire (
  'myDiv',
  {
    mouseover:setDivHoverClass,
    mouseout:setDivDefaultClass,
    click:showYouClickedMeAlert
  }
);

Uize.Dom.Basics.unwire ('myDiv');

In the above example, we're wiring handlers for the mouseover, mouseout, and click events of the div with the id of "myDiv". Then, we're using the Uize.Dom.Basics.unwire method to unwire all handlers for all events of this node. After the above code has been executed, our div will have no hover highlighting behavior, and clicking on it will not pop up a JavaScript alert dialog.

2.9. Wiring Events for Multiple DOM Nodes

Just as the Uize.Dom.Basics.wire method makes wiring multiple events a snap, you can just as easily wire handlers for one or more events of multiple DOM nodes - in a single method call.

The Uize.Dom.Basics.wire method - along with many other methods in the Uize.Dom.Basics module - supports a concept called the node blob. Where a method might otherwise be used to apply an action to just a single node, a node blob can be used instead to apply that action to more than one node. A "blob" of nodes can be specified using an array of node IDs or node references, as shown in the example below...

EXAMPLE

Uize.Dom.Basics.wire (
  ['myDiv1','myDiv2','myDiv3'],
  {
    mouseover:function () {this.className = 'divHover'},
    mouseout:function () {this.className = 'divDefault'},
    click:function () {alert ('You Clicked ' + this.id)}
  }
);

In the above example, we have taken the example shown in the section Wiring Multiple Events and extended it so that the Uize.Dom.Basics.wire method is wiring multiple events of multiple DOM nodes. Here we're wiring the mouseover, mouseout, and click events for the div nodes with the IDs of "myDiv1", "myDiv2", and "myDiv3". We're using an array of node IDs in this case for our node blob. You'll notice that in the handler for the click event we're using the this keyword to get the value of the id property for the DOM node that fired the event, and we're using this value to form the message that shows in the alert dialog. So, for example, clicking the div with the id of "myDiv1" will pop up an alert dialog with the message "You Clicked myDiv1".

2.9.1. Wiring a Node Blob, Using Single Form

Of course, you can also use the node blob technique with the variation of the Uize.Dom.Basics.wire method that only wires a handler for a single event, as shown in the example below...

Uize.Dom.Basics.wire (
  ['myDiv1','myDiv2','myDiv3'],
  'click',
  function () {alert ('You Clicked ' + this.id)}
);

Here's we're only wiring the click event for our three DOM nodes.

2.10. Unwiring Events for Multiple DOM Nodes

Just as it's possible to wire handlers for multiple DOM nodes in a single method call by specifying a node blob in place of a single node (see Wiring Events for Multiple DOM Nodes), handlers wired to many DOM nodes can be unwired in a single method call with the Uize.Dom.Basics.unwire method.

EXAMPLE

var
  divIds = ['myDiv1','myDiv2','myDiv3'],
  divHandlers = {
    mouseover:function () {this.className = 'divHover'},
    mouseout:function () {this.className = 'divDefault'},
    click:function () {alert ('You Clicked Me!')}
  }
;

Uize.Dom.Basics.wire (divIds,divHandlers);
Uize.Dom.Basics.unwire (divIds,divHandlers);

After the above code has been executed, none of the event handler functions contained in the divHandlers event-name-to-handler mappings object will be wired to any of the div nodes contained in the divIds node blob.

2.11. Unwiring Events That Use the Same Handler

The Uize.Dom.Basics.wire method provides a way to unwire all events that are wired to a particular handler function in a single method call, by simply specifying the value undefined for the event name parameter.

EXAMPLE

function sayHi () {alert ('hi!')}

Uize.Dom.Basics.wire ('myDiv1','click',sayHi);
Uize.Dom.Basics.wire ('myDiv2','mouseover',sayHi);
Uize.Dom.Basics.wire (
  'myDiv3',
  {
    click:function () {alert ('You clicked me!')},
    mouseover:sayHi
  }
);

Uize.Dom.Basics.unwire (['myDiv1','myDiv2','myDiv3'],undefined,sayHi);

In the above example, handlers are being wired for events of the nodes with the IDs of "myDiv1", "myDiv2", and "myDiv3". Some of the events are wired to execute the handler function sayHi, which would pop up an alert dialog with the message "hi!". Using the Uize.Dom.Basics.unwire method, we are then unwiring all events of our three div nodes that are wired to the sayHi handler. We do this by specifying a reference to sayHi for the handler function parameter, but specifying the value undefined for the event name parameter. The undefined value effectively acts as wildcard value (i.e. any event name). After the above code has been executed, the only event wiring left standing will be the wiring of the click event of the div with the id of "myDiv3", so clicking on this node would produce an alert dialog with the message "You clicked me!".