I want to close all open lists, which contain submenus

Discussion in 'JavaScript' started by lionking, Jul 4, 2010.

  1. #1
    hello everybody

    I have a list like this


    
      
    <ul id="main_menu">
            <li><a href="#">Comments</a></li>
            <li><a href="#">[COLOR=#000000]Advertising[/COLOR]</a>
                <ul>
                    <li><a href="#">edit/delete  ads</a></li>
                    <li><a href="#">Add Ads</a></li>
                </ul>
            </li>
            <li><a href="#">Groups</a></li>
            <li><a href="#">Members</a>
                <ul>
                    <li><a href="#">Edit /  Delete Member</a></li>
                    <li><a href="#">Add Member</a></li>
                </ul>
            </li>
            <li><a href="#">Photo</a>
                <ul>
                    <li><a href="#">edit /  Delete Photo</a></li>
                    <li><a href="#">Add a  picture</a></li>
                </ul>
            </li>
            <li><a href="#">Sections</a>
                <ul>
                    <li><a href="#">Edit / Delete  section</a></li>
                    <li><a href="#">Add  Section</a></li>
                </ul>
            </li>
            <li><a href="#">General  Settings</a></li>
            <li><a href="#">Home</a></li>
        </ul>
      
    
    Code (markup):
    This list contains lists of 8, including 4 lists contain children (Advertising,Members,Photo,Sections)

    And I've written this code but did not work very well


    
    function MainMenu(item){
        var MenuItems = document.getElementById('main_menu');
        for (var i = 0; i < MenuItems.children.length; i++) {
            MenuItems.children[i].children[1].style.display = "none";
        }
        item.children[1].style.display = "block";
    }
    
    Code (markup):


    What i needed is when i press a list containing the submenus Close all open lists Then open this menu
     
    lionking, Jul 4, 2010 IP
  2. Rainulf

    Rainulf Active Member

    Messages:
    373
    Likes Received:
    12
    Best Answers:
    0
    Trophy Points:
    85
    #2
    You need to use 'onclick' event attribute in your hyperlinks to run that function of yours once you click it. :)
    eg:
    <a href="#" [B]onclick='whatever( );'[/B]>Comments</a></li>
    Code (markup):
    See: http://www.w3schools.com/TAGS/tag_a.asp
     
    Rainulf, Jul 4, 2010 IP
  3. lionking

    lionking Peon

    Messages:
    33
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #3
    Thanks Rainulf for your Help but I know this code But I forgot to write in the example at the top
    But this is not the solution
     
    lionking, Jul 4, 2010 IP
  4. meloncholy

    meloncholy Peon

    Messages:
    22
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #4
    You're not making sure that the lis actually have 2 children (an a and an ul) and in some cases, like your comments or home lis, they don't. This throws and error and stops your code working. Adding a quick check solves the problem.

    
    		function MainMenu(item) {
    			var MenuItems = document.getElementById('main_menu');
    			for (var i = 0; i < MenuItems.children.length; i++) {
    				if (MenuItems.children[i].childElementCount > 1) MenuItems.children[i].children[1].style.display = "none";
    			}
    			if (item.childElementCount > 1) item.children[1].style.display = "block";
    		}
    
    Code (markup):
     
    meloncholy, Jul 4, 2010 IP
  5. lionking

    lionking Peon

    Messages:
    33
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #5
    Thanks meloncholy
    Indeed, this is the right solution to the problem, But unfortunately, this code does not work on Internet Explorer
    I think the Internet Explorer browser does not support the function (childElementCount)
     
    lionking, Jul 5, 2010 IP
  6. meloncholy

    meloncholy Peon

    Messages:
    22
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #6
    Oops. My bad. I didn't check and apparently it's not widely supported. The link says children.length is a better alternative. Though personally I'd have avoided it all with a line or two of jQuery. :)

    
    	$("#main_menu>li ul").hide();
    	$(this).children("ul").show();
    
    Code (markup):
    
    	$(this).children("ul").show().parent().siblings().children("ul").hide();
    
    Code (markup):
     
    meloncholy, Jul 5, 2010 IP
  7. lionking

    lionking Peon

    Messages:
    33
    Likes Received:
    0
    Best Answers:
    0
    Trophy Points:
    0
    #7
    Thank you for your continue help me
    But I wish it were JavaScript code not Jquery
    any way thank you for your help
     
    lionking, Jul 5, 2010 IP
  8. hdewantara

    hdewantara Well-Known Member

    Messages:
    540
    Likes Received:
    47
    Best Answers:
    25
    Trophy Points:
    155
    #8
    Probably this function shall do:

    function MainMenu(item){
      var 
        aChild = document.getElementById('main_menu').getElementsByTagName('ul');
        for (var i = 0; i < aChild.length; i++) {
          aChild[i].style.display = (aChild[i].parentNode == item.parentNode)? "block" : "none";
        }
    }
    HTML:
    and the link should look like:
    <li><a href="javascript:void(0)" onclick="MainMenu(this)">Advertising</a>
    HTML:
    Though I'm not sure IE would support .parentNode ?
     
    hdewantara, Jul 5, 2010 IP
  9. tdemetri

    tdemetri Peon

    Messages:
    39
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #9
    can this be done using just javascript and not using jquery ? of course it can.

    it took me a little while to come up with the solution, but this is it.
    the children uls (under: Advertising, Members, Photo, and Sections) each get a unique ID ( i used 'a1', 'a2' etc)

    the main list items without children get a function to close all the uls.
    the main list items with children (Advertising, Members, Photo, and Sections) get a function which passes the ID of the ul . the function then just first closes all the ul, and then opens the correct one.

    here is the correct code to make it work. it will need some extra work to make it pretty, though. and i agree, jquery or another framework would make it more 'elegant'. but none-the -less, for learning purposes, i offer this up ,and it should work across all browsers:
    <html>
    
    <head>
        
    <script type="text/javascript">
    function closeLists() {
    	for (var i=0;i<8;i++)
    	{document.getElementById("main_menu").getElementsByTagName("ul")[i].style.display="none"};
    
    }
    function closeLists2(q) {
    	
    	for (var x=0;x<4;x++)
    	{document.getElementById("main_menu").getElementsByTagName("ul")[x].style.display="none";
    
    	document.getElementById(q).style.display="block";
    	
    	}
    }
    
    </script> 
    
    </head>
    
    <body id="body">
    
    <ul id="main_menu">
            <li onclick="closeLists()">Comments</li>
            <li  onclick="closeLists2('a1')"><a href="#">Advertising</a>
                <ul id="a1">
                    <li><a href="#">edit/delete  ads</a></li>
                    <li><a href="#">Add Ads</a></li>
                </ul>
            </li>
            <li onclick="closeLists()"><a href="#">Groups</a></li>
            <li  onclick="closeLists2('a2')"><a href="#">Members</a>
                <ul id="a2">
                    <li><a href="#">Edit /  Delete Member</a></li>
                    <li><a href="#">Add Member</a></li>
                </ul>
            </li>
            <li  onclick="closeLists2('a3')"><a href="#">Photo</a>
                <ul id="a3">
                    <li><a href="#">edit /  Delete Photo</a></li>
                    <li><a href="#">Add a  picture</a></li>
                </ul>
            </li>
            <li  onclick="closeLists2('a4')"><a href="#">Sections</a>
                <ul id="a4">
                    <li><a href="#">Edit / Delete  section</a></li>
                    <li><a href="#">Add  Section</a></li>
                </ul>
            </li>
            <li onclick="closeLists()"><a href="#">General  Settings</a></li>
            <li onclick="closeLists()"><a href="#">Home</a></li>
        </ul>
      
    
    </body>
    
    </html>
    Code (markup):
     
    tdemetri, Jul 5, 2010 IP
  10. meloncholy

    meloncholy Peon

    Messages:
    22
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #10
    Whoa! I'm sure lionking is very grateful for all of the help, but I imagine 3 solutions to his problem (plus 2 in jQuery) is probably enough. :)
     
    meloncholy, Jul 5, 2010 IP
  11. tdemetri

    tdemetri Peon

    Messages:
    39
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #11
    hi meloncholy -
    can you please elaborate on your response?
    i am not sure what point you were trying to make.
    are you suggesting to NOT offer solutions and help? especially when it is clear that lionking has
    NOT had his question answered fully before ( i.e. to NOT have to use jquery, AND to not use something unsupported in IE ).

    i would like to think that we are all sharing our knowledge and enthusiasm in a friendly and free manner.....
     
    tdemetri, Jul 5, 2010 IP
  12. meloncholy

    meloncholy Peon

    Messages:
    22
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #12
    Hey tdemetri,

    I'm sorry if my reply came across in the wrong way. I didn't mean it to be taken too seriously, and certainly wasn't intended as criticism of anyone posting here.

    The solution I provided works fine in IE if childElementCount is swapped for children.length, as I mentioned in my earlier reply. Then hdewantara posted another solution (which admittedly I haven't tried), followed shortly by your solution. That makes 3, plus the jQuery ones I listed. And, well, 3 answers seemed like it was probably sufficient for now. :)

    But I do think it's great that people are being so helpful here, and that this is an active and positive forum. It's a great place to get help and a great place to help out too, which of course is mostly down to people like those posting in this thread.
     
    meloncholy, Jul 5, 2010 IP
  13. tdemetri

    tdemetri Peon

    Messages:
    39
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #13
    no problem meloncholy, - still friends :) -

    and i didn't see where you said:
    BUT - in trying out your code, i do see how it will close all the ULs, but i don't see how it will open the child of the parent which was clicked. i would be grateful if you could explain that, and/or post a working sample
     
    tdemetri, Jul 5, 2010 IP
  14. meloncholy

    meloncholy Peon

    Messages:
    22
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #14
    Phew. :)

    Sure. I only added a couple of bits to lionking's original code, so this part is really his solution. The line in question is

    
    if (item.children.length > 1) item.children[1].style.display = "block";
    
    Code (markup):
    The clicked li is passed into the function as item, so after iterating through and hiding all of the menus, the clicked li's second child (the ul) is made visible.

    In my test code I've cheated and used jQuery to bind the click event to the lis, but you could do it by adding onclick="MainMenu(this);" to the comments, advertising, etc. lis or through another method too of course.

    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>Untitled Page</title> 
    	<script type="text/javascript" src="jquery/jquery-1.4.2.js"></script>
    	<script type="text/javascript">
    		function MainMenu(item) {
    			var MenuItems = document.getElementById('main_menu');
    			for (var i = 0; i < MenuItems.children.length; i++) {
    				if (MenuItems.children[i].children.length > 1) MenuItems.children[i].children[1].style.display = "none";
    			}
    			if (item.children.length > 1) item.children[1].style.display = "block";
    		}
    
    		(function ($) {
    			$(document).ready(function () {
    				$("#main_menu>li").click(function() {
    					MainMenu(this);
    				});
    			});
    		})(jQuery);		
    	</script>
    </head>
    <body>
    <ul id="main_menu">
            <li><a href="#">Comments</a></li>
            <li><a href="#">Advertising</a>
                <ul>
                    <li><a href="#">edit/delete  ads</a></li>
                    <li><a href="#">Add Ads</a></li>
                </ul>
            </li>
            <li><a href="#">Groups</a></li>
            <li><a href="#">Members</a>
                <ul>
                    <li><a href="#">Edit /  Delete Member</a></li>
                    <li><a href="#">Add Member</a></li>
                </ul>
            </li>
            <li><a href="#">Photo</a>
                <ul>
                    <li><a href="#">edit /  Delete Photo</a></li>
                    <li><a href="#">Add a  picture</a></li>
                </ul>
            </li>
            <li><a href="#">Sections</a>
                <ul>
                    <li><a href="#">Edit / Delete  section</a></li>
                    <li><a href="#">Add  Section</a></li>
                </ul>
            </li>
            <li><a href="#">General  Settings</a></li>
            <li><a href="#">Home</a></li>
        </ul>
    </body>
    </html>
    
    HTML:
     
    Last edited: Jul 5, 2010
    meloncholy, Jul 5, 2010 IP
  15. tdemetri

    tdemetri Peon

    Messages:
    39
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #15
    so
    he he he....

    all kidding aside, i don't see it working like that, and i've tested and re-tested .

    here is a posted example using my (non jquery) code:
    demetri-media.com/JavaScript/XHTMLtest3.html

    if you could post an example using your code i would be grateful, as i'd love to compare it and see where i am going wrong in trying to do it with jquery.

    you friend,
    -demetri-
     
    tdemetri, Jul 5, 2010 IP
  16. meloncholy

    meloncholy Peon

    Messages:
    22
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #16
    Hmmm... I'm not sure what's going wrong for you. Let me try again. Here's the code with no jQuery and with the onclick events added. (All the jQuery was doing was saving me from adding the onclicks manually.)

    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>Untitled Page</title> 
    	<script type="text/javascript">
    		function MainMenu(item) {
    			var MenuItems = document.getElementById('main_menu');
    			for (var i = 0; i < MenuItems.children.length; i++) {
    				if (MenuItems.children[i].children.length > 1) MenuItems.children[i].children[1].style.display = "none";
    			}
    			if (item.children.length > 1) item.children[1].style.display = "block";
    		}
    	</script>
    </head>
    <body>
    <ul id="main_menu">
            <li onclick="MainMenu(this);"><a href="#">Comments</a></li>
            <li onclick="MainMenu(this);"><a href="#">Advertising</a>
                <ul>
                    <li><a href="#">edit/delete  ads</a></li>
                    <li><a href="#">Add Ads</a></li>
                </ul>
            </li>
            <li onclick="MainMenu(this);"><a href="#">Groups</a></li>
            <li onclick="MainMenu(this);"><a href="#">Members</a>
                <ul>
                    <li><a href="#">Edit /  Delete Member</a></li>
                    <li><a href="#">Add Member</a></li>
                </ul>
            </li>
            <li onclick="MainMenu(this);"><a href="#">Photo</a>
                <ul>
                    <li><a href="#">edit /  Delete Photo</a></li>
                    <li><a href="#">Add a  picture</a></li>
                </ul>
            </li>
            <li onclick="MainMenu(this);"><a href="#">Sections</a>
                <ul>
                    <li><a href="#">Edit / Delete  section</a></li>
                    <li><a href="#">Add  Section</a></li>
                </ul>
            </li>
            <li onclick="MainMenu(this);"><a href="#">General  Settings</a></li>
            <li onclick="MainMenu(this);"><a href="#">Home</a></li>
        </ul>
    </body>
    </html>
    
    HTML:
    And, if you prefer, here's a link to the same code on a page. Works for me... :confused:
     
    meloncholy, Jul 5, 2010 IP
  17. tdemetri

    tdemetri Peon

    Messages:
    39
    Likes Received:
    1
    Best Answers:
    0
    Trophy Points:
    0
    #17
    got it. thanks. - and of course it makes perfect sense ( with jquery ! )
     
    tdemetri, Jul 5, 2010 IP