2

I have a page loading content with the waypoints infinite scroller plugin.

On the success of the AJAX call and after DOM elements are added, a callback runs to re-initilize javascript functionality, like carousels, buttons and other animation.

On the first AJAX call, buttons tasked with toggling work properly. On the next AJAX call, the new DOM items work, but the previous buttons now execute toggles twice when clicked. On the third call, original items now run three times, the second items twice and the new ones once, so on and so fourth, continuing to compound as AJAX content is called.

How can I isolate the callback to not affect the previously loaded content, or, is there a way to set a global state for the JS, so that I don't need the callback each time?

Some pseudo code:

$('.infinite-container').waypoint('infinite', {

    onAfterPageLoad: function() { 

        //Carousel options     
        $('.carousel-container').carousel({
            options: here,
            ....
        }); 

        //Button Toggles
        $('.button').click(function(){

            var self = $(this); 

            $(this).siblings('.caption').animate({ 

               height: 'toggle'

               }, 200, function() {

                 // Callback after animate() completes.
                 if(self.text() == 'Hide Details'){

                   self.text('Show Details');

                 } else {

                   self.text('Hide Details');
                 }
            }); 
        }); 

     }   
});    

Edit: Thanks everybody. All the answers lead me to differing but appropriate solutions. The selected was picked as it's a great collection of all the suggested issues and worth the read.

PHPeer
  • 649
  • 1
  • 6
  • 18

4 Answers4

2

Check out this answer. I think it is the same situation you are having and has a solution:

Best way to remove an event handler in jQuery?

Community
  • 1
  • 1
nikeaa
  • 1,037
  • 7
  • 17
2

You are attaching a new click handler each time that block of code gets executed. The result is multiple click handlers being bound to your button. Use jQuery's unbind: http://api.jquery.com/unbind/ to remove any click handler(s) before adding a new one:

$('.infinite-container').waypoint('infinite', {

    onAfterPageLoad: function() { 

        //Carousel options     
        $('.carousel-container').carousel({
            options: here,
            ....
        }); 

        // Un-bind click handler(s)
        $('.button').unbind('click');

        //Button Toggles
        $('.button').click(function(){

            var self = $(this); 

            $(this).siblings('.caption').animate({ 

               height: 'toggle'

               }, 200, function() {

                 // Callback after animate() completes.
                 if(self.text() == 'Hide Details'){

                   self.text('Show Details');

                 } else {

                   self.text('Hide Details');
                 }
            }); 
        }); 

     }   
});
renab
  • 373
  • 2
  • 9
2

Try bind only once click event to button. Of course you can use on instead of live.

$('.button').live('click', function(){
    var self = $(this); 
    $(this).siblings('.caption').animate({ 
       height: 'toggle'
       }, 200, function() {
         // Callback after animate() completes.
         if(self.text() == 'Hide Details'){
           self.text('Show Details');
         } else {
           self.text('Hide Details');
         }
    }); 
}); 
$('.infinite-container').waypoint('infinite', {
    onAfterPageLoad: function() { 
        //Carousel options     
        $('.carousel-container').carousel({
            options: here,
            ....
        }); 
        //Button Toggles
     }   
});
Ikrom
  • 3,635
  • 4
  • 42
  • 68
  • 1
    +1 avoid having to remove existing click handlers by only adding the click handler once – renab Apr 29 '13 at 18:29
1
$('.button').click(function(){

You add an event handler to every button that has the class button. When the second button is added then you add it to every ... which means button 1 and button 2. And so on.

Try

$('.button').last().click(function(){
a better oliver
  • 24,069
  • 2
  • 48
  • 59
  • This wouldn't cause clicking any one button to execute the click handler more than once. I believe multiple executions of the the $().click(); are adding multiple click handlers. – renab Apr 29 '13 at 18:27
  • My solution only adds a click handler to the last button. – a better oliver Apr 29 '13 at 18:30
  • My comment was pointing out that adding the click handler to every button with the "button" class would not cause clicking on any one of them to execute multiple instances of the click handler, which is the issue the OP described. If he substituted your code in his function, it would still add multiple instances of the same click handler to one button should it be executed more than once. – renab Apr 29 '13 at 18:34
  • Yeah, I realized what you meant after I've written the comment :D That's right, of course, and I strongly suggest using `container.on("click", ".button")` if possible. It's pseudo code, though, and we don't no if any local variable is referenced from within the event handler. – a better oliver Apr 29 '13 at 18:39
  • Indeed, without seeing the full source it is difficult to pin the direct issue, I have experienced this issue myself in the past and ended up using a combination of callback generators (functions which return a function) and the unbind() method to resolve a somewhat complex handler chain update – renab Apr 29 '13 at 18:44