Javascript to toggle visibility of Menu and anchored Divs

Hello all,

The solution to my problem is most likely very simple, but I’m a js newby and am struggling to get it to work. I have a basic menu that points to a number of divs on the same page, the idea being that I want users to navigate the contents without leaving the page. To ensure graceful degradation, the default state of both the menu and the respective divs is “display:block”, so the page functions as a normal page with anchors if the browser doesn’t support js. This is an abbreviated version of my HTML:

<div id="menu_container">
    <ul>
       <li id="anchor_1" class="menu_items">
          <a href="#content_block_1">Menu Item 1</a>
       </li>
       <li id="anchor_2" class="menu_items">
          <a href="#content_block_2">Menu Item 2</a>
       </li>
       [etc.]
    </ul>
</div>

<div id="content_block_1" name="content_block_1" class="content_blocks">
content....
</div>

<div id="content_block_2" name="content_block_2" class="content_blocks">
content....
</div>

[etc...]

And my CSS:

#menu_container{
    display:block;
}

.content_blocks{
    display:block;
}

My first question, which is unrelated to js, relates to the use of anchors. The books tell me that I need to use the name attribute as I’ve done above. However, I’ve noticed that my anchors also seem to work if I point to an id with my href (I know my ids and names are the same in the example, but the anchors work even if I omit the name attributes completely). Is that a new thing in modern browsers or am I missing something?

Now for my js:

// First I define a function to change the default state by
// turning off the visibility of everything except the menu

function initDispState(elmsOff, elmsOn){
	if(!document.getElementById){
		return;
	}
	else {
		for(i=0, len=elmsOff.length; i < len; i++) {
			elmsOff[i].style.display = "none";
		}
		for(i=0, len=elmsOn.length; i < len; i++) {
			elmsOn[i].style.display = "block";
		}
	}
}

// Next my clickhandler
function addClickHandler(menuContainer, menuItems, contentBlocks){
	for (i = 0, len=MenuItems.length; i < len; i++){
		MenuItems[i].onclick = dispToggle(menuContainer, contentBlocks[i]);
	}
	for (j = 0, len=contentBlocks.length; j < len; j++){
		contentBlocks[j].onclick = dispToggle(contentBlocks[j], menuContainer);
	}

}

function dispToggle(elmOff, elmOn){
	elmOff.style.display = "none";
	elmOn.style.display = "block";
}

// Now I call my functions
window.onload = function(){
   var menuContainer = document.getElementById("menu_container");
   var menuItems = Menu.getElementsByTagName("a");
   var contentBlocks= [document.getElementById("content_block_1"), document.getElementById("content_block_1"), etc...]

   initDispState(menuContainer, contentBlocks);
   addClickHandler(menuContainer, menuItems, contentBlocks);
}

My first function, initDispState, works fine on its own, but when I add the call to the addClickHandler function, the whole page goes wonky (my initDispState seems to work in reverse, i.e. menu is invisible and all the contentBlocks are visible) and I get an error in FF saying “elmOn is undefined”. This happens when the page loads, i.e. I don’t even get the point where I can click a menu item.

Any help will be much appreciated!

Art

Hi again,

I’ve made some progress with my js, but am still encountering an error. This is what my js looks like now:

// First I define a function to change the default state by
// turning off the visibility of everything except the menu

function initDispState(elmsOff, elmsOn){
	if(!document.getElementById){
		return;
	}
	else {
		for(i=0, len=elmsOff.length; i < len; i++) {
			elmsOff[i].style.display = "none";
		}
		for(i=0, len=elmsOn.length; i < len; i++) {
			elmsOn[i].style.display = "block";
		}
	}
}

// Next my clickhandler
function addClickHandler(menuContainer, menuItems, contentBlocks){
	for (i = 0, len=menuItems.length; i < len; i++){
	     menuItems[i].onclick = function(evt){
                   if(menuContainer.style.display == "block"){
                       menuContainer.style.display = "none";
                       contentBlocks[i].style.display = "block";
                   }
                   else{
                       menuContainer.style.display = "block";
                       contentBlocks[i].style.display = "none";
                   }
              }
	}
	for (j = 0, len=contentBlocks.length; j < len; j++){
	     contentBlocks[j].onclick = function(evt){
                   if(contentBlocks[j].style.display == "block"){
                       contentBlocks[j].style.display = "none";
                       menuContainer.style.display = "block";
                   }
                   else{
                       contentBlocks[j].style.display = "block";
                       menuContainer.style.display = "none";
                   }
              }
       }
}

// Now I call my functions
window.onload = function(){
   var menuContainer = document.getElementById("menu_container");
   var menuItems = Menu.getElementsByTagName("a");
   var contentBlocks= [document.getElementById("content_block_1"), document.getElementById("content_block_1"), etc...];

   initDispState(menuContainer, contentBlocks);
   addClickHandler(menuContainer, menuItems, contentBlocks);
}

The page loads fine without an error, but when I click on a menu item, I get a js error saying “[i] is undefined”, which means that [j] will likely also be undefined if the script would execute that far. I’m guessing that the problem is that my click event doesn’t pass the array index number of the menuItem clicked to [i]. If I remove the line, “contentBlocks[i].style.display = ‘block’”, from the first part of my addClickHandler function the script executes correctly to that point, i.e. it hides the menu when I click on a menu item. But if I add the line back in, it doesn’t work at all. So, I’m guessing that because [i] is undefined, the script can’t tell which contentBlock to toggle in response to the menu click.

Once again, any help will be greatly appreciated!

Art