Main Points
- Unobtrusive Javascript Example 10 Condensing the obscene amount of event handlers.
- Rewriting the Display Code The condensed event handlers don't use parameters so we had to rewrite the code to turn the menus on and off.
- Skip to Main Points links return to the Main Points menu.
Unobtrusive Javascript Example 10
The abundance of event handlers in the navbar section of the .js file is simply ridiculous. And the horrible thing is there are other things we will have to do the same way if we can't find a way around it. Originally, there were 40 event handlers that looked like this.
Each handler had to pass details about itself by using parameters. It was recommended that we eliminate the parameters and instead use this.id inside the called function. While this expanded the scope of the project to rewriting the driveMenu() function, it eliminated half the line length and we did ultimately develop the code along those lines. For more info check out our section below on this.id. For now just note that we were able to condense function() {driveMenu("specific", 5, "off")} into MenuOff. Here's the rest of the code for the event handlers, basically there are three nested loops which cycle through all the different variations of the element ids that the Javascript needs to control.
function navbarEvents() {
var arrNavElement = new Array("Button", "Menu");
var intNumberOfNavElements = 5;
for (var i = 0; i <= 1; i++) {
for (var j = 0; j <= 1; j++) {
for (var k = 1; k <= intNumberOfNavElements; k++) {
var strNavElementId = arrNavbars[i] + arrNavElement[j] + k;
document.getElementById(strNavElementId).onmouseover = MenuOn;
document.getElementById(strNavElementId).onmouseout = MenuOff;
The first thing you'll notice is that we declare the function name, and define several variables. We define two arrays which contain the strings which differentiate the ids of the navbar elements. "specific" and "siteWide" are the two strings used to name elements of the section specific and site wide navbars. Since we observed this naming convention, it is easy for the Javascript to take advantage of it. The other array cycles contains the "Button" and "Menu" strings, taking advantage of naming conventions once again. The final variable intNumberOfNavElements was one of the last changes added. It is not strictly necessary, the number five could have been left hard coded in the final for loop. However, using it makes it easy to adjust the Javascript to navbars with different numbers of buttons. We could have 50 different navbuttons on a webpage and this script can manage them all simply by changing this variable. That's it. It makes the script tremendously portable to other websites using the same style of navigation.
for (var i = 0; i <= 1; i++) {
for (var j = 0; j <= 1; j++) {
for (var k = 1; k <= intNumberOfNavElements; k++) {
The next section is the three nested loops. These were throwing all kinds of errors when I added the second loop. I was quite worried that nested loops weren't going to work the way I had hoped. Fortunately, I went debugging with alerts and quickly realized that I had written for (var j = 1; j <= 2; j++). Then I realized that I was feeding 1 & 2 into an array, and arrays start at index 0. Once I changed the conditions to for (var j = 0; j <= 1; j++), it worked fine. The first two for loops cycle through two options which will be tied in later to the arrays to grab the appropriate strings needed to write each id. The final loop cycles through each set of navbar elements (a button and a menu), however many there are. In this case, intNumberOfNavElements is five.
Finally we've reached the interior, the last section. The first line is a little unexpected. Like including intNumberOfNavElements, this was one of the last parts written for the function. The function call k = twoDigitString(k); makes sure that there are two digits in the value of k. Before making this change we were hard coding the number zero before k. This is because all our div ids are written 01, 02, etc. That way if there are more than 10, they still fall into numerical order when ordered alphabetically by a computer. By calling twoDigitString, the script automatically adds a zero to a single digit number but leaves double digit numbers alone. This is necessary anytime intNumberOfNavElements is set to 10 or more; not necessary for our code, but it does make the results easily portable to a website with a large navbar.
var strNavElementId = arrNavbars[i] + arrNavElement[j] + k;
document.getElementById(strNavElementId).onmouseover = MenuOn;
document.getElementById(strNavElementId).onmouseout = MenuOff;
The guts of the loop are fairly self-explanatory. The results of each loop are used to construct the id of one element of the navbars, each id is then stored in the variable, strNavElementId. strNavElementId is then passed into two event handlers, writing the conditions on which it should turn a menu on or off.
Skip to Main PointsRewriting the Display Code
Since getting the above code to work involved nixing all the parameters, we had to go back to the drawing board again. That's why the hint to use this.id was critical to trying this method, because I had not found a stable way to pass that information into the menu control function without parameters. Fortunately this.id fit the bill perfectly. If there were a way to pass on the information about the event that triggered it, I would not even need two functions, but I haven't figured out how to do that yet. Perhaps in the future, but for now MenuOn() and MenuOff work fine. MenuOn() is quite self explanatory.
var myElement = this.id;
var myId = myElement.substring(myElement.length - 2, myElement.length);
var myNavbar = myElement.substring(0, 8);
var myMenu = myNavbar + "Menu" + myId;
document.getElementById(myMenu).style.display="block";
First, the function sets a collection of necessary variables. The id of the navbar element which called the function is stored as a variable using this.id. Substring methods can then be used to pull the suffix id and the navbar prefix to figure out exactly which menu should be turned on. Finally, myMenu is defined by adding all the pieces of the id of the menu. Finally we use myMenu to reset the menus display to block so that it turns on.
Conveniently, MenuOff() uses the exact same code, except for the final line which turns the menu off. document.getElementById(myMenu).style.display="none";. While this makes the code repetitive, there were a couple bumps trying to condense it. Given that we were only going to save a couple lines, we gave up on the endeavor quickly. The adjustments we'd already made knocked 2k off the script's file size, and it was clear we weren't going to get much better than that.
Skip to Main Points