Also beware that legacy IE does not pass an event that way, only "modern" browsers as well as IE9/later do. You want legacy support for JScript (IE's flavor of JS that's different for a whole host of stupid legal reasons) you need to access window.event instead. Likewise there's event.target in JavaScript browsers that legacy IE lacks, and is instead on window.event.srcElement.
An easy way to do this is to have your function handler be:
Code:
function callback(e) {
e = e || window.event;
if (!e.target) e.target = e.srcElement;
}
Now it will work in all flavors of browsers all the way back to IE 5. I usually have a function dedicated to normalizing "e" that way, as well as having an option for letting me cancel the event's bubbling and propagation... this means if you trap something like an anchor that has a href on it for scripting off behavior (something you should have before you even have a line of JS involved) you can cancel the normal event behavior. (like the browser actually following that href)
Code:
function eventProcess(e, prevent) {
/*
ACCEPTS
e - the event if present passed to the callback function
prevent -- boolean, prevent further event handlers from firing
RETURNS
normalized cross browser event
*/
e = e || window.event;
if (!e.target) e.target = e.srcElement;
if (prevent) {
// this MAY be overkill... Oh, who are we kidding, it is!
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
e.returnValue = false;
}
return e;
}
You can then inside your callback function just call:
Code:
function callback(e) {
e = eventProcess(e);
... and now E will work as expected across all JS supporting browsers past and present.
It's also NOT a good idea to directly access .onclick unless you just created the element on the DOM yourself with document.createElement as you have NO idea if other scripts on the page are also (or have already) attached themselves to the element. While it's important to know that onclick exists, you should really be chaining the event onto the element instead... Sadly doing so is also inconsistent between "modern browsers" and legacy IE, so you need a helper function for that too so you can test for attachEvent (IE10/earlier) or addEventListener (everything else).
Code:
function eventAdd(e, eventName, callback) {
/*
ACCEPTS
e - element to add event handler to
eventName - name of the event to trap (click, mouseover, etc)
callback - function to be called when the event happens
RETURNS
nothing
*/
if (e.addEventListener) e.addEventListener(eventName, callback, false);
else e.attachEvent('on' + eventName, callback);
}
Either way that double-function "return a function" for nothing is gibberish, as idx doesn't exist and I wouldn't be passed... it's also bad practice to use "anonymous functions" -- aka the function declaration as a variable assignment -- when the same thing is being assigned more than once. It increases the overhead and parsing time as new instances of that function are uniquely created each and every time. That callback function should be created BEFORE the loop and then passed to eventAdd inside the loop.
Likewise the var declaration before the loop would be slower and more code than declaring it on the loop, as does looking up the object property on "nodes" of "length" every loop...
Assuming I'm following the intent of the original code, it should probably look something more like this:
Code:
// When you click on a node, an alert box will display the ordinal of the node.
function eventProcess(e, prevent) {
/*
ACCEPTS:
e - the event if present passed to the callback function
prevent -- boolean, prevent further event handlers from firing
RETURNS:
normalized cross browser event
*/
e = e || window.event;
if (!e.target) e.target = e.srcElement;
if (prevent) {
// this MAY be overkill... Oh, who are we kidding, it is!
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
if (e.preventDefault) e.preventDefault();
e.returnValue = false;
}
return e;
}
function eventAdd(e, eventName, callback) {
/*
ACCEPTS
e - element to add event handler to
eventName - name of the event to trap (click, mouseover, etc)
callback - function to be called when the event happens
RETURNS
nothing
*/
if (e.addEventListener) e.addEventListener(eventName, callback, false);
else e.attachEvent('on' + eventName, callback);
}
function nodeHandler(e) {
e = eventProcess(e);
alert("event : " + e + "\n\n came from " + e.target);
}
function addTheHandlers(nodes) {
for (var i = 0, iLen = nodes.length; i < iLen; i += 1)
eventAdd(nodes[i], 'click', nodeHandler);
}
Knowing about the target attribute is damned handy as it gives you what element actually sent you the event - which is often what you want your scripting to process, and is a place where you can store values unique to the event using data- attributes so you don't end up trying to screw around with globals.
Oh, and it's generally sloppy to use underscores instead of camelCase -- JS does have a naming convention for function, method, variables, and objects after all. That's not so much of a geniune bug or screwup, as it is a good practice. Wait 'till you get into languages like PHP where even their own function library doesn't follow the language's own alleged naming conventions as it's a hodge-podge from different languages. Real hair puller.
I realize that being a book example, they probably tried to dumb it down a bit for you removing things like the cross-browser woes... but these are things you should probably be aware of from the start as they will bite you in the backside sooner than later.