SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Addict
    Join Date
    Jul 2006
    Location
    Fionnphort, Isle of Mull, Scotland
    Posts
    334
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    Refining the jQuery selection

    The code below is my first crack at a jQuery script for animating a three-level 'Suckerfish' menu which has run in CSS only form for some time. It can be seen working at http://www.holidaymullandiona.com

    This is the entire script:

    Code:
    	$(document).ready(function(){
    //		alert ('Welcome to Holiday Mull');
    
    		$('#nav li ul').css({
    			display: 'none',
    			left: 'auto'
    		});
    //              Selector for first level <li>
    		$('ul.level1 li').hover(function() {
    			$(this)
    				.children('ul')       // Should select ONLY next (second) level UL
    				.stop(true, true)
    				.delay(500)
    				.slideDown('slow');
    		}, function() {
    			$(this)
    				.children('ul')       // Should select ONLY next (second) level UL, but appears to select third level as well
    				.stop(true, true)
    				.delay(500)
    				.fadeOut('fast');  // This action gets applied to all levels when <li> is un-hovered, but this is NOT what I want
    		});
    
    //              Selector for second level <li>
    		$('#nav li li').hover(function() {
    			$(this)
    				.children('ul')       // Should select ONLY next (third) level UL
    				.css({'opacity': '0', zIndex: '-1'})
    				.animate({
    					left: '104px',
    					opacity: '1',
    					zIndex: '1'
    				}, 500);
    		}, function() {                     // This should be the 'un-hover' action, but the 'fadeOut' above happens first
    			$(this)
    				.children('ul')
    //				.delay(500)
    				.animate({
    					left: '200px',
    					opacity: '0.25',
    //					zIndex: '-1'
    				}, 500);
    		});
    	});
    Hovering over the first level <li> gets the drop-down menu as required, then hovering on a second-level <li> gets the third level (where present). The third level <ul> appears from behind the second, in accordance with the animation:
    Code:
    		$('#nav li li').hover(function() {
    			$(this)
    				.children('ul')
    				.css({'opacity': '0', zIndex: '-1'})  // sets a start condition ensuring the third level underlies second
    				.animate({
    					left: '104px',
    					opacity: '1',
    					zIndex: '1'
    				}, 500);
                                     ...
    Up to this point it works as I intend. The problem is that when I move the mouse, either to another <li> or off the menu altogether the third level <ul> does the "fadeOut('fast')" of the second level instead of the intended animation. For illustration purposes only, the intended animation shown would move the <ul> further out to the right and fade it. It is clear that this action does occur (but only after the "fadeOut('fast')"), because when the <li> is next hovered, the <ul> does indeed appear from the right.

    Code:
    // Intended action on UN-hovering (moves <ul> to the right and fades it out)
                    ...
    		}, function() {
    			$(this)
    				.children('ul')
    //				.delay(500)
    				.animate({
    					left: '200px',
    					opacity: '0.25',
    //					zIndex: '-1'
    				}, 500);
    		});
    // For illustration only: ultimately this will be changed to move <ul> back to the left
    This can be most easily seen on the linked web page by first hovering on 'Places to Stay' and then alternately hovering 'B&B/Guest Hoses' and 'Self-catering'. http://www.holidaymullandiona.com


    What I'd like is for the third level <ul> to follow the intended animation when it's parent <li> is no longer hovered, and NOT fade out as it does now. I think this means making the first level selector more specific so that it doesn't also select the second level. I thought I'd done that with the ".children('ul')", but it seems not. I have tried adding a class to the <ul>, as in ".children('ul.level2')" or ".find('ul.level2')" but so far without success. It doesn't produce a syntax error, just no level 3 action, so presumably it's now TOO specific !

    Can anyone point me in the right direction, please ?
    Tim Dawson
    Isle of Mull, Scotland

  2. #2
    Under Construction silver trophybronze trophy AussieJohn's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    776
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    It seems that the main problem you have is that you want to select the immediate children of a certain level. You can do this by adding the immediate-child selector before the selector you want when using .children().

    So in your case you could do:
    Code:
    $(this)
        .children(' > ul')
    //...
    This way you can always be sure that only the next level of <ul>(s) are selected.
    var details = {
    . . web: "afterlight.com.au",
    . . photos: "jvdl.id.au",
    . . psa: "usethelatestversion.com"
    }

  3. #3
    SitePoint Addict
    Join Date
    Jul 2006
    Location
    Fionnphort, Isle of Mull, Scotland
    Posts
    334
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Thank you, John, for your response.

    It seems that the main problem you have is that you want to select the immediate children of a certain level. You can do this by adding the immediate-child selector before the selector you want when using .children().
    I'd have said that was exactly what I wanted to do. In fact, I thought that was what ".chidren('e')" was meant to do on its own, without any '>'. I've never previously seen the immediate-child selector used without an element in front of it. I've tried adding the '>', so the script reads:

    Code:
    		$('ul.level1 li').hover(function() {
    			$(this)
    				.children('> ul')
    				.stop(true, true)
    				.delay(500)
    				.slideDown('slow');
    		}, function() {
    			$(this)
    				.children('> ul')
    				.stop(true, true)
    				.delay(500)
    				.fadeOut('fast');
    		});
    but now it doesn't work at all. No second-level drop down. It doesn't look as if anything's getting selected.

    However ".find('> ul')" does work, but in exactly the same way as ".children('ul')".
    Last edited by ramasaig; Dec 28, 2012 at 18:09. Reason: Add final line
    Tim Dawson
    Isle of Mull, Scotland

  4. #4
    Under Construction silver trophybronze trophy AussieJohn's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    776
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    I was just having a play around and thought I'd make a standalone example to get this to work. I actually just ended up making your main selectors more specific rather than address the .children().

    So the first level <li> selector becomes: $('#nav > ul > li')
    The second (and subsequent) <li> selector becomes: $('#nav > ul ul li')

    I have a live example on JS Fiddle: http://jsfiddle.net/GeekyJohn/C26MJ/
    var details = {
    . . web: "afterlight.com.au",
    . . photos: "jvdl.id.au",
    . . psa: "usethelatestversion.com"
    }

  5. #5
    SitePoint Addict
    Join Date
    Jul 2006
    Location
    Fionnphort, Isle of Mull, Scotland
    Posts
    334
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Funnily enough I had the same thought in my shower this morning, though I hadn't worked out what the main selectors should become. I've tried your suggestion, and although $('#nav > ul > li') works at first level (i.e. the second level UL drops down), the third level UL doesn't fly out to the right when the second level is hovered. Whether that's due to the change in the first or second main selector I've yet to determine.

    I've looked at your example, which seems to work OK, so it will probably help if I work out what the difference is.
    Tim Dawson
    Isle of Mull, Scotland

  6. #6
    Under Construction silver trophybronze trophy AussieJohn's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    776
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ramasaig View Post
    I've looked at your example, which seems to work OK, so it will probably help if I work out what the difference is.
    Ah yes, I think in the second hover event handler I had to also add a "display:block" to the .css() call - since you were setting it to "none" to start with, but weren't setting it back to "block"

    i.e.
    Code:
     .css({'opacity': 0, display: "block", left:0})
    Once you add that in together with the updated selector it should show the 3rd level.
    var details = {
    . . web: "afterlight.com.au",
    . . photos: "jvdl.id.au",
    . . psa: "usethelatestversion.com"
    }

  7. #7
    SitePoint Addict
    Join Date
    Jul 2006
    Location
    Fionnphort, Isle of Mull, Scotland
    Posts
    334
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Later: Turns out the crucial difference between my script (as amended today) and your demo is in the "display: 'block'" in the second level hover function. I see now that without that the third level would still be "display:' none'" in accordance with the first function.
    With that and reverting a few other values in my script the third level UL now glides nicely out and back.
    http://www.holidaymullandiona.com

    Thank you for your help.
    Tim Dawson
    Isle of Mull, Scotland


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
  •