Question

I can not make this piece of code work:

$("a.expand_all").on("click",function(){
    $(this).text('Hide');
    $('.answer').each(function () {
        $(this).slideDown(150, function () {
            $(this).show();
        });
    });
}, function () {
    $(this).text('Expand');
    $('.answer').each(function () {
        $(this).slideUp(150, function () {
            $(this).hide();
        });
    });
});

I'm trying to collapse expend multiple divs, but nothing happens on click event. I 'm using latest jQuery 1.10.1

Was it helpful?

Solution

It looks to me like you're using jQuery's .on method incorrectly. That method has some overloads, but none of them (sensibly) takes two functions.

If I understand what you're trying to do correctly, you just want to toggle some answer elements when a <a> tag is clicked. What you really need to do is have some way of determining if your answers are expanded or not. There are multiple ways to do that, but I've chosen to use a data element:

<a class="expand_all" href="#" data-collapsed="true">expand</a>
<p class="answer">I'm an answer!</a>
<p class="answer">Another answer</a>

Then your JavaScript can be simplified thusly:

$('a.expand_all').on("click",function(){
    if( $(this).data('collapsed') ) {
        $(this).text('hide').data('collapsed','');
        $('.answer').slideDown(150);
    } else {
        $(this).text('expand').data('collapsed','true');
        $('.answer').slideUp(150);
    }
});

I simplified some of your constructs as well. In particular, in your code:

$('.answer').each(function () {
    $(this).slideDown(150, function () {
        $(this).show();
    });
});

The .each is unnecessary. Just applying a jQuery method is essentially equivalent to calling .each. You rarely need to use .each. So that simplifies to this:

$('.answer').slideDown(150, function () {
    $(this).show();
});

Then, .slideDown shows the element before it starts, so there's no need to call .show a second time. So we can get rid of the callback, simplifying all of this to:

$('.answer').slideDown(150);

You can see all of this in action here:

http://jsfiddle.net/Jammerwoch/sRnkw/5/

Lastly, the reason I asked whether any of your elements are dynamically added is because if they are, the way you are attaching them won't work. That is, the jQuery selectors run once, and then don't get re-run when you add new elements. So you have to be more clever. That's described in the jsfiddle above. Let me know if you need more clarification on that point.

OTHER TIPS

That doesn't look like valid event binding to me, having the two functions there.

HTML - I added a div wrapper for event delegation

<div class="expando_content">
<a class="expand_all" href="#">Expand</a>

    <p class="answer">I'm an answer!</a>
        <p class="answer">Another answer</a>
            <p>Dynamically added "expand more" goes below...it won't work :(</p>
            <div id="thing"></div>
        </p>
    </p>
</div>

JS - moved the toggling functionality inside one function.

$(".expando_content").on("click", ".expand_all", function () {

    if (!$('.answer').is(':visible')) {
        $(this).text('Hide');
        $('.answer').each(function () {
            $(this).slideDown(150, function () {
                $(this).show();
            });
        });
    } else {
        $(this).text('Expand');
        $('.answer').each(function () {
            $(this).slideUp(150, function () {
                $(this).hide();
            });
        });
    }
});

$('<a class="expand_all" href="#">expand more</a>').appendTo($('#thing'));

jsFiddle

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top