user1227914
user1227914

Reputation: 3514

jquery Ajax call seems to work only once?

I have a bunch of images that people can click on a heart on top to "love" or "unlove". I figured out how to make it work with Ajax / jQuery but for some reason, it only works once.

The image underneath has a link to it, too ...so I need to do a preventDefault on the heart div overlayed on top. Which again, works once.

The structure is like:

<a href="...">
<div class="image">
  <img src="...">
    <div class="love-response love"></div>
</div>
</a>

So if they click the heart, it works correctly ...but if they click it again, it then goes to the link of the image underneath. If they however reload the page after clicking the link, they can again click it and it works to unlove it. But then again, if they click again without reloading it goes to the image underneath again.

I think it has to do with the fact that the json data is returned and then updates the content, but on further clicks it somehow doesn't do a preventDefault anymore.

What could be wrong here?

jQuery(document).ready(function($){
$('.love').click(function (e) {
  e.preventDefault();
  var id = $(this).data("id");
  $("#love-response-" + id).hide();
  $("#love-waiting-" + id).show();
  $.ajax({
    url: "https://www.domain.com/love.php?id=" + id,
    type: "GET",
    dataType: 'json',
    success: function(json) {
        if(json.valid == 1) {

            $("#love-waiting-" + id).hide();
            $("#love-response-" + id).replaceWith(json.message);
            $("#love-response-" + id).show();

        }
        else {
            $("#love-waiting-" + id).hide();
            $("#love-response-" + id).replaceWith(json.message);
            $("#love-response-" + id).show();
        }
    },
    error: function (xhr, ajaxOptions, thrownError) {

        $("#love-waiting-" + id).hide();
        $("#love-response-" + id).html('ERROR');
    },
    timeout: 15000
  });
});
});

The json is pretty basic. It's either:

{
"valid":"0",
"message":"<div class=\"love-response love\" id=\"love-response-782\" data-id=\"782\"><span class=\"icon love-black\"><\/span><\/div>"
}

or

{
"valid":"1",
"message":"<div class=\"love-response love\" id=\"love-response-782\" data-id=\"782\"><span class=\"icon love-red\"><\/span><\/div>"
}

I really feel like the problem is somehow with the preventDefault not executing anymore after it received the response back from json.

Upvotes: 2

Views: 5404

Answers (2)

David
David

Reputation: 218798

When you do this:

$('.love').click(function (e) {

You're attaching that function to the click event of those matched elements. Not to the selector, but to the elements which are selected at that time. Then when you do this:

$("#love-response-" + id).replaceWith(json.message);

You remove those elements and add new ones. Those new ones don't have click events associated with them. The old ones did.

You can correct this by using event delegation. What this means is binding to the click event of some common parent element and filtering the origin of the click based on some selector. At its simplest, it would look like this:

$(document).on('click', '.love', function (e) {
    // your code
});

Upvotes: 3

john Smith
john Smith

Reputation: 17906

delegate the click event handler to sth. thats always in your DOM as the .love is manipulated dom (loaded via ajax) so it triggers only once because the element was not there when the script was executed

simply change

 $('.love').click(function (e) {

to

 $(document).on('click','.love',function (e) {

Upvotes: 10

Related Questions