What is the reason for this function outputting 20 console.log statements instead of just once?

My application.js file is set up to display all the 'topics' on the page from an ajax call, and when one is clicked, all the information should appear on the screen. Everything works perfectly in development mode, but I encounter a 500 server error in production (heroku).

While trying to troubleshoot this issue, I observed that the console.log is being triggered 20 times with the .onclick call. I'm not sure why this is happening, and if it could be related to the 500 error occurring in production.

I have marked the sections of code where the console.log statements are causing the repetition with ** **.

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 the same js file:

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

Here is the handlebar template for topics:

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

Thank you for any assistance provided!

Edit**

I also attempted the following:

$.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 №1

One effective way to address the issues related to assigning multiple event listeners is by restructuring the code and utilizing a delegate strategy for defining them. By moving the listeners out of loops and handling them differently, you can enhance the performance and organization of your code.

You could consider implementing a solution along the lines of the following conceptual approach:

function handleJSONSuccess(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);
    }
}

function handleJSONError(err){
    console.log(err);
}

if(window.location.pathname === "/topics")  {

    $('.actions').click(function(e) {
        console.log("submit");
    });

    $('.topic-wrapper').on("click", '.listing-topics, .favorite-topic-title', function(e){
        e.preventDefault();

        // Implementation logic goes here

    });

    $('.topic-wrapper').on("click", ".unfavorited_heart_icon, .favorited_heart_icon", function(e) {
        e.preventDefault();

        // Additional implementation details here
        
    });

    $.ajax({
        url: '/topics',
        dataType: 'json',
        type: 'GET',
        success: handleJSONSuccess,
        error: handleJSONError
    });
}

Answer №2

It seems likely that the results array contains approximately 20 items. The issue may be arising from how your click event handler is bound within a for loop to classes

.listing-topics, .favorite-topic-title
. This can result in all click events triggering at once when an element is clicked, as opposed to individually firing for each item. To confirm this theory, sharing a JSFiddle would be helpful.

To resolve this problem, consider modifying how you bind the event handler. It is essential to scope it to a specific instance of a class or element to ensure that each event fires independently rather than simultaneously.

SAMPLE SCENARIO

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


//Current approach
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());
  }));
}

A simulated scenario resembling yours has been constructed to provide further clarity on the situation. Instead of binding all events together (by class), try binding them to elements as they are being created.

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 jQuery's $.each(index, item) method to iterate through elements and bind click events individually instead of collectively.
                $('.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)    {

        }
    });

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The onChange event of the dropdownlist in MVC is not functioning correctly and is not properly triggering the action

Hey everyone, I'm trying to achieve a functionality where changing the selection of a dropdown list will trigger an AJAX call to a specific action with some data being passed. Below is the code I have implemented for this purpose. Despite verifying th ...

VueJS not refreshing DOM after AJAX data modification

Utilizing Vue.js to make changes to my DOM, I have implemented the fetch_data() method. This method attempts to update data.messages to display 'Love the Vue.JS' once the AJAX call is successfully completed. The AJAX call executes successfully a ...

Leveraging the refresh token for obtaining the access token in Office 365's REST API

When attempting to use the refresh token in order to obtain an access token via the office 365 REST api, I utilized the following Jquery ajax request. jQuery.ajax({ url: "https://outlook.office365.com/common/oauth2/token", type: "post", header ...

How can I change the background color of the initial word in a textbox?

In my HTML, I have a text box input. While I am familiar with how to use CSS to set the background color of the entire textbox using background-color, I am wondering if it is possible to specifically target and change the background color of only the first ...

Discover the maximum length of an element in an array using JavaScript

I am trying to determine the length of the longest string in a given array. If the array is empty, the function should return 0. Here is my attempted solution: function getLengthOfLongestElement(arr) { var longestLength = 0; for(var i=0; i< arr.le ...

The comparison between "rxjs-tslint" and "rxjs-tslint-rules" npm packages

Previously, I utilized the rxjs-tslint-rules package to identify RxJS-related issues in my projects. This package was included in the devDependencies section of my projects' package.json files. Now, there is a new rxjs-tslint package that introduces ...

Retrieve vue instance/data from within a filter method

I'm attempting to access the data of a Vue instance within a filter function as shown below. JS:- new Vue({ data:{ amount: 10, exchangeRate:50 }, el:"#app", filters:{ currency: function(amount){ console.log(this); ...

Interactive game created using JavaScript input

I've scoured the internet for guidance on creating a text-based game that utilizes user input, but all I come across are tutorials focusing on button interactions. What I envision is triggering different responses based on specific user inputs. For i ...

What is the process for disabling the CSS module feature in Next.js?

In Next.js, Global CSS can only be imported in _App.js. However, importing global CSS in every component is not allowed, so we have to use CSS modules to comply with this restriction imposed by Next.js. Currently, I am in the process of migrating a large ...

AngularJS controller function fails to trigger

I have three directives, "parenta", "parentb", and "childb". The first two are siblings while the third one is a direct child of "parentb". When attempting to call a controller method from "parenta", it does not work. Strangely, calling a method on the "c ...

identifies a data point from a combined dropdown menu

Is there a way to detect a specific value from a multiplied combo box? For example, when the value in one of the combo boxes changes to "2", a component is displayed. However, if the value in another combo box changes to anything other than "2", the compon ...

Steps for integrating an Angular 2 App into Express.js as a view

I am currently working on developing an Angular 2 app that requires data from a script running on the server. To achieve this, I am attempting to integrate my existing Angular app as a view within an express application, similar to the process demonstrated ...

"Lost in the mist of the unfulfilled promise

As a newcomer to JavaScript, I recently came across a text document filled with nouns and thought it would be a great idea to create an API using these words. I parsed the file and stored the nouns in a List: public List<Noun> getData() throws IOEx ...

Displaying imported JSON data in a tabular format

I am struggling with writing a function in my VueJS template that sends a request to the backend API with a specific key and then displays the JSON response in a table. For example, here is a sample of the JSON data: {"driver_id":1,"driver_name":"{driver ...

Having trouble with a switch statement in Javascript that is unable to find a case for "none."

In my code, I am checking to see if there is a ball in a specific map point and then changing the color of the pixels where the ball is located to match the color of the ball. Here is my code snippet: function UpdateColorInMapPoints(mapPointIndexs) { / ...

Using Angular to link Google Places API responses to a form: a guide on merging two different length objects with a shared key

I'm struggling with a key concept here regarding displaying the results of a places autocomplete query. I want to replace the types[0] name with more familiar terms such as suburb or city instead of sublocality_level_1 or administrative_area_level_1 ...

Push information into MongoDB without the need to make changes to the entire entry within the MEAN stack

I have a MEAN Stack single-page application up and running for managing exams. The schema/model I have for an exam (or Klausur in German) looks like this: var KlausurSchema = new Schema( { name: String, semester: String, krankm ...

Deploy the server on Heroku platform

I've been working on setting up a server for my first MERN app over the past week, but I'm facing issues getting it to work. It runs perfectly fine when hosted locally, but when deploying it on Heroku I keep running into the error H10. index(ind ...

What is the method for sending information to an HTML file with Express.js?

I am currently wrapping up a project for my web development bootcamp and I am facing some difficulties with adding new data to my HTML using a form. Although I have set up the HTML properly, I am not able to see any new data when I try to post it. Addition ...

ReactJS: Oops! Looks like there's an issue with the element type - it's invalid. We were expecting a string

I am in the process of setting up a basic server-side rendered React application. Listed below are the steps I have taken: Step 1: Creating a new React app using create-react-app: npx create-react-app my-ssr-app Step 2: Installing necessary dependencies: ...