Take the 2-minute tour ×

This is the HTML I'm working with:

<ul id="categories">
  <li><a href="#cargo">Cargo Trailers</a></li>
  <div class="dropdown">
      <li><a href="#utility">Utility Trailers</a></li>

I have written a jQuery script to hide the dropdown div. The dropdown div appears the first time the click event is fired. Once the li in the dropdown div is selected and switches places with the first li in the #categories ul, clicking on the li will not bring up the dropdown div.

Here is the jQuery:

jQuery(document).ready(function($) {

// hide the dropdown div
$('#categories > div').hide();

    Click the drop down arrow function
var $listHeader = $('#categories > li');

$listHeader.click(function() {  

    if ( $('#categories > div:hidden') ) {
        //show the drop down
        $('#categories > div').show();
    } else {
        //hide the drop down

    Click a list-item in the drop down function
$('#categories > div a').click(function() {

    /* actions to change the title to the newly selected item */
    // hide the ul

    // move the clicked item to the header
    $(this).prependTo('#categories > li');

    // move the previous title to the dropdown and sort
    $('#categories > li > a:eq(1)').prependTo('#categories > div > ul > li:empty');

    // Reset the listHeader variable

    // cancel default browser action
    return false;

share|improve this question
You cannot put a DIV there. Only LIs can be inside UL. –  Šime Vidas Jan 21 '11 at 21:55

3 Answers 3

up vote 4 down vote accepted

this $('#categories > div:hidden') will always return jQuery object (which evaluates to true), even if there are no elements matching selector. Use jQuery's .toggle() instead of if...else:

$('#categories > div').toggle();

here's an example to play with

Update in response to your comment: Updated example - http://jsfiddle.net/Etkjr/1/

You are correct, event handlers are unbound on DOM change. To prevent, that you would need to use 2 jQuery functions: .live() and .delegate. Both of them monitor DOM changes and rebind events to selectors when the DOM is changed.

You want click on a first li to expand dropdown menu - use

$('#categories li:first').live('click', function() {})

this way clicking on a first li will trigger your handler, even if your li was just now moved to first position.

$('#categories').delegate('.dropdown a', 'click', functon(evt) {})

This is an example of .delegate(). This means that when someone clicks element matching .dropdown a inside the #categories this handler will be called.

Here you can use .live() instead, but .delegate makes more sense. Instead of assigning (copying) event handler to all matching elements, we delegate all clicks to a single event handler.

I also updated "moving" code. Interesting side effect here, is that you don't need to .hide() dropdown inside the second handler. You see, when you click on a link inside dropdown, the link gets moved into first position. .live() detects that and assigns a click() handler to the link you just clicked. But event is still propagating, so after your second handler is finished, event bubbles up to li, and $('.li').live('click', ...) executes, hiding your dropdown div.

Hope this makes sense.

share|improve this answer
I get the same result binding the click event with .toggle(). Clicking on 'Cargo Trailers' pops up the div. Clicking on "utility Trailers" causes the anchor element to switch places with "Cargo Trailers". Once they have switched places is where the problem comes in. I expect that clicking on "Utility Trailers" after the switch will still cause the div to show up, but it does not. Debugging I can tell that the click event is not even firing anymore. Somewhere in the switch, the click event has become unbound. –  ToddSmithSalter Jan 22 '11 at 2:35
@ToddSmithSalter, I updated my answer and example fiddle –  German Rumm Jan 22 '11 at 4:11

It could be your if statement needs .length on it, giving:

If ( $('selector').length > 0 ) // show the drop down

Your current if statement doesn't check whether the object exists. Selectors return an empty collection of elements, not null, if they don't match anything.

share|improve this answer

Maybe prependTo removes the click event handler. Execute the initialization again. If that indeed works, you can choose to use the jQuery.live() function instead of jQuery.click() to bind the click events.

share|improve this answer

Your Answer


