DHTML Lab: Hierarchical Menus, I; onLoad | WebReference

DHTML Lab: Hierarchical Menus, I; onLoad


Logo

DHTML Hierarchical Menus, Part I
menu creation and setup

Webreference

Contents

Open the menus above to remind yourself that this is a technique worth learning.

Most of the routines we have discussed in these columns have been linear. That is, a function is called. When it terminates, it calls another, and so on. The present menu routines are more complex. Functions call other functions, which call other functions, branching out in several directions, before they execute their statements and terminate.

This type of structure is also the most difficult to describe. To assist us in explaining the routines to follow, we have decided to use long English-like property and method names. Most functions will be declared as methods of objects, instead of having objects passed as arguments.

This approach was used briefly in the Puzzle series, when we defined a showIt method for elements to control their visibility. A quick refresher for creating property methods follows, using showIt as an example:

We need a function that when called will change the visibility of an object. It may defined as:

function showIt(elementReference,toggleBoolean) {
 if (toggleBoolean) {
  element.visibility = "show";
 }
 else {
  element.visibility = "hide";
 }
}

or

function showIt(elementReference,toggleBoolean) {
 element.visibility = (toggleBoolean) ? "show" : "hide";
}

In either case, we show an element by calling the function in this way, (using elMenu1 as the element to show):

showIt(elMenu1,true);

To hide an element, we use this syntax:

showIt(elMenu1,false);

Conversely, we may create a function called showIt() that may be assigned to an object as a method of that object. We'll use elMenu1 as the example element:

function showIt(toggleBoolean) {
 this.visibility = (toggleBoolean) ? "show" : "hide";
}
elMenu1.showIt = showIt;

To show elMenu1, we use the following statement:

elMenu1.showIt(true);

In our function, the this keyword refers to the object that showIt is a method of. Any positioned element object can have a showIt method that toggles its visibility. In the same way, we may create longer functions, with more complex statements, that may be assigned as an object method, executing the statements on the object when the method is called.

The Top Level Menus

The first function to be called, makeTop(), is responsible for creating, or initiating the creation of, all the menus for our page. As with our other functions, we will discuss it one statement at a time. Since it calls other functions that will be discussed further on, it would be a good idea to refer back to it as we progress to fully understand the function hierarchy.

When makeTop() is called, it first displays a message in the browser status bar alerting the user to the menu creation in progress. This is a courtesy to the user who will notice some activity after the page loads.

function makeTop() {
 status = "Creating Hierarchical Menus";
 while(eval("window.arMenu" + topCount)) {
  topArray = eval("arMenu" + topCount);
  topName = "elMenu" + topCount;
  topMenu = makeElement(topName);
  topMenu.setup = menuSetup;
  topItemCount = 0;
  for (i=0; i<topArray.length; i+=3) {
   topItemCount++;
   topItemName = "item" + topCount + "_" + topItemCount;
   topItem = makeElement(topItemName,topMenu);
   if (topItemCount>1)
    topItem.prevItem = (keep with next)
      eval("item" + topCount + "_" +(topItemCount-1));
   topItem.setup = itemSetup;
   topItem.setup(i,topArray);
   if (topItem.hasMore) makeSecond();
  }
      
  topMenu.setup(false,topItem);
  topCount++
 }
 status = "Menus Created"
 areCreated = true;
}

The body of makeTop() is a while loop. The control statement for the loop is:

    while(eval("window.arMenu" + topCount))

By evaluating window.arMenu with an incrementing topCount, the statement checks for the existence of arMenu1, arMenu2, arMenu3, and so on. These are the arrays we have previously defined for our top level menus. As long as it finds such an array defined, the statements within the while loop will be executed. Otherwise the statements following the loop will be executed.

If a usuable array is found, it is assigned to the topArray variable, for easy reference:

      topArray = eval("arMenu" + topCount);

Our top level menus will have be identified as elMenu1, elMenu2, etc. We first create a string (topName) using the elMenu prefix and the top level menu count (topCount):

      topName = "elMenu" + topCount;

We then actually create the menu element by calling the makeElement() function, passing the name string as an argument. makeElement() will, as we'll see further on, return a value representing the menu element. This element reference we assign to topMenu, an in-function temporary identifier for the menu-being-created.

      topMenu = makeElement(topName);

A menu has many properties and methods. Since all menus have the same properties and methods, they are assigned to the menus in a function called menuSetup(). We assign this function to a method of topMenu called setup. Now, whenever we are ready to set up the menu, we can issue the statement: menuReference.setup().

      topMenu.setup = menuSetup;

We have established a top level menu, created identifiers for it, and defined a method that will complete the creation of it. Now, we can turn to the items the menu contains. First, a counter is initialized so we can keep track of the total items created.

      topItemCount = 0;

A for loop will move us through the menu array. Notice that in the for control statement, the incrementation of the i counter is by 3. Most often we see for loops incremented by 1. The 3 is used because our arrays have three elements that pertain to each item, as you recall, the display text, the link URL and the have-child Boolean.

 for (i=0; i<topArray.length; i+=3) {

Our item counter is incremented. The first time through it becomes 1.

  topItemCount++;

As we did with the menu, we give the item a string identifier, prefixing it with item, adding the menu count, then an underscore separator, then the item count. Therefore, the first item in the first menu, will have the identifier item1_1, the second, item1_2, and so on:

  topItemName = "item" + topCount + "_" + topItemCount;

The makeElement() function is called again, this time with two arguments. The string identifier, as before, and the identifier for the containing menu. makeElement() will return a reference for the item which we assign to topItem, for use within the function.

  topItem = makeElement(topItemName,topMenu);

Every item, except the first, will have an item just before it. We need a reference for this previous item to use in positioning later. We know that the previous item has an identifier with a suffix one integer less than the present item. For example, the item previous to item1_4 is item1_3. If applicable, we assign the previous item to the prevItem property of the present item:

         if (topItemCount>1)
    topItem.prevItem =  (keep with next)
eval("item" + topCount + "_" +(topItemCount-1));

There is a lot more setting up to do for each item, but because it is common to all items, we assign a function called itemSetup() to the setup method of the item. We then immediately call the setup method, passing two parameters: the array pointer (i) and the array reference (topArray).

         topItem.setup = itemSetup;
         topItem.setup(i,topArray);

When we return from setting up the item, we will have created a property called hasMore. This property stores a Boolean value that denotes whether the item has a child menu associated with it. If it does, the makeSecond() function is called to create the child menu associated with the item:

         if (topItem.hasMore) makeSecond();

When we return from creating any child menu, the for loop repeats, and continues repeating until there are no more items defined in the array. With the item creation complete, the setup method of the menu is called passing two arguments: a Boolean that specifies whether the menu has a parent menu (false for top level menus) and the last item that was created (topItem). After menu setup, the top level menu count is incremented and the while loop repeats. When all top level menus are created, the browser status bar displays another courtesy message, and the global areCreated variable becomes true. The menus are ready for use.

      }
      
      topMenu.setup(false,topItem);
      topCount++
   }
   status = "Menus Created"
   areCreated = true;

In Plain English

This one function controls the creation of all our menus and items. All other functions involved in the creation process, are called directly or indirectly by this controlling function. We will of course look at all of these in detail, but for now let's recap the logic of makeTop(), in plain English:

  1. Tell the user menu creation is in progress
  2. Search the array list for top level menu arrays. For each one found:
    1. Create a positioned element for the menu with an incrementing identifier of the form: elMenu1, elMenu2...
    2. Declare where the remainder of the setup routines for the menu are located.
    3. Go through the array creating the individual items:
      1. Create a positioned element for each item with an identifier of the form: item1-1, item1_2...
      2. Run the item setup routines.
      3. Create a child menu for the item, if called for, and go on to the next item.
    4. Complete the menu setup now that all items are created, and go on to the next menu.
  3. When all menus are done, alert the user, and allow access.

Now, let's look at the functions called by makeTop() in sequence.


Produced by Peter Belesis and

All Rights Reserved. Legal Notices.
Created: Feb. 19, 1998
Revised: Feb. 19, 1998

URL: http://www.webreference.com/dhtml/column14/menuLoad.html