gwalshington gwalshington - 2 months ago 6
Ajax Question

Why does this function console.log 20 times instead of once?

In application.js, I have all the 'topics' compiling on the page from an ajax call, and then when one is clicked, all the information appears on the screen. Everything works great in development, but in production I get a 500 server error.

In trying to debug this, I noticed that the console is logging 20 times with the .onclick call. Why is this happening, and does it have any reason why it is returning a 500 error in production (heroku)?

I put ** ** around the 3 console.logs where this is happening.

if(window.location.pathname === "/topics") {
$('.actions').click(function(e) {
console.log("submit");
})

$.ajax({
url: '/topics',
dataType: 'json',
type: 'GET',
success: function(result) {
console.log(result);
for(var i = 0; i < result.length; i++) {
var title = result[i].title;
var level = result[i].level;
var id = result[i].id;
var favlink = '/topics/' + id + '/favorite';
var link = '/topics/' + id;
var topicInfo = {title: title, link: link};
var template = compiledTopics(topicInfo);
$('.topic-wrapper').append(template);



$('.listing-topics, .favorite-topic-title').click(function(e){
e.preventDefault();
if( $(this).hasClass("favorite-topic-title")) {
var heartClass = "favorited_heart_icon"

}
else if( $(this).hasClass("listing-topics")) {
var heartClass = "unfavorited_heart_icon";
$('html, body').animate({ scrollTop: 0 }, 'fast');

}
**console.log(this);**
$.ajax({
url: this,
dataType: "json",
type: 'GET',
success: function(result) {


var id = result.id;
var title = result.title;
var body = result.body;
var level = result.level
**console.log(level);**

//SHOW TOPIC and FAVTOPIC AS POPUP WHEN CLICKED

//Add proper favorite icon.
var favlink = '/topics/' + id + '/favorite';
**console.log(heartClass);**
var topicInfo = {title: title, body: body, heartClass: heartClass};
var template = compiled(topicInfo);



$('.topic-wrapper').append(template);

//CLOSE TOPIC WHEN CLICKING THE GREY SURROUNDING BOX - topicClose
$('.topicClose').click(function(e) {
$('.topicClose').css("display", "none");
$('.show_topic').css("display", "none");
})

//FAVORITE TOPIC
//ADD TO FAV TOPICS LIST

$(".unfavorited_heart_icon, .favorited_heart_icon").click(function(e) {
e.preventDefault();
//onclick - change colors of heart

if ( $(this).hasClass("favorited_heart_icon")) {
$(this).removeClass("favorited_heart_icon");
$(this).addClass("unfavorited_heart_icon");
urlEnd = '/unfavorite';
}
else if ( $(this). hasClass("unfavorited_heart_icon")) {
$(this).removeClass("unfavorited_heart_icon");
$(this).addClass("favorited_heart_icon");
urlEnd = '/favorite';
}
// console.log('/topics/favorite/' + id);
$.ajax({
url: '/topics/' + id + urlEnd,
type: 'POST',
success: function(result) {
location.reload();
}
})

});



},
error: function(err) {
console.log(err);
}


})
});


};

},
error: function(err) {

}
});


at the bottom of same js file:

var listingSource = $("#listingTopics").html();
var compiledTopics = Handlebars.compile(listingSource);


topics handlebar template:

<script id="listingTopics">
<div>
<a href={{link}} class="listing-topics">{{title}}</a>
</div>
</script>


Thanks in advance!

EDIT**

I've also tried:

$.ajax({
url: '/topics',
dataType: 'json',
type: 'GET',
success: function(result) {
for(var i = 0; i < result.length; i++) {
var title = result[i].title;
var level = result[i].level;
var id = result[i].id;
var favlink = '/topics/' + id + '/favorite';
var link = '/topics/' + id;
var topicInfo = {title: title, link: link};
var template = compiledTopics(topicInfo);
$('.topic-wrapper').append(template).click(function(e) {
e.preventDefault();
console.log($(this))
});
};
},

Answer

I'm guessing that results is roughly 20 items. When you're creating your click event handler within your for loop, your binding it to a classes .listing-topics, .favorite-topic-title. When you click on the element it goes ahead and fires the click events (20 times since you have 20 items in you results array). I suspect this is what is happening but need to see it to verify. Do you have a JSFiddle?

To fix this, change up the way you're binding your event handler. You need to scope it to a specific instance of a class or element in order for the events to fire individually instead of all at once.

SAMPLE SCENARIO

var results = ["1", "2", "3"];


//How you're currently doing it
for (var i = 0; i < results.length; i++) {
    $('#container').append($('<div />', {text: results[i], class:'test-class'}));
  $('.test-class').click(function () {
  console.log($(this).text());
  });
}

//Solution
for (var i = 0; i < results.length; i++) {
    $('#container').append($('<div />', {text: results[i], class:'test-class'}).click(function () {
  console.log($(this).text());
  }));
}

I have created a simple reproduction of this scenario (aligning with yours) to help better explain what's happening. Basically, instaed of binding all your events within one go (by class), bind it to the element as you're creating it.

JSFIDDLE: https://jsfiddle.net/ncrxekmq/

UPDATED CODE

if(window.location.pathname === "/topics")  {
    $('.actions').click(function(e) {
        console.log("submit");
    })

    $.ajax({
            url: '/topics',
            dataType: 'json',
            type: 'GET',
            success: function(result)   {
                console.log(result);
                for(var i = 0; i < result.length; i++)  {
                    var title = result[i].title;
                    var level = result[i].level;
                    var id = result[i].id;
                    var favlink = '/topics/' + id + '/favorite';    
                    var link = '/topics/' + id;
                    var topicInfo = {title: title, link: link};
                    var template = compiledTopics(topicInfo);
                    $('.topic-wrapper').append(template);


                //use $.each(index, item) to loop through all of your elements and bind the click event individually instead of in one go.
                $('.listing-topics, .favorite-topic-title').each(function (index, item) {
                    $(item).click(function(e){
                        e.preventDefault();
                        if( $(this).hasClass("favorite-topic-title"))   {
                            var heartClass = "favorited_heart_icon"

                        }
                        else if( $(this).hasClass("listing-topics"))    {
                            var heartClass = "unfavorited_heart_icon";
                            $('html, body').animate({ scrollTop: 0 }, 'fast');

                        }
                        **console.log(this);**
                        $.ajax({
                            url: this,
                            dataType: "json",
                            type: 'GET',
                            success: function(result)   {


                                var id = result.id;
                                var title = result.title;
                                var body = result.body;
                                var level = result.level
                                **console.log(level);**

                                //SHOW TOPIC and FAVTOPIC AS POPUP WHEN CLICKED

                                //Add proper favorite icon.
                                var favlink = '/topics/' + id + '/favorite';    
                                **console.log(heartClass);**
                                var topicInfo = {title: title, body: body, heartClass: heartClass};
                                var template = compiled(topicInfo);



                                $('.topic-wrapper').append(template);

                                //CLOSE TOPIC WHEN CLICKING THE GREY SURROUNDING BOX - topicClose
                                $('.topicClose').click(function(e)  {
                                    $('.topicClose').css("display", "none");
                                    $('.show_topic').css("display", "none");
                                })

                                //FAVORITE TOPIC
                                //ADD TO FAV TOPICS LIST

                                $(".unfavorited_heart_icon, .favorited_heart_icon").click(function(e)   {
                                    e.preventDefault();
                                    //onclick - change colors of heart

                                    if ( $(this).hasClass("favorited_heart_icon"))  {
                                        $(this).removeClass("favorited_heart_icon");
                                        $(this).addClass("unfavorited_heart_icon");
                                        urlEnd = '/unfavorite';
                                    }
                                    else if ( $(this). hasClass("unfavorited_heart_icon"))  {
                                        $(this).removeClass("unfavorited_heart_icon");
                                        $(this).addClass("favorited_heart_icon");
                                        urlEnd = '/favorite';
                                    }
                                    // console.log('/topics/favorite/' + id);
                                    $.ajax({
                                        url: '/topics/' + id + urlEnd,  
                                        type: 'POST',
                                        success: function(result)   {
                                            location.reload();
                                        }
                                    })

                                });



                            },
                            error: function(err)    {
                                console.log(err);
                            }


                        })
                    });
                });

            };

        },
        error: function(err)    {

        }
    });