SitePoint Sponsor

User Tag List

Results 1 to 3 of 3
  1. #1
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    JS error, "x has no properties" - accordion-style dropdown menu

    I have an accordion style dropdown list/sublist menu (functions similar to the "today on WebMD video" widget found on http://www.webmd.com/) - it will allow users to click on a headline (from the main list) to open up the full listing (sublist) below that headline.

    My JavaScript is almost but not quite working as needed. It also serves up an error that an object "has no properties". The particular error message and line of code it refers to:

    Code:
    sf has no properties
     var state = sf.style.display;
    I'll explain further and give actual code snippets - hopefully somebody can see something obvious that I need to fix?

    Basically, I'm coding a tool that has a list of headlines (coded in definition list, DL). Clicking on a headline will reveal all the items listed below it in a subordinate list (coded as a unordered list, UL, nested inside a DD tag). Click on the same headline again, and it closes. Or, click on any other headline and the previously opened headline closes.

    Another action also requiring JS is the position of the background image used on the top-level headlines (in the main list) needs to change when their respective subordinate ULs are expanded. Once the subordinate is closed, the background image also needs to change back to it's original position.

    It is actually very similar to a basic drop-down list with rollovers, but because this requires closing/opening (i.e. "accordion") of the top level items via clicking events (and not mouseovers / hover events), it can't be done with only CSS and requires Javascript.

    OK, hopefully that clearly explains the goal. What I've got so far is basic HTML and CSS - truncated version below:

    HTML Code:
    <dl>
    <dt id="featured1" onclick="toggleDisplay('subfeat1');toggleBgPos('featured1');return false;">Headline 1</dt>
    <dd id="subfeat1">
     <ul>
       <li><a href="#" title="link info">1.1 Lorem ipsum</a></li>
       <li><a href="#" title="link info">1.2 Dolor sit amet</a></li>
     </ul>
    </dd>
    <dt id="featured2" onclick="toggleDisplay('subfeat2');toggleBgPos('featured2');return false;">Headline 2</dt>
    <dd id="subfeat2">
     <ul>
       <li><a href="#" title="link info">2.1 Lorem ipsum</a></li>
       <li><a href="#" title="link info">2.2 Dolor sit amet</a></li>
     </ul>
    </dd>
    <dt id="featured3" onclick="toggleDisplay('subfeat3');toggleBgPos('featured3');return false;">Headline 3</dt>
    <dd id="subfeat3">
     <ul>
       <li><a href="#" title="link info">3.1 Lorem ipsum</a></li>
       <li><a href="#" title="link info">3.2 Dolor sit amet</a></li>
     </ul>
    </dd>
    </dl>
    The simplified CSS:
    Code:
    dt {background: url(image.gif) 0 0 no-repeat;}
    That is a "pixy rollover" style image - so the desired effects is that when a main list item (DT element) is clicked and it's subordinate is expanded, that background position will change to "0 -25px".

    All the HTML/CSS validates. The problem is definitely (well, best I can tell) with the Javascript - as follows:

    Code:
    /* TOGGLE DISPLAY - show / hide the list */
    window.onload=toggleDisplay; // will load if Javascript enabled, otherwise all menus will stay shown / accessible
    
    function toggleDisplay(subFeatID) {
    	var sf = document.getElementById(subFeatID);
    	
    	for (var i = 1; i<=10; i++) { // menus are hidden when the document loads up, but only if Javascript is enabled.
    		if (document.getElementById('subfeat'+i)) {document.getElementById('subfeat'+i).style.display='none';}
    	}
    	
    	var state = sf.style.display; // toggle display rule
    	if (state == 'block')
    		sf.style.display = 'none';
    	else if (state != 'block')
    		sf.style.display = 'block'; 
    }
    
    
    /* TOGGLE BACKGROUND - change background image position accordingly */
    function toggleBgPos(featID) {
    	var f = document.getElementById(featID);
    	
    		for (var i = 1; i<=10; i++) {
    		if (document.getElementById('featured'+i)) {document.getElementById('featured'+i).style.backgroundPosition='0px 0px';}
    	}
    
    	pos = f.style.backgroundPosition;
    	if (pos == '0px -25px')
    		f.style.backgroundPosition = '0px 0px';
    	else if (pos != '0px -25px')
    		f.style.backgroundPosition = '0px -25px'; 
    }
    As is, the headlines open and close properly *except* in the case where you click on the open headline itself. If you click on any headline (DT element), it expands to show the sub list. Click on *any other* headline DT element, and the first one closes and the new one just clicked on expands. The background image position changes correctly.

    So the only two problems are:
    1. the error message
    2. can't get the headline DT elements to close when clicking on the one that is open.

    I EXTREMELY appreciate anybody who has read through all this and feels inspired enough to suggest some fix. Any ideas are welcome!

    Thanks!

  2. #2
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,271
    Mentioned
    197 Post(s)
    Tagged
    3 Thread(s)

    no properties

    The code has an onload calling the function but no argument is passed to it
    Code:
    window.onload=toggleDisplay; // will load if Javascript enabled, otherwise all menus will stay shown / accessible
    
    function toggleDisplay(subFeatID) {
    	var sf = document.getElementById(subFeatID);
    sf has no properties because there is no element with an id of NULL

  3. #3
    SitePoint Enthusiast
    Join Date
    Apr 2006
    Posts
    34
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yes, my ordering of the arguments was also apparently an issue. After some help elsewhere, I've arrived at the following which works fine now!

    Code JavaScript:
     
    <script type="text/javascript">
    <!--
     
    window.onload=closeAll; // will load if Javascript enabled, otherwise all menus will stay shown / accessible
     
    // TOGGLE DT DISPLAY STATE - show/hide the list. Sets clicked DT's display to 'block' if closed, otherwise set to 'none'; close any other open DT
    function toggleDisplay(subFeatID) {
    	var sf = document.getElementById(subFeatID);
    	var state = sf.style.display; // toggle display rule
            closeAll();
    	if (state == 'block')
    		sf.style.display = 'none';
    	else if (state != 'block')
    		sf.style.display = 'block'; 
    }
     
    function closeAll() {
    	for (var i = 1; i<=10; i++) { // menus are hidden when the document loads up, but only if Javascript is enabled.
    		if (document.getElementById('subfeat'+i)) {document.getElementById('subfeat'+i).style.display='none';}
    	}
    }
     
    // TOGGLE DT BACKGROUND - change background image position accordingly */
    function toggleBgPos(featID) {
    	var f = document.getElementById(featID);
     
    	pos = f.style.backgroundPosition;
    	for (var i = 1; i<=10; i++) {
    		if (document.getElementById('featured'+i)) {document.getElementById('featured'+i).style.backgroundPosition='0px 0px';}
    	}
            if (pos == '0px -25px')
    		f.style.backgroundPosition = '0px 0px';
    	else if (pos != '0px -25px')
    		f.style.backgroundPosition = '0px -25px'; 
    }

    so all good!


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
  •