Re-binding jQuery Events on AJAX Callbacks

Posted by Jetlogs @ 1:48 pm
Category: jQuery,Web Development

Or the title can be put shortly as: Why doesn’t my jQuery events work after an AJAX callback?

Lets create a very simple example jQuery script which simply changes a list’s class on hover:

We’ll assign red as the hover color:

<style type="text/css">
.hover
{
	color: #f00;
}
</style>

Then add the jQuery hover() event to toggle/change the list’s class when the mouse hovers over the list. This is how the javascript code will look like inside the document.ready() function:

$("li").hover(
function()
{
	$(this).toggleClass("hover");
},
function()
{
	$(this).toggleClass("hover");
});

To simplify things, I’ve added a sample AJAX callback function which is triggered by a button:

<div id="container">
<ul><li>This list should trigger the hover event</li></ul>
The AJAX callback loads here...
</div>

<input type="button" id="btnLoad" value="Click me to change list">

Our javascript would then look like this:

$(document).ready(function()
{
	$("li").hover(
	function()
	{
		$(this).toggleClass("hover");
	},
	function()
	{
		$(this).toggleClass("hover");
	});

	$("#btnLoad").click(function()
	{
		$.ajax(
		{
			url: "samplelist.html",
			success: function(html)
			{
				$("#container").empty().append(html);
			}
		});
	});

});

The completed demo of the code above can be found here:
jQuery: Non-working Callback Events

When you click the button and load the AJAX callback, notice that the hover() event no longer triggers? This problem is also applicable to other jQuery events suck as click(), blur(), and others.

Lets take a look at what happens:

When we set the hover event for our lists, what is actually does is that it adds a javascript event and its matching function for each of the matched elements. So upon loading of the page, this is what happens to our list. It turns from:

<li>...</li>

to:

<li onmouseenter="function()..." onmouseleave="...">...</li>

But what we forgot is that is that when we loaded the AJAX callback, it still doesn’t have the event binded to the element:

<li>AJAX callback loaded me</li>

So our hover event doesn’t trigger anymore because our AJAX callback doesn’t have one in the first place!

So how do we fix this? It quite simple. We just need to rebind the hover event to our AJAX callback. Running this function again:

$("li").hover(
function()
{
	$(this).toggleClass("hover");
},
function()
{
	$(this).toggleClass("hover");
});

will make our hovers work again. But to make it even easier on our part, we can simply move all the initial bindings into a separate function and just call that on our document.ready() and AJAX success functions.

Remember, we don’t have to move all the bindings, just the ones that are affected by the AJAX callback. In this example’s case, we only need the binding for the hover event on our list.

By doing this, our javascript will now look like this:

$(document).ready(function()
{
	initBinding();

	$("#btnLoad").click(function()
	{
		$.ajax(
		{
			url: "samplelist.html",
			success: function(html)
			{
				$("#container").empty().append(html);
				initBinding();
			}
		});
	});

});

function initBinding()
{
	$("li").hover(
	function()
	{
		$(this).toggleClass("hover");
	},
	function()
	{
		$(this).toggleClass("hover");
	});
}

Now we no longer have to worry why our Javascript events and validations don’t work on AJAX callbacks.

The working demo of this page can be found here:
jQuery: Re-binding jQuery Events on AJAX Callbacks

Or if you want to download all the source codes, you can follow the link below:
Download jQuery: Re-binding jQuery Events on AJAX Callbacks Source


26 Comments »

26 Comments to “Re-binding jQuery Events on AJAX Callbacks”

  1. RamaJin
    1

    any idea on how to enable javascript events on an innerHTML response?

  2. Jetlogs
    2
    Author Comment

    For innerHTML its basically the same, after modifying the innerHTML, try to rebind their events again.

    Just call the rebind function after your innerHTML directive

  3. RamaJin
    3

    how will i know the rebind functions? thickbox have tb_init, how about jquery?

  4. Jetlogs
    4
    Author Comment

    what rebind basically means is that you need to re-call the trigger javascript functions for the newly loaded DOM.

  5. RamaJin
    5

    now how will i trigger the $(document).ready(function(){ } or even the $(‘#CheckboxAll’).click(function(){} ?

  6. Jetlogs
    6
    Author Comment

    in your case:

    $(document).ready(function()
    {
    initBinding();
    }

    function initBinding()
    {
    $(‘#CheckboxAll’).click(function(){…});
    }

    function changeInnerHtml()
    {
    …innerHtml = ”;
    initBinding();
    }

  7. RamaJin
    7

    awww, so i have to put initBinding in every jquery i make :(

  8. Jetlogs
    8
    Author Comment

    nope, just the elements affected by the added/replaced DOM

  9. Charles
    9

    Thank you, thank you, thank you, thank you, thank you!

  10. Martin
    10

    Thank you!!!

  11. Mark Richards
    11

    The past tense of “Rebind” is “Rebound” not “Rebinded” …

  12. William W.
    12

    Thanks a ton man! I can’t believe my search actually found an answer. You rock!

  13. Nicolai Schlenzig
    13

    Hi,

    I found this article after spending some time investigating the same problem described above.

    However – my code is somewhat larger and more complex, so I didn’t really feel like refactoring too much before looking around some more.

    This lead me to find jQuery.live() which was added in 1.3.x.

    I’m using it now, and it works wonders! :)

    http://docs.jquery.com/Events/live

    But thanks for pointing me in the right direction and making me able to ask Google the correct question: “jquery copy events”. I first started out by trying “jquery lost/forgot event/action” and the like ;)

    Cheers

    – Nicolai

  14. Oz
    14

    rebinding is not the best solution.
    for most cases, using jQuery.live() instead of jQuery.bind() will mean that you only have to bind the event once, and it will apply also after ajax calls.

    jQuery.live() is only available from version 1.3.x
    if you are using older version please checkout a pluging called liveQuery (or simply upgrade :) ).

  15. Coufu
    15

    Just what I needed. Thanks!

  16. Matt
    16

    This just saved my life. Thank you. Stuff like this is so daunting to newbies to jquery (like me). I spent like 4 hours trying to figure out how to rebind. “live” wasn’t working, “bind” was confusing as hell, but storing your animations as a function and using a callback from .load = easy. Even though you’re using .ajax, this led me in the right direction. I can sleep. Thanks again!

  17. ash
    17

    rebinding an event by placing it in a function and calling the function from an ajax callback works for some users but doesn’t seem to be working for others. Javascript is enabled in the browser and it does not seem to work in boht FF and IE on few computers. Unable to figure out why this works for some users but doesn’t seem to be working for others.

  18. Dominic Watson
    18

    Re-binding jQuery Events on AJAX Callbacks
    ——————————————–

    Or the title can be put shortly as: Why doesn’t my jQuery events work after an AJAX callback?

    Shortly? that title is longer than the actual title of this article :P

  19. arash
    19

    cool
    sweet
    thx thx thx
    thnx thx thx

  20. content management
    20

    very good, thanks for the above.

  21. digital publishing solutions
    21

    very good. thanks for the above.

  22. dima
    22

    Thank you! This saved me a ton of headache and time!

  23. Jayesh
    23

    This post is a great help for this problem..

    http://jquerybyexample.blogspot.com/2010/07/jquery-does-not-work-properly-after.html

  24. Newo
    24

    Thanks Man!!!!

  25. OnLine
    25

    Thank you for this article.
    It helped me to register jquery events on a form loaded via Ajax.

  26. DevlshOne
    26

    As a reminder, if you are cloning an element, re-binding is not necessary as you can carry the bindings over using the value ‘true’ in the .clone() event…. $e.clone(true) will clone the element with all the bindings intact!

RSS Comment Feed Comments RSS |trackback TrackBack URI

Leave a comment

  • Archives

  • Donations

  • Social Bookmarks

  • Jetlogs.org
    Some Rights Reserved 2007
    Creative Commons License