Search code examples
jqueryevent-bubbling

Making my own accordion style toggle with jquery


I have a var in js which holds a click action. This action is bound to a few different divs:

<div class="clickable"><div class="hidden">inner content 1</div></div>

<div class="clickable"><div class="hidden">inner content 2</div></div>

<div class="clickable"><div class="hidden">inner content 3</div></div>

The js looks like so:

$(document).ready(function(){

var clicker = function(){

    $('.hidden').slideUp();

    $(this).children('.hidden').slideDown();

    $(this).unbind('click',clicker);
}


$('.clickable').bind('click',clicker);


});

The above code basically works. If i click a div.clickable it shows the hidden content. If I click another div.clickable, it hides the content I was just looking at and reveals another one. The problem however is that because of that unbind function inside 'clicker' anything I click loses its clicker functionality. I did this because the hidden content has clickable stuff, and anything I now click inside the hidden content triggers off 'clicker' again.

Whats the more intelligent approach to this without using the accordion plugins?

How can I check to see if a div has been bound to a function, and if not, rebind it or something of the sort? All I am looking for is to rebind the div.clickable to 'clicker' once its been closed ie another div.clickable .hidden is being looked at.


Solution

  • You can just exclude the one you're clicking on in the .slideUp(), like this:

    $(document).ready(function(){
      $('.clickable').click(function(){
        $('.hidden').not($(this).children()).slideUp();
        $(this).children('.hidden:hidden').slideDown();
      });
    });
    

    By using .not() we're excluding the current element in the .hidden ones to hide, and when showing children restricting it to only :hidden elements means we won't re-slide any that are already visible.

    Another way to re-write it a bit more plainly is:

    $(function(){
      $('.clickable').click(function(){
        $('.clickable').not(this).children('.hidden').slideUp();
        $(this).children('.hidden:hidden').slideDown();
      });
    });
    

    Or, if they all .clickable elements are siblings:

    $(function(){
      $('.clickable').click(function(){
        $(this).children('.hidden:hidden').slideDown()
         .end().siblings('.clickable').children('.hidden').slideUp();
      });
    });