views:

462

answers:

4

The code below will show / hide a div on click. It works perfectly for the first div listed, but doesn't work for any of the others. Is there a way to have the function apply to all the elements with the same class names? It should, of course, only open / close the div to which it's being applied (i.e., clicking on the Second Div toggle button should only open / close the Second Div, and not the others...)

// this is the markup
<div class="collapsible-item">
    <div class="collapsible-item-title">
        <div class="item-title-header"> First Div</div> 
        <img src="/images/expand.png" alt="Expand this section" class="toggle-button">
        </div>
    </div>
    <div style="display: none;" class="togglethis">
        Cras cursus sodales odio, quis consectetur felis ultricies in. 
    </div>
</div>

<div class="separator"></div>

<div class="collapsible-item">
    <div class="collapsible-item-title">
        <div class="item-title-header"> Second Div</div> 
        <img src="/images/expand.png" alt="Expand this section" class="toggle-button">
        </div>
    </div>
    <div style="display: none;" class="togglethis">
        Cras cursus sodales odio, quis consectetur felis ultricies in. 
    </div>
</div>

<div class="separator"></div>

<div class="collapsible-item">
    <div class="collapsible-item-title">
        <div class="item-title-header"> Third Div</div> 
        <img src="/images/expand.png" alt="Expand this section" class="toggle-button">
        </div>
    </div>
    <div style="display: none;" class="togglethis">
        Cras cursus sodales odio, quis consectetur felis ultricies in. 
    </div>
</div>

And, this is the jQuery:

$(document).ready(function () {
        $('.toggle-button').toggle(
            function() {
                $(this).attr('src', '/images/collapse.png');
                $(this).parent().siblings('.togglethis').slideToggle('slow');
            },
            function() {
                $(this).attr('src', '/images/expand.png');
                $(this).parent().siblings('.togglethis').slideToggle('slow');
            }
        );

        $('.item-title-header').toggle(
                function() {
                        $('.toggle-button').attr('src', '/images/collapse.png');
                        $(this).parent().siblings('.togglethis').slideToggle('slow');
                },
                function() {
                        $('.toggle-button').attr('src', '/images/expand.png');
                        $(this).parent().siblings('.togglethis').slideToggle('slow');
                }
        );
   });
+1  A: 

You have a mismatch of opening and closing DIV tags. It’s probably either the closing DIV tag in the line of the opening DIV tag of the class item-title-header or two lines below that.

You can also make it more compact by using this:

$(document).ready(function() {
    $('.collapsible-item-title').toggle(
        function() {
            $(this).attr('src', '/images/collapse.png')
                .next('.togglethis').slideToggle('slow');
        },
        function() {
            $(this).attr('src', '/images/expand.png')
                .next('.togglethis').slideToggle('slow');
        }
    );
});
Gumbo
You are right about the mismatched tags but your code doesn't really duplicate the functionality. It would if you changed `$(this).attr('src', '/images/collapse.png')` to `$(this).find('.toggle-button').attr('src', '/images/collapse.png').end()`
brianpeiris
+1  A: 

Something like this?

<script>
$(document).ready(function () {

    $.fn.toggleTo = function( options ) {
        options = $.extend( options, {
     containerClass:'collapsible-item',
     speed:'slow',
     collapse:'/images/collapse.png',
     expand:'/images/expand.png',
     toggleClass:'togglethis'
        });

        return this.each(function() {

     var p = $(this).closest('.' + options.containerClass);

     $(this).toggle(function() {
         $(p).find('.toggle-button').attr('src', options.collapse);
         $(p).next('.' + options.toggleClass).slideToggle('slow');
     }, function() {
         $(p).find('.toggle-button').attr('src', options.expand);
         $(p).next('.' + options.toggleClass).slideToggle('slow');
     });
        });
    }

    $('.item-title-header, .toggle-button').toggleTo();
   });

</script>

http://jsbin.com/ayula

And I think some of your traversing was off, it didn't descend high enough or something of that nature to get to the sibling, I just re-coded it entirely.

meder
Upvoted. I like the plugin pattern, definitely need to use that more often. And, yes, traversing to the collapsible-item parent, instead of attempting to find a sibling of the immediate parent, circumvents the problem caused by the mismatched </div> in the HTML.
brianpeiris
A: 

You guys are making this sound too hard. Pretty sure this is all you need:

$(document).ready(function() {
    $('.toggle-button').click(function(){
         $(this).parent().next().slideToggle('slow');
    });
});
Jakobud
I actually tried *exactly* that, but only the first div toggled...
phpN00b
A: 

The main problem is that you have mismatched </div>s inside your collapsible-item-title divs. Just remove that and it will fix the toggling. You might also want to add end-slashes to your img tags.

Also I'm guessing that, instead of,

$('.toggle-button').attr('src', '/images/collapse.png');

you meant to have

$(this).siblings('.toggle-button').attr('src', '/images/collapse.png');

Here is the corrected code posted on JS Bin:
http://jsbin.com/iruvo (editable via http://jsbin.com/iruvo/edit)

Lastly, you can make your jQuery code much simpler by refactoring your event handlers into a single function:

function toggleIt() {
  var collapsibleItem = $(this).parents('.collapsible-item');
  var toggleButton = collapsibleItem.find('.toggle-button')
  var currentImage = toggleButton.attr('src');

  toggleButton.attr('src', currentImage === minusIcon ? plusIcon : minusIcon);

  collapsibleItem.find('.togglethis').slideToggle('slow');
}

$('.toggle-button, .item-title-header').toggle(toggleIt, toggleIt);
brianpeiris