SitePoint Sponsor

User Tag List

Results 1 to 16 of 16
  1. #1
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    jquery: toggling the sibling

    Hi,

    I want to toggle the next sibling of a link in a list like this,

    Code:
    <ul>
    	<li><a href="#">1</a></li>
    	<li><a href="#">2</a>
    		<ul class="selected">
    			<li><a href="#">2.1</a></li>
    			<li><a href="#">2.2</a></li>
    			<li><a href="#">2.3</a></li>
    		</ul>
    	</li>
    	<li><a href="#">3</a></li>
    	<li><a href="#">4</a>
    		<ul class="selected">
    			<li><a href="#">4.1</a></li>
    			<li><a href="#">4.2</a></li>
    			<li><a href="#">4.3</a></li>
    		</ul>
    	</li>
    	<li><a href="#">5</a></li>
    </ul>
    and this is my jquery,

    Code:
    $(document).ready(function(){
    
    	$("a").each(function () {
    		if ( $(this).siblings().size() > 0) 
    		{
    			$(this).append("<span class='has-child'>has child</span>");
    
    			$(this).toggle(
    				function (){
    					$("ul").removeClass("showme");
    					$(this).siblings(".selected").addClass("showme");
    					//$(this).next().css({display: "block"});
    				},
    				function (){
    					$(this).siblings(".selected").removeClass("showme");
    					//$(this).next().css({display: "none"});
    			});
    
    		}
    	});
    	
    	$('ul > li > ul > li:last-child > a').css('background','yellow');
    	
    });
    the css,

    Code:
    ul > li > ul {
    		display:none;
    	}
    	
    	ul > li:hover ul{
    		display: block;
    	}
    	.showme {
    		display: block;
    	}
    first of all, it seems fine - I can toggle the targeted sibling, but why after the first toggle at any parent, I have to click twice sometime to hide other siblings when I click/ toggle at the current parent?

    here is the live site if I am not explaining it clearly,
    http://lauthiamkok.net/tmp/jquery/toggle/

    Many thanks,
    Lau

  2. #2
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Code JavaScript:
    $(document).ready(function(){
    	// Change the first <ul> of the HTML to <ul id="tree"> in order for the next line to work
    	// I changed it because it's bit overkill to walk ALL <a>'s on the page when you're just interested in
    	// the <a>'s in the tree
    	$("#tree a").each(function () {
    		// add .selected in .siblings() to be more specific
    		if ($(this).siblings('.selected').size() > 0) {
    			// Please, no single quotes for HTML attributes...
    			$(this).append("<span class=\"has-child\">has child</span>");
     
    			// The toggle here was causing the problem of needing to click twice.
    			// .toggle() does not take into account if an element is currently visible, but merely
    			// lets you assign two onclick functions where the first function is fired every even click
    			// and the second one if fired every odd click
    			// Because a click of an element in your case can cause *another* element to show/hide, the
    			// normal principle of .show()/.hide() doesn't work here anymore
    			$(this).click( function (){
    					// check if the next element (the "drop down") is currently visible
    					if ($(this).siblings('.selected').is(':visible')) {
    						$('.selected').removeClass('showme'); // hide all drop downs
    						$(this).siblings('.selected').addClass('showme'); // and show the drop down connected to this link
    					}
    			});
    		}
    	});
    	$('ul > li > ul > li:last-child > a').css('background','yellow');
    });

    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  3. #3
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    Code JavaScript:
    $(document).ready(function(){
    	// Change the first <ul> of the HTML to <ul id="tree"> in order for the next line to work
    	// I changed it because it's bit overkill to walk ALL <a>'s on the page when you're just interested in
    	// the <a>'s in the tree
    	$("#tree a").each(function () {
    		// add .selected in .siblings() to be more specific
    		if ($(this).siblings('.selected').size() > 0) {
    			// Please, no single quotes for HTML attributes...
    			$(this).append("<span class=\"has-child\">has child</span>");
     
    			// The toggle here was causing the problem of needing to click twice.
    			// .toggle() does not take into account if an element is currently visible, but merely
    			// lets you assign two onclick functions where the first function is fired every even click
    			// and the second one if fired every odd click
    			// Because a click of an element in your case can cause *another* element to show/hide, the
    			// normal principle of .show()/.hide() doesn't work here anymore
    			$(this).click( function (){
    					// check if the next element (the "drop down") is currently visible
    					if ($(this).siblings('.selected').is(':visible')) {
    						$('.selected').removeClass('showme'); // hide all drop downs
    						$(this).siblings('.selected').addClass('showme'); // and show the drop down connected to this link
    					}
    			});
    		}
    	});
    	$('ul > li > ul > li:last-child > a').css('background','yellow');
    });

    Hi, thanks so much for explaining about toggle(). I have tried your suggestion, however, the current parent does not toggle anymore, it only toggle when I click on other parents... have a look here,

    http://lauthiamkok.net/tmp/jquery/toggle/index_2.html

    for instance, when I click on the link 2 only, I was hoping to show its sibling too. and hide it when I click on this parent again.

    is it possible...?


    thanks!

  4. #4
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by lauthiamkok View Post
    is it possible...?
    It sure is.

    Replace

    Code JavaScript:
    $(this).click( function (){
    		// check if the next element (the "drop down") is currently visible
    		if ($(this).siblings('.selected').is(':visible')) {
    			$('.selected').removeClass('showme'); // hide all drop downs
    			$(this).siblings('.selected').addClass('showme'); // and show the drop down connected to this link
    		}
    });
    }

    with
    Code JavaScript:
    $(this).click( function (){
    	// check if the next element (the "drop down") is currently visible
    	var sibling = $(this).siblings('.selected');
    	$('.selected').not( sibling ).removeClass('showme'); // hide all visible drop downs, but not the sibling of the clicked <a>
    	if (!sibling.hasClass('showme')) {
    		sibling.addClass('showme'); // show the drop down connected to this <a>
    	} else {
    		sibling.removeClass('showme'); // hide the drop down connected to this <a>
    	}
    });

    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  5. #5
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    It sure is.

    Replace

    Code JavaScript:
    $(this).click( function (){
    		// check if the next element (the "drop down") is currently visible
    		if ($(this).siblings('.selected').is(':visible')) {
    			$('.selected').removeClass('showme'); // hide all drop downs
    			$(this).siblings('.selected').addClass('showme'); // and show the drop down connected to this link
    		}
    });
    }

    with
    Code JavaScript:
    $(this).click( function (){
    	// check if the next element (the "drop down") is currently visible
    	var sibling = $(this).siblings('.selected');
    	$('.selected').not( sibling ).removeClass('showme'); // hide all visible drop downs, but not the sibling of the clicked <a>
    	if (!sibling.hasClass('showme')) {
    		sibling.addClass('showme'); // show the drop down connected to this <a>
    	} else {
    		sibling.removeClass('showme'); // hide the drop down connected to this <a>
    	}
    });

    hi thanks again! I have modified the code a little, so that I can toggle the parent in the way I want to achieve,


    Code:
    $(this).click( function (){
    				// check if the next element (the "drop down") is currently visible
    				var sibling = $(this).siblings('.selected');
    				$('.selected').not( sibling ).removeClass('showme'); // hide all visible drop downs, but not the sibling of the clicked <a>
    				if (!sibling.hasClass('showme')) {
    					sibling.css({display: 'block'});
    					sibling.addClass('showme'); // show the drop down connected to this <a>
    				} else {
    					sibling.css({display: 'none'});
    					sibling.removeClass('showme'); // hide the drop down connected to this <a>
    				}
    				return false;
    			});

    but then, the problem is the css hover is not working anymore!

    is there any way I can have both toggle and hover at the same time, or I only can have one of them??

    thanks so much!

  6. #6
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Why did you use sibling.css()? Isn't that what you created the "showme" CSS class for? Does sibling.css() add anything to the script it didn't do before (besides breaking the :hover CSS) ?

    PS. Instead of node.css({display: "block";}); you can use node.show(); and instead of node.css({display: "none";}); you can use node.hide();. Shorter and better readable
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  7. #7
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    Why did you use sibling.css()? Isn't that what you created the "showme" CSS class for? Does sibling.css() add anything to the script it didn't do before (besides breaking the :hover CSS) ?
    sorry, i got things complicated! i created addClass to fix this problem in the first place actually,

    http://lauthiamkok.net/tmp/jquery/toggle/index_3.html

    I can do the hover with usual css's tricks, and I want the next sibling/ children to stay open when I click on the parent, the problem is that when I close/ hide the next sibling/ children, I cannot open/ show the the next sibling/ children again by hovering. so i thought addClass could help me on this... guess I was wrong.

    this is the initial idea...

    Code:
    $(document).ready(function(){
    
    	$("a").each(function () {
    		if ( $(this).siblings().size() > 0) 
    		{
    			$(this).append("<span class='has-child'>has child</span>");
    			
    			$(this).toggle(
    				function (){
    					$(this).next().css({display: "block"});
    					//$(this).parent().css({background: "#000"});
    				},
    				function (){
    					$(this).next().css({display: "none"});
    			});	
    
    		}
    	});	
    	
    	$('ul > li > ul > li:last-child > a').css('background','yellow');
    	
    });
    it seems that there's no way to re-open/ show the sibling/ children again after hiding them with toggle() - doesn't it?

    thanks!

  8. #8
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    The css :hover doesn't work because .show() and .hide() -- and their .css nephews as well -- set an inline style on the elements, which by definition take precedence over styles defined in the CSS.

    Hence, if you drop the .hide() and .show() and use .addClass() and .removeClass() --as I've already provided for you-- it will work, because ul > li:hover ul takes precedence over .show.

    Am I missing something or are you seeing a problem where there is none?
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  9. #9
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    The css :hover doesn't work because .show() and .hide() -- and their .css nephews as well -- set an inline style on the elements, which by definition take precedence over styles defined in the CSS.

    Hence, if you drop the .hide() and .show() and use .addClass() and .removeClass() --as I've already provided for you-- it will work, because ul > li:hover ul takes precedence over .show.

    Am I missing something or are you seeing a problem where there is none?
    nope, you are not missing anything! :-) it is just that I am rubbish in explaining this, without demonstrating the problem on screen for u. will get back to this thread when I can explain it better or when i get the solution

    thanks for your help and time!

  10. #10
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post

    Am I missing something or are you seeing a problem where there is none?
    I came out with this solution, in which I made two functions,

    Code JavaScript:
    $(document).ready(function(){
     
    	$("a").each(function () {
    		if ( $(this).siblings().size() > 0) 
    		{
    			$(this).append("<span class='has-child'>has child</span>");
     
    			var $this = $(this);
    			hoverme($this);
    		}
    	});	
     
    	$('ul > li > ul > li:last-child > a').css('background','yellow');
     
    });
     
     
    function hoverme($this) {
     
    	var parent_li = $this.parent();
    	var sibling_ul = $this.next();
     
    	parent_li.hover(
    		function (){
    			sibling_ul.css({display:'block'});
    				parent_li.click( function (){
     
    					sibling_ul.css({display:'block'});
    					parent_li.unbind('mouseenter mouseleave');
     
    					toggleme($this,parent_li,sibling_ul);
    					return false;
    				});
     
    			},
    		function (){
    		sibling_ul.css({display:'none'});
    		//sibling_ul.fadeOut();
    	});
    }	
     
    function toggleme($this,parent_li,sibling_ul){
     
    	parent_li.addClass('hideme');
     
    	$('.hideme').click(function (){
     
    		sibling_ul.css({display:'none'});
    		parent_li.removeClass('hideme');
    		parent_li.addClass('showme');
     
    		$('.showme').click(function (){
    			sibling_ul.css({display:'block'});
    			parent_li.removeClass('showme');
     
    			toggleme($this,parent_li,sibling_ul);
    		});
     
    	hoverme($this);
    	});					
    }


    you can have a look at the link below for what I am trying to achieve here,
    http://lauthiamkok.net/tmp/jquery/toggle/index_3.html

    1. you can hover the parent, and you can stop the hover when you click on the parent.
    2. you can toggle the parent without hovering away from the parent.
    3. when you close/ hide the sibling/ children, you can start hovering the parent again.

    but the flaw of this solution is, the more I click on the same parent without hovering away from it, the script seems to run oddly and getting 'tired'....

    what have I done wrong?

    thanks.

  11. #11
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    No offense, but if you need 41 lines of jQuery (not counting black lines and comment-only lines) to achieve the three relative simple points you outlined above you're doing something wrong
    My advise is to delete all jQuery code you have so far and go back to the drawing board. The code you have now is way over-complicated.

    Furthermore, I'm not a usability expert, but the workings of your menu are utterly confusing me.

    Am I correct to assume you want to toggle the menu items with jQuery but want to offer an alternative to users who don't have javascript enabled through the use of CSS hover?

    If so, there's a better solution for that.

    1) In your master stylesheet, leave ul > li:hover > ul { display: block; }
    2) Create an external stylesheet with the rule ul > li:hover > ul { display: block; }
    3) Load the external stylesheet through jQuery
    Code javascript:
    $('<link>').attr({'rel':'stylesheet','type':'text/css','href':'/path/to/my/stylesheet.css'}).appendTo('head');
    4) Create the jQuery for toggling the menu items

    That way, if a user doesn't have javascript enabled the functionality will be available using CSS hover, but if they do have javascript enabled, javascript cancels the CSS behavior through the loading of the external stylesheet and replaces it with javascript functionality.

    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  12. #12
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    No offense, but if you need 41 lines of jQuery (not counting black lines and comment-only lines) to achieve the three relative simple points you outlined above you're doing something wrong
    My advise is to delete all jQuery code you have so far and go back to the drawing board. The code you have now is way over-complicated.
    nope, no offence at all! thanks for pointing out the mistake I am doing indeed

    Quote Originally Posted by ScallioXTX View Post
    Am I correct to assume you want to toggle the menu items with jQuery but want to offer an alternative to users who don't have javascript enabled through the use of CSS hover?
    actually is the other way round - I would like to offer the use of CSS hover as the first choice, but also to offer Javascript's toggling as an alternative.

    the reason doing is that sometime the CSS hover doesn't work properly on Apple's machine and IE browser (whether on PC or Apple). so, I thought Javascript's toggling can provide this solution when the browser and machine fail the CSS

    Quote Originally Posted by ScallioXTX View Post

    1) In your master stylesheet, leave ul > li:hover > ul { display: block; }
    2) Create an external stylesheet with the rule ul > li:hover > ul { display: block; }
    3) Load the external stylesheet through jQuery
    Code javascript:
    $('<link>').attr({'rel':'stylesheet','type':'text/css','href':'/path/to/my/stylesheet.css'}).appendTo('head');
    4) Create the jQuery for toggling the menu items

    That way, if a user doesn't have javascript enabled the functionality will be available using CSS hover, but if they do have javascript enabled, javascript cancels the CSS behavior through the loading of the external stylesheet and replaces it with javascript functionality.

    this is an interesting idea. I will think about it. again, thanks so much

  13. #13
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by lauthiamkok View Post
    actually is the other way round - I would like to offer the use of CSS hover as the first choice, but also to offer Javascript's toggling as an alternative.

    the reason doing is that sometime the CSS hover doesn't work properly on Apple's machine and IE browser (whether on PC or Apple). so, I thought Javascript's toggling can provide this solution when the browser and machine fail the CSS
    In that case get rid of the child-selectors in your CSS (which are not properly supported in all major browsers), ie change ul > li:hover > ul to ul li:hover ul (which is supported in all major browser) and use Whatever:hover to enable :hover for all elements in IE < 7

    The website of Whatever:hover suggests

    Code CSS:
    body {
      behavior: url("csshover3.htc");
    }

    but I find that a bit over-kill and suggest you only apply it for elements and classes where you actually need it. In your case that would be

    Code CSS:
    ul li {
      behavior: url("csshover3.htc");
    }

    In addition, if you store that rule in a stylesheet called ie6.css and serve it using conditional comments by putting the following in the <head> of your HTML

    Code:
    <!--[if lt IE 7]>
       <link rel="stylesheet" type="text/css" href="/styles/ie6.css" />
    <![endif]-->
    only IE versions lower than 7 will download and apply it while other browsers don't bother

    PS. Come to think of it, you could also rewrite ul > li:hover > ul to li:hover ul because the first ul is superfluous and li:hover ul is a better (faster) rule than ul li:hover ul
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  14. #14
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    In that case get rid of the child-selectors in your CSS (which are not properly supported in all major browsers), ie change ul > li:hover > ul to ul li:hover ul (which is supported in all major browser) and use Whatever:hover to enable :hover for all elements in IE < 7
    oh, i use lots of child-selectors in my CSS, loads of changes to work on now! lol

    I should avoid child-selectors as much as possible in the futures.

    thank you.

  15. #15
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,084
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by lauthiamkok View Post
    I should avoid child-selectors as much as possible in the futures.
    Well, for the near future at least. Let's hope that at some point in the future all major browsers will support them

    PS. Futures? Do you subscribe to the many worlds theory?
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  16. #16
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ScallioXTX View Post
    Well, for the near future at least. Let's hope that at some point in the future all major browsers will support them
    I hope so!

    Quote Originally Posted by ScallioXTX View Post
    PS. Futures? Do you subscribe to the many worlds theory?
    it's my bad english!

    (out of topic) but in science and philosophy, I think many worlds should exist! string theory!


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
  •