javascriptjqueryajaxjquery-events

Jquery Event bound twice after ajax call


I want to bind an event on elements which are dynamically created by ajax call. Some elements are already present and an event is binds with them when page loads. But when new elements created after ajax call then new elements lose their bindings.

I searched and found a very good solution. Jquery Event won't fire after ajax call

In this question "Jason Fingar" presented two solution to fix this

Here is the first solution he presented

"1) Encapsulate your "binding" code and call it both on page load and immediately after the element in question gets added back to the page. For example:"

$(document).ready(function(){
// bind event handlers when the page loads.
bindButtonClick();
});

function bindButtonClick(){
$('.myClickableElement').click(function(){
    ... event handler code ...
});
}

function updateContent(){
$.ajax({
    url : '/ajax-endpoint.php',
    data : {'onMyWay' : 'toServer'},
    dataType : 'html',
    type : 'post',
    success : function(responseHtml){
        // .myClickableElement is replaced with new (unbound) html 
     element(s)
        $('#container').html(responseHtml);

        // re-bind event handlers to '.myClickableElement'
        bindButtonClick();  
    }
});
}

What problem I am facing? The event is bind with the new elements successfully but for the old elements or the elements which are loaded on page load, the event is bound twice. What is the problem with this?


Solution

  • jQuery doesn't check if an event listener is already bound to an element before binding listener for the same event. In your code, .myClickableElement selects all such elements, and for existing elements, duplicate listeners will be added.

    By unbinding the event listeners first

    One way you can fix this is to remove the listener first, and then bind it again. In this way, it will exist once for each target element.

    function bindButtonClick(){
      $('.myClickableElement').off('click').on('click', function(){
        ... event handler code ...
      });
    }
    

    By using event delegation on parent element

    Another (but effective) way is to use event delegation for child elements. I don't know much about your HTML, but you can do this on the parent element (.parent here is the parent for all .myClickableElement elements):

    $('.parent').on('click', '.myClickableElement', function() {
      ... event handler code ...
    });
    

    This will enable event binding for those elements as well, which are not present in the DOM when this code executes. So this will be a generic solution for your problem, and you won't need to bind the listeners when the AJAX completes.