<%response.buffer=true%> <% yere = year(date()) Response.Expires = 0 %> JavaScript Intro
<Events>
  spacerspacer

JS Events

An Event: An event is something that happens that warrants notice.  On a web page we mean page loads, keystrokes and mouse activities.  Older browsers were designed to respond to very few events on a web page.

As improvements were made in browsers, now many events can be handled or captured (identified and responded to) by JavaScript functions.

Event Handling/Capture: Reacting to the occurrence of a event is said to be 'capturing' it.  This capture only occurs if we specifically write a function to react to an event.  Just as browsers are different, these events are not always the same for each browser.  Calling a function an event handler implies it not only can 'capture' the event, but hopefully can manage the entire situation, hence the word 'handle'.

According to JS expert PPK events are the 'beating heart' of a JavaScript application.   Historically we capture these events and attach 'event handing' functions explictly:

onmouseover="rollover()"

This is the original Netscape model of accessing events.  The number of event handlers was limited, and many browsers mimicked the Netscape model. Early event handlers were few but included the click event of links and and the submit event of forms. 

Event Propogation: With the entry of the 'fours', meaning the advent of Netscape Version 4, and IE Version 4, in June and September of 1997 respectively, the real browser wars began.  Just as each browser was developing it's own (chiefly incompatible) prehistoric DOM, (DOM level 0) they also were creating incompatible event handling models.  Once a click event was declared for an element, what would you do if there was an element inside of that, also with a possible click event?  Which one was accessed, and it what order?  All of these rules needed to be sorted out programatically.

Event Capturing vs. Event Bubbling: Not surprisingly, Netscape and IE diverged greatly on how to handle sorting out which element get the 'click' when we have nested elements. Netscape opted for Event Capturing, which starts on the outer element, and works inward.  IE of course opted to start on from the inmost element, so that events are fired from the inside out, like a bubble moving out from the center, hence Event Bubbling.

By November 2000, we have a third event handling specification, the W3C DOM Event standard.  This version wisely implemented both the capturing, then bubbling, in that order:




Frequently, we just want this feature shut off, so that only the element actually assigned the event will respond:

(To shut off event propagation) In the Microsoft model you must set the event’s cancelBubble property to true.

window.event.cancelBubble = true;

In the W3C model you must call the event’s stopPropagation() method:

e.stopPropagation()

This stops all propagation of the event in the bubbling phase. Stopping event propagation in the capturing phase is impossible. One wonders why. For a complete cross-browser experience do:


function doSomething(e)
{
if (!e) var e = window.event;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}

Setting the cancelBubble property in browsers that don’t support it doesn’t hurt. The browser shrugs and creates the property. Of course it doesn’t actually cancel the bubbling, but the assignment itself is safe.

What is italicized above is from another article by PPK: Event Order

Note that this is not always what we want to do.  If we were to build our own drag & drop application (or perhaps to keep from interfering with one working on our page at that time) this could interfere with expected behavior, as event handlers are then placed in different places (like on the document itself) as a fallback to quirky behavior. 

Unobtrusive JavaScript: The term 'unobtrusive' JavaScript refers to the fact that we can wire to events by identifying and determining their occurence, and reacting to it.  We previously wired directly to the onload event of the body tag, but were able to do the same unobtrusively, by assigning a function directly to the load property of the window object:

window.onload = myFunction;

Note that we aren't using the parens () on the above, because we don't want the function to actually run when it is called.  We are just registering the name of the function, and associating it with the load event of the window object.  When the window actually loads, that function is called.  We created a workaround function named addOnload() which allowed us to attach multiple event handling functions to the window.onload event.

Anonymous Functions: When we want a function to be called at intervals in reaction to events, it helps to 'name' the function, so it can be called by name.  However, when we only need the function to run once, we can attach an anonymous function (no name given or necessary) to an event.  This can save ourselves some confusion, and free up resources:

window.onload = function(){
    //we can use an anonymous function, since the window only ever loads once
    //perform initialization code here
}


Registering An Event Handler: Since we are not going to assign events explicitly we'll need another means to attach to events.  We can register all events we wish to use during the window/body load/onload event.  We can't do this prior to the load event, because the DOM document is not done loading until that moment:

window.onload = function(){
    //we use an anonymous function to register the event handler
    document.getElementById("myDiv").onclick = imclicked; //function is registered to onclick event of myDiv
}


Here we've registered a function named imclicked() to a div with an id of "myDiv". 

Cross Browser Event Access: Just as we 'sniffed' browsers, or we determined DOM capabilities, we need a way to access events across multiple browsers.  We do this to determine who was just clicked, and then can apply code to respond to that DOM element.

Event Target: On this score, both the Netscape and DOM versions concur the target property of the event returns the current DOM element.  However in IE, its the srcElement property. 

Cross Browser Event Registration: Since events are the exact type of thing on which we suspect changes later, let's put a wrapper around our event handling code.

Let's view the function:

function imclicked(e) {
    var targ;
    if (!e) var e = window.event;
    if (e.target) targ = e.target;  //NN & DOM
    else if (e.srcElement) targ = e.srcElement;  //IE
    if (targ.nodeType == 3) targ = targ.parentNode; // defeat Safari bug

    currClass = targ.className; //old school way of getting classname, for IE
    if(currClass == "back1")
    {//toggle class/color here
        targ.className = "back2";
        
    }else{
        targ.className = "back1";
    }
}


View the demo here: clickDiv.htm

Registering Multiple Events:
we can expand the registration to add any number of elements, and assign the click event to each one:

window.onload = function(){
    //we use an anonymous function to register the event handler
    document.getElementById("myDiv").onclick = imclicked; //now we're registering 3 events
    document.getElementById("otherDiv").onclick = imclicked;
    document.getElementById("yetAnotherDiv").onclick = imclicked;
}


Now the same function is applied to multiple divs: clickDivs.htm

Registering A Range of Elements:
We can also assign a function to a range of elements.  Here we identify a div, then grab all div's inside it, with getElementsByTagName():

window.onload = function(){
    theDiv = document.getElementById("myDiv"); //get a div via the ID - can't name JS var same as ID!
    aDiv = theDiv.getElementsByTagName("div"); //return an array of divs internal to 'myDiv'
    for(x=0;x<aDiv.length;x++)
    {//apply the function to all divs in the array
        aDiv[x].onclick = imclicked;
    }
}


Then we loop through the array of divs, and apply one function to the onclick event of each.  The advantage here is we don't need to identify any of the internal divs, and any number of new divs can be added, and all will get the same treatment: clickRange.htm

Determining a Target on click: Besides registering specific functions to events on page load, we can also determine which element is being clicked on the fly.  Here's an example from the JavaScript & AJAX 7th ed. book, at the end of chapter 3: Web 2.0 Bingo

In this example, identification of the target of the click is handled with the following code:

if(evt){

      var thisSquare = evt.target;

}else{//I'm IE!!
     var thisSquare = window.event.srcElement;
}

In the else above is the IE way of determining which element is being clicked.  View the similarities (and differences) between this event determination code.  It's less effective because it doesn't accommodate the Safari bug.  However, in this way we don't need to register each and every event, just the one that actually happens!  Here's the code that changes the color:

if(thisSquare.className == ""){
     thisSquare.className = "pickedBG";
}else{

     thisSquare.className = "";
}


In which the class is changed to the colored background, pickedBG, or if clicked again, changed back to a blank background.   See page 69 of JavaScript & AJAX for the web, 7th Ed. for more details.

Capturing Keystrokes: We can also capture the keystroke combinations of the users.  Here are a couple of examples from Stuart Landridge's DHTMLUtopia: Key Code Detect and Portable Detect

Event Listeners: There are times you may want to register multiple functions to a single event.  There may also be times you wish to add or remove events during the processing of a page.  Event Listeners allow these capabilities.  To add an event listener in every browser except for IE you could do this:

document.getElementById("myLink").addEventListener("click",imclicked,false);

To do the same for IE:

document.getElementById("myLink").attachEvent("onclick",imclicked);

The differences are highlighted above. Note that IE uses a different means to attach the event, attachEvent instead of addEventListener.  Further IE uses the DOM level 0 event handler name, onclick instead of click.

The false in the W3C model refers to capture or bubble phase.  False refers to the bubble phase, which is the only phase supported by IE, so it's the one we would normally use.


Cross Browser Event Listeners: Since we see that IE (and potentially other browsers) again present differences in handling Event Listeners, we'll want to have a wrapper function to allow us to attach event listeners:
 
// Cross-browser implementation of element.addEventListener()
 
function listen(evnt, elem, func) {
    if (elem.addEventListener)  // W3C DOM
        elem.addEventListener(evnt,func,false);
    else if (elem.attachEvent) { // IE DOM
         var r = elem.attachEvent("on"+evnt, func);
return r;
    }
    else window.alert('I\'m sorry Dave, I\'m afraid I can\'t do that.');
}
 
// Use: listen("event name", elem, func);
 
JS Anthology Examples: Here are a couple of examples of event handlers at work: Sort Tables and Enterprise Tooltip 
 

DOM Events: Here's a list of DOM events to which we can attach functions. Here's some more on Event Listeners: How To Create DOM Events

 
More?: A great place to start on advanced event handling at PPK on Events  

Enter the APIs: When you combine the browser differences regarding the DOM and events, it's no wonder there have been several JS APIs designed to alleviate all the inconsistencies.  It's for this reason we'll be focusing on jQuery, which is widely used and does a great job of allowing us to trade the browser differences for an entirely new syntax!

 

   
Print this Page Back To Top

2000- <%=yere%> newMANIC INC, All rights reserved