zer0
zer0

Reputation: 5017

jQuery event won't work after ajax call

I have an expand/collapse block for which I have written a function as such:

function expandCollapse() {
    var $btnShowHide = $('.btn-show-hide');
    var $contentShowHide = $('.content-show-hide');

    contentToggle();

    $btnShowHide.each(function() {
        $(this).on('click', function() {
            var i = $btnShowHide.index(this);
            $contentShowHide.eq(i).slideToggle('fast');
            $contentShowHide.eq(i).toggleClass('collapsed');

            if ($contentShowHide.eq(i).hasClass('collapsed')) {
                $('.icon-show-hide', this).text('+');
            } else {
                $('.icon-show-hide', this).text('-');
            }
        });
    });

    function contentToggle() {
        $contentShowHide.each(function() {
            var i = $contentShowHide.index(this);
            if ($(this).hasClass('collapsed')) {
                $(this).hide();
                $('.icon-show-hide', $btnShowHide.eq(i)).text('+');
            } else {
                $('.icon-show-hide', $btnShowHide.eq(i)).text('-');
            }
        });
    }
}

and I call this function on $(document).ready. This works fine but fails when there is an ajax call done in the page. So, I looked at this answer and called the function again on ajax success, but this makes the behaviour odd (like, clicking on the btn once will collapse and expand the content multiple times for a single click). Any ideas on how I can get around this?

Sample HTML (there could be multiple of these on one page):

<h3 class="btn-show-hide">
 <span class="icon-show-hide"></span>
 <span>Title</span>
</h3>
<div class="content-show-hide collapsed">
//Stuff
</div>

Upvotes: 0

Views: 312

Answers (2)

zer0
zer0

Reputation: 5017

Apparently the solution is to set an off before listening to the event. So, it would just be

 $btnShowHide.each(function() {
        $(this).off('click').on('click', function() {
            var i = $btnShowHide.index(this);
            $contentShowHide.eq(i).slideToggle('fast');
            $contentShowHide.eq(i).toggleClass('collapsed');

            if ($contentShowHide.eq(i).hasClass('collapsed')) {
                $('.icon-show-hide', this).text('+');
            } else {
                $('.icon-show-hide', this).text('-');
            }
        });
    });

This fixed my problem but I have no idea why this works.

Upvotes: 1

A.O.
A.O.

Reputation: 3763

Unless you are removing/replacing all instances of $('.btn-show-hide'); and $('.content-show-hide'); before each call to expandCollapse() you are re-adding the same event handler over and over, which I suspect is the cause of the multiple collapse/expands.

$btnShowHide.each(function() {
        $(this).on('click', function() {
            var i = $btnShowHide.index(this);
            $contentShowHide.eq(i).slideToggle('fast');
            $contentShowHide.eq(i).toggleClass('collapsed');

            if ($contentShowHide.eq(i).hasClass('collapsed')) {
                $('.icon-show-hide', this).text('+');
            } else {
                $('.icon-show-hide', this).text('-');
            }
        });
    });

The above code adds a new event handler each time you call expandCollapse(), perhaps it should be placed outside this function and only executed once...

Upvotes: 0

Related Questions