SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    I ♥ PHP
    Join Date
    Jul 2003
    Location
    Melbourne, Australia
    Posts
    579
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Function firing for each parent node in the DOM chain

    Hi everyone,

    I have an extremely odd situation occuring that I can't for the life of me troubleshoot.

    I have the following function:
    Code:
    function treeControl(id)
    {
      var root = $(id);
      var child = root.getElementsByTagName('ul')[0];
                
      if (child.style.display == 'none')
      {
        child.style.display = 'block';
      }
      else
      {
        child.style.display = 'none';
      }
    }
    The code is fired with the following HTML:
    HTML Code:
    <ul id="tree">
      <li id="ptid1" onclick="treeControl('ptid1'); return false;">1
        <ul>
          <li id="ptid2" onclick="treeControl('ptid2'); return false;">2
            <ul>
              <li id="ptid3" onclick="treeControl('ptid3'); return false;">3</li>
              <li id="ptid4" onclick="treeControl('ptid4'); return false;">4</li>
              <li id="ptid5" onclick="treeControl('ptid5'); return false;">5</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
    The problem arises when I click on a lower level list item, such as "ptid4". When clicked, it is firing the function three times. Once for itself, then again for its parentNode "ptid2" and then a thirs time for the next parentNode up the chain: "ptid1".

    Can anyone see what is causing my code to execute itself for parent nodes?

    Regards,
    Jordan

  2. #2
    SitePoint Guru
    Join Date
    Jun 2004
    Location
    Finland
    Posts
    703
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My guess would be that
    Code:
    root.getElementsByTagName('ul')[0];
    raises an error because the node does not contain any ULs, and therefore it stops executing the code before it reaches "return false;"

  3. #3
    I ♥ PHP
    Join Date
    Jul 2003
    Location
    Melbourne, Australia
    Posts
    579
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Sorccu, thanks for the reply.

    No errors are being raised, the function is executing correctly, it is just being fired multiple times as it walks up the DOM tree.

    I am not 100% sure, but I have a feeling this may be an issue to do with closures, and that when I click on the list item, it is registering a click event for each of it's parents as well. Odd.

    Anybody else have any ideas please?

    Regards,
    Jordan

  4. #4
    I ♥ PHP
    Join Date
    Jul 2003
    Location
    Melbourne, Australia
    Posts
    579
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Wait, I've got it. I "am" actually clicking on each of those nodes now that I look at it! Because it is a nested list, when I click on "ptid4" it is also registering the click event for "ptid2" and "ptid1" due to the nesting.

    Does anybody have any idea how to get around this? These nested divs are causing me all kinds of grief right now, so a solution would be fantastic, thank you.

    Regards,
    Jordan

  5. #5
    I ♥ PHP
    Join Date
    Jul 2003
    Location
    Melbourne, Australia
    Posts
    579
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK, last post. I have fixed the problem by enclosing the value of the list item in an anchor tag. Doing this disables the click being registered for each parent object as there is no nesting for the anchors.

    Luckily I was adding the anchors anyway, solving the problem waqs just a bonus.

    Thanks guys.

    Regards,
    Jordan

  6. #6
    SitePoint Guru
    Join Date
    Jun 2004
    Location
    Finland
    Posts
    703
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah well. I knew return false might not be enough but I was kinda hoping it would because DOM events are nothing but pain and agony. Here's a simplified way of doing it

    Code:
    		function treeControl(e)
    		{
    			var e = e || window.event;
    			
    			if (e.stopPropagation)
    			{
    				e.stopPropagation();
    			}
    			else {
    				e.cancelBubble = true;
    			}
    			
    			var child = this.getElementsByTagName('ul')[0];
    			
    			if (!child)
    			{
    				return false;
    			}
    			            
    			if (child.style.display == 'none')
    			{
    				child.style.display = 'block';
    		 	}
    			else
    			{
    				child.style.display = 'none';
    			}
    		}
    		
    		function init()
    		{
    			var lis = $('tree').getElementsByTagName('li');
    			
    			for (var i = 0; i < lis.length; ++i)
    			{
    				lis[i].onclick = treeControl; // should use addEventListener
    			}
    		}
    		
    		window.onload = init;
    HTML Code:
    		<ul id="tree">
    			<li id="ptid1">1
    				<ul>
    					<li id="ptid2">2
    						<ul>
    							<li id="ptid3">3</li>
    							<li id="ptid4">4</li>
    							<li id="ptid5">5</li>
    						</ul>
    					</li>
    				</ul>
    			</li>
    		</ul>

  7. #7
    I ♥ PHP
    Join Date
    Jul 2003
    Location
    Melbourne, Australia
    Posts
    579
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thank you Sorcco, I will look at implementing it this way.

    Regards,
    Jordan


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
  •