Click doesn’t work after AJAX load – jQuery
If you use AJAX on your website, beware that events like click, submit, hover might not work if you don’t attach them properly. I will be using click event to describe the problem, but all of this applies to most events in jQuery.
Problem
Let say I have an item with a title and hidden description. The description is shown on click with this code:
$('.toggle-item').click(function(e){
e.preventDefault();
$(this).parent().next('.category-item-content').toggle();
});
I load new items without reloading my page with AJAX with this code:
$('#category-wrapper').load(link.attr('href'));
When I load a website everything works fine until I load new items or replace old once. Ajax still works fine but toggle for item description doesn’t work anymore. WAT? Check this jsfiddle below for working example of that problem.
Note, you can change tabs and view JS and HTML that was used for this example.
Solution 1
Click event is attachted to existing elements on page load. The key word here is “existing”. When we load something with AJAX we manipulate DOM. We are placing totally new element that didn’t exist when page loaded. So what we need to do is to attach that event after placing new content. If you use .load()
function (like in my example) you just need to repeat $('.toggle-item').click()
in the callback function:
$('#category-wrapper').load(link.attr('href'),function(responseText, textStatus, XMLHttpRequest){
$('.toggle-item').click(function(e){
e.preventDefault();
$(this).parent().next('.category-item-content').toggle();
});
});
that way, we are also attaching click event to newly added elements.
We could of course move $('.toggle-item').click()
outside callback and make it as a function to not repeat ourselves (for better maintenance and all, you know, right? DRY?), but I want you to understand the why and how.
If you use .ajax()
function instead of .load()
just attach event in .done()
part (success hook) of AJAX call. Mu updated jsfiddle with solution numero uno below:
Solution 2
What if we don’t want to attach event every time AJAX is called? Is there any other, more “global” solution? Of course there is. We can use .on()
function. Yay!
But wait!
Isn’t .click()
same as .on('click')
? Yes it is. But here’s a fun part – we can delegate event.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time
So instead of attaching click event on completed ajax we just attaching it more errm “globally”:
/* Toggle category item */
$('#category-wrapper').on('click','.toggle-item',function(e){
e.preventDefault();
$(this).parent().next('.category-item-content').toggle();
});
We could attach it to $('body').on('click','.toggle-item',function(){});
but:
For best performance, attach delegated events at a document location as close as possible to the target elements. Avoid excessive use of document or document.body for delegated events on large documents.
Remember – delegated event must be attached to the element that exist on the page at the time your code makes the call and doesn’t change during ajax calls – some kind of wrapper. This is the reason why people are attaching it to body, but if it’s possible select the element that is closer to targeted element.
On a side note in the earlier versions of jQuery instead of .on()
we used .live()
or .delegate()
functions.
This is a very well thought out and thorough explanation . Thanks a Lot.
Thanks a lot, excellent explanation!!
Thank You So much….You saved my day!
Wonderful, it help me a lot.
Merci pour ces explications bien détaillées
Thank you so much. The explanations are wonderful.
Solution 2 saved me. First I couldn’t delete items after adding 1 now I can because I first used .click() instead if .on(“click”). You’re lifesaver!
Thanks a lot. It saves my day.
Hello, thanks. Nice trick, but how do you re initialize non event driven Javascript functionalities. All predefined non event driven Javascript functions stop working after the refresh.
You have to rewrite those parts to be able to re initialize them. There is no other way.
This helped me a lot. Thanks for describing your explanation! :)
Thank you so much!
Thank you very much !
You are my hero!! :)
Thanks Eliza. I load a lot of bootstrap modals via load() method and sometimes the button close wasn’t working.
I changed the way I call it using on.
It’s working very well now.
Thanks a lot. This really really helped me. Your style of explanation is wonderful. Thanks again!
Thak you!, even now it’s so usefull. Great Article
This sintax work after run ajax.
$(document.body).on(‘click’, ‘#btn_send_pass’, function(e){
e.preventDefault();
….
});
Buen artículo!!!
Thankx aloT .. (Y)
hello nice tutorial, i have some problem with ajax loading..
var mycustom = function () {}
mycustom.prototype.loadajax = function(){
$.ajax({
url: “example.php”
});
}
mycustom.prototype.second = function(){}
it’s working fine but after loading example.php mycustom function stop working for runing second function
could you please help me to solve the problem.
thanks
You should have some “onComplete” or similar function in ajax where you should call second. If you run second BEFORE related html content is present on page, it won’t work.
Thank you!!!! I know how to use on()
you killed the game with this article. good job maddam’
Thank you a LOT! You saved my day ;)
Best explanation, thank you very much.
Your explanation has solved many of my problems
Your solution rocks
Clear explanation. Worked for me. Thanks!
I just KNOW that the solution to my problem is right here, but my brain has completely stopped working. I used the tutorial linked below to write a simple shopping cart for my site. It works AWESOME — but of course the javascript uses ‘click’ and any new actions launched by the Ajax-generated code won’t work. I’m trying to use your 2nd solution to edit my javascript code, but I can’t get it to work. Is there possibly a missing close-parenthesis in this line? $(‘#category-wrapper’).on(‘click’, ‘.toggle-item’, function(e) { The on( begins with an open-parenthesis but before the { there is… Read more »
The code is ok, there is nothing missing. You can check the code in JS tab in second example https://monosnap.com/file/yMUpVVo2Wt2ZAy1ZmamCQ7UTPQ6BaA I don’t see anything loaded by ajax on your page except for adding to cart. Try attaching the click to more global element like $(‘body’).on(‘click’,’.your-class’,function(e){});
Your brief but still complete explanation about the argument helped me to understand more deeply the issue and how was the best way to solve it, thank you very much Eliza!
Hi Eliza, this it very helpful. Thank you
Hi Eliza,
Thanks a lot for your explanation, it really helped me to understand the issue.
Unfortunately I still struggle with $(“form.my_form”).on(‘submit’, function(event), it seems after I do a ajax reload of my content, it doesn’t recognize the submit anymore.
Maybe you have an idea, what else I could try.
$(document).on(‘click’, ‘your_button_class’, function({
‘your code’
});
thank you man, helpful a lot!!!!
hello Eliza,
thank you for this solutions. I need to use after() method with .on() method
please help me.
thanks
hey, wielkie dzięki, sprytne drugie rozwiązanie
Hello Elisa,
i dont know where i do the fail.
could you help me?
Best Regards
$(“#m_reflink”).click(function(e){
e.preventDefault();
$(this).parent().next(‘#main’).toggle();
$(“#main”).animate({opacity:”0″, filter:”alpha(opacity=0)”}, 400, function(){
$(“#main”).load(“pages/reflink.php”, function(){
$(“#main”).animate({opacity:”1″, filter:”alpha(opacity=100)”}, 400);
});
});
});
Eliza Witkowska, Thank you for this article. It helped me much
Hey Eliza.
What if none of .on, .live, .delegate works?
Then you’re doing something wrong, but without a code sample there is no way to tell what.
Thanks for sharing this useful tip! I was able to fix an issue in a personal project with your example code.
Thank You!!
Thank you Eliza, well explained :)
Excellent
Thank you.i am searching such type of solution from two days.
Thanks Eliza, You post saved me a lot of headache.
Good solution. works for me. Thanks a lot..
It works! Thanks. But if I have some attributes in object which is loaded by ajax, how can I get this value? In my case I have #show-people-goods-block as a parent object and some buttons with class .want-to-have which were loaded by ajax. Each of this button has an attribute gid. I need to get the data from this attribute only in that button which was clicked. The code is :
$(document).ready(function() {
$('#show-people-goods-block').on('click', '.want-to-have',function(e) {
e.preventDefault();
var gid = $(this).attr("gid").val();
});
});
Please help)
If you have data attribute then just use a .data() for that.
var gid = $(this).data('gid');
and thats it. Read more about it here https://api.jquery.com/data/
Dzięki ;]
$(document).on(“click”, “class-name”, function() {
// — do something — //
});
[…] I found a very good Blog explaining how i could fix it: https://aiocollective.com/blog/click-doesn-t-work-after-ajax-load-jquery/ […]
Hi Eliza.
Could you help me with my code ?
I have button to go to “See more videos”.
Work well and loads ajax content, but button that i generate inside ajax with new code don’t work.
What i need change inside to make it work ?
More Videos – CAcQAA
And
$(function() {
//More Button
$(‘.more’).on(“click”, function()
{
var ID = $(this).attr(“id”);
alert(ID);
if(ID)
{
$(“#more”+ID).html(”);
$(“#more”+ID).remove();
$.ajax({
type: “POST”,
url: “Ajax_more.asp”,
data: “pageToken=”+ ID+”&DataUltimo=”,
cache: false,
success: function(html){
var conteudo = html.split(‘||’);
$(“div#updates”).append(conteudo[0]);
$(“#MaisVideos”).html(conteudo[1]);
}
});
}
else
{
$(“.morebox”).html(‘The End’);
}
return false;
});
});
Eliza can you helpe me to figure this out, I have three dropdownlist’s, they don’t work after i use ajax: here is the ajax that load: function hideLoader(){ $('#clienteFields').removeClass('loader-container'); } //Esta funcion es utilizada para habilitar y deshabilitar los campos de empresa al momento de seleccionar del dropdown del tipo de cliente $('#select_tipoCliente').on('change', function(e){ var id = document.getElementById('idCliente').value; var tipo = document.getElementById('select_tipoCliente').value; $('#clienteFields').addClass('loader-container'); $.ajax({ url: 'modulos/info_cliente/funciones/ajax_callback.php', type: 'POST', data: { func: 0, idCliente: id, tipoCliente: tipo }, success: function(datas){ setTimeout(hideLoader, 1000); datas = datas.trim(); if(datas){ $('#clienteFields').html(''); $('#clienteFields').html(datas); $( ".date-picker" ).datepicker({ autoclose:true, changeMonth: true, changeYear: true, maxDate: 0, dateFormat: 'yy-mm-dd' });… Read more »
Just change functions like
$('#drop_departamento').change(function(){
to
$('body').on('change','#drop_departamento',function(){
Thank you so much Eliza, works like a charm :)
What if I want to get or select an element which is loaded by ajax? Like we getElementById normally. I couldn’t find any solution for this.
If you use .on() with the more “global” selector like:
$('body').on('click','your-selector',function(){
//code here
});
it will work. It’s called delegation. Read it here http://api.jquery.com/on/#direct-and-delegated-events