SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Zealot
    Join Date
    Oct 2006
    Posts
    153
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Why can't I get class looping to work as well as getElementById?

    Hi
    I wished to create a project where I would have pictures of classic cars like the model T. and Stanley steamer with drop-down menus beneath them linking to stories about them on the Web. These pictures would be in separate div tags in the menus beneath them with their code not be in semantically related HTML. Another works these drop downs would be completely separate from each other. So I went looking for some good drop-down menu code on the Web and I thought I found it in keyboard accessible sucker fish drop downs. However the code used in ID attribute on the top-level unordered list tag in my project would have to use classes instead because I did not wish to read duplicate my JavaScript code attaching it to every ID of a separate drop-down menu. So I went looking for how to use classes instead of IDs in this code.

    I thought I found a way of using classes instead of IDs when I found on the web the article about a JavaScript function called "The Ultimate getElementsByClassName." what this function would do for me was to deliver me an array of all the elements classed with a certain class. I could then create a loop that would loop through my code attaching it to all unordered list tags classed with the requisite Nav class tag for the drop-down code to work. So at first I try to do this with the somewhat complicated drop-down code of thekeyboard accessible sucker fish drop downs. However this was a little confusing to me so I instead try to figure it out with this simpler "Son of Suckerfish Dropdowns" code.

    Were I am now is I can use a class instead of an ID if I explicitly code the JavaScript to pick up the first member of the class array. However if I loop through my code as is my plan it doesn't work. What follows is, my proof of principle, code with the offending code commented out and the class array member number change from a J variable to an explicit zero. Can someone tell me how to undo commented out code and get the loop to work. Any help would be greatly appreciated.

    Sincerely
    Marc

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html>
    <head>
    	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    	<title>Classes Son Sucker fish Single-level no loop</title>	
    <script type="text/javascript" charset="utf-8">
    function getElementsByClassName(oElm, strTagName, strClassName){
    /*
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com	
    */
    	var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    	var arrReturnElements = new Array();
    	strClassName = strClassName.replace(/-/g, "\-");
    	var oRegExp = new RegExp("(^|\s)" + strClassName + "(\s|$)");
    	var oElement;
    	for(var i=0; i<arrElements.length; i++){
    		oElement = arrElements[i];
    		if(oRegExp.test(oElement.className)){
    			arrReturnElements.push(oElement);
    		}
    	}
    	return (arrReturnElements)
    }	
    //for(var j=0;j<arrClassedNav.length;j++)
    //{
    		sfHover = function() {
    			var sfEls = arrClassedNav[0].getElementsByTagName("LI");
    			for (var i=0; i<sfEls.length; i++) {
    				sfEls[i].onmouseover=function() {
    					this.className+=" sfhover";
    				}
    				sfEls[i].onmouseout=function() {
    					    this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
    				}
    			}
    		}
    //}
    window.onload=function(){
    document	
    arrClassedNav = getElementsByClassName(document, "ul", "nav");	
    if (window.attachEvent) window.attachEvent("onload", sfHover);	
    }
    </script>	
    <style type="text/css" media="screen">
    .nav, .nav ul {
    	padding: 0;
    	margin: 0;
    	list-style: none;
    }
    
    .nav a {
    	display: block;
    	width: 10em;
    	}
    
    .nav li {
    	float: left;
    	width: 10em;
    	}
    
    .nav li ul {
    	position: absolute;;
    	width: 10em;
    	left: -999em;
    }
    
    .nav li:hover ul, .nav li.sfhover ul {
    	left:auto;
    	}
    </style>
    </head>
    
    <body>
    <ul class="nav">
    	<li><a href="#">Percoidei</a>
    		<ul>
    			<li><a href="#">Remoras</a></li>
    			<li><a href="#">Tilefishes</a></li>
    			<li><a href="#">Bluefishes</a></li>
    			<li><a href="#">Tigerfishes</a></li>
    		</ul>
    	</li>
    
    	<li><a href="#">Anabantoidei</a>
    		<ul>
    			<li><a href="#">Climbing perches</a></li>
    			<li><a href="#">Labyrinthfishes</a></li>
    			<li><a href="#">Kissing gouramis</a></li>
    			<li><a href="#">Pike-heads</a></li>
    			<li><a href="#">Giant gouramis</a></li>
    		</ul>
    	</li>
    </ul>
    	
    <div style="clear:both;"><br /><br ><br /></div>
    <!------second dropdowns group begins here-------->
    
    <!--
    <ul class="nav">
    	<li><a href="#">Percoidei</a>
    		<ul>
    			<li><a href="#">Remoras</a></li>
    			<li><a href="#">Tilefishes</a></li>
    			<li><a href="#">Bluefishes</a></li>
    			<li><a href="#">Tigerfishes</a></li>
    		</ul>
    	</li>
    
    	<li><a href="#">Anabantoidei</a>
    		<ul>
    			<li><a href="#">Climbing perches</a></li>
    			<li><a href="#">Labyrinthfishes</a></li>
    			<li><a href="#">Kissing gouramis</a></li>
    			<li><a href="#">Pike-heads</a></li>
    			<li><a href="#">Giant gouramis</a></li>
    		</ul>
    	</li>
    </ul>
    -->
    </body>
    
    </html>

  2. #2
    CSS & JS/DOM Adept bronze trophy
    Join Date
    Mar 2005
    Location
    USA
    Posts
    5,482
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You've overcomplicated it. Basically, all you needed was to add the function call to getElementsByClassName() inside the sfHover() and then add an extra for loop around the rest.

    Try this.
    Code:
    sfHover = function() {
      var sfEls, lists = getElementsByClassName(document, "ul", "nav");
      for(var k=0;k<lists.length;k++){
        sfEls = lists[k].getElementsByTagName("LI");
        for(var i=0; i<sfEls.length; i++){
          sfEls[i].onmouseover=function(){
            this.className+=" sfhover";
          }
          sfEls[i].onmouseout=function(){
            this.className=this.className.replace(new RegExp(" sfhover\\b"),"");
          }
        }
      }
    }
    if(window.attachEvent) window.attachEvent("onload", sfHover);
    We miss you, Dan Schulz.
    Learn CSS. | X/HTML Validator | CSS validator
    Dynamic Site Solutions
    Code for Firefox, Chrome, Safari, & Opera, then add fixes for IE, not vice versa.

  3. #3
    SitePoint Zealot
    Join Date
    Oct 2006
    Posts
    153
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks
    the code you gave me works! It does seem to have a better program flow than mine. But I am failing to understand what is wrong with mine and why it doesn't work? I have tried setting a breakpoint both in the inner loop of your code in mine. And I am failing to get a readout on the two counting variables. This is confusing me. I am using the Aptana debugger. So your code is very good and thanks. But I sure would like to understand what's going on better.

  4. #4
    CSS & JS/DOM Adept bronze trophy
    Join Date
    Mar 2005
    Location
    USA
    Posts
    5,482
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Your code didn't make sense. Putting a for loop around a function definition like that serves no purpose.

    Also, unless you modify the function to take an argument so that you call it for each list, you need to find all of the lists inside the function and then loop through them.
    We miss you, Dan Schulz.
    Learn CSS. | X/HTML Validator | CSS validator
    Dynamic Site Solutions
    Code for Firefox, Chrome, Safari, & Opera, then add fixes for IE, not vice versa.

  5. #5
    SitePoint Enthusiast
    Join Date
    Feb 2004
    Location
    Third Stone From The Sun
    Posts
    82
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I have no idea about model t or stanley steamer.

    For events, use bubbling. It's more efficient.
    Code:
    function hoverSF( ev ) {
     // We only care about LI elements.
      if( ev.target.tagName.toUpperCase() != "LI" ) return;
    // if it already has the class, exit.
      if( hasClass( ev.target, "hoversf" ) ) return;
      addClass( ev.target, "hoversf" );
    }
    function unhoverSF( ev ) {
      if( ev.target.tagName.toUpperCase() != "LI" ) return;
      removeClass( ev.target, "hoversf" );
    }
    function loadHandler () {
      var container = document.getElementById( "nav" );
      addListener( container, "mouseover", hoverSF );
      addListener( container, "mouseout", unhoverSF );
    }

    The example assumes:
    1) addListener function
    2) hasClass function
    3) removeClass function
    4) addClass function


    It's way more efficient to add only 1 listener to the nav. If you have multiple navs, use an object and encapsulate that.

    HTH.
    Last edited by DHTML Kitchen; May 10, 2007 at 23:30. Reason: code tag in wrong place
    My outdated site is down for a while now.

  6. #6
    SitePoint Zealot
    Join Date
    Oct 2006
    Posts
    153
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK thanks
    that makes sense I do not want to declare the function several times.

  7. #7
    CSS & JS/DOM Adept bronze trophy
    Join Date
    Mar 2005
    Location
    USA
    Posts
    5,482
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It also assumes that addListener() will give window.event as an argument to the function in IE. Many functions that are used to attach event handlers don't do that. Also what about srcElement? How would it's value get copied to the target property in IE?
    We miss you, Dan Schulz.
    Learn CSS. | X/HTML Validator | CSS validator
    Dynamic Site Solutions
    Code for Firefox, Chrome, Safari, & Opera, then add fixes for IE, not vice versa.

  8. #8
    SitePoint Enthusiast
    Join Date
    Feb 2004
    Location
    Third Stone From The Sun
    Posts
    82
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    5) getTarget( ev );

    Thank you for pointing that out.
    My outdated site is down for a while now.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •