Problems arising when implementing closures in upcoming events

As I strive to develop a function that can capture multiple elements on the page, iterate through them, and apply a mousedown event listener while passing data in a variable to another function that changes with each iteration, I hit a roadblock. I want to ensure that when the event is triggered, the variable holds the correct value from that specific iteration rather than the last one.

Despite scouring various answers across different platforms, I find myself unable to make this work successfully. Regardless of trying numerous supposedly correct solutions, I keep getting stuck with the final value from the data at hand.

Here are several variations I've experimented with - These variants display the anticipated value upon attachment but output an incorrect value when activated. I would greatly appreciate any insight into what could be going wrong here. Thank you!

Terminology Used:

_externalFunction() - The external function intended for invocation upon triggering the event, accompanied by the data object.

changingDataValue - The initial data value destined for transfer to the external function.

Utilizing Closure within a Separate Function

function addMouseDown(elem, data) {
    elem.addEventListener("mousedown", function () {
        _externalFunction(data);
        console.log("triggered - mouseDown: " + data.value);
    }, false);
    console.log("attached - mouseDown: " + data.value);
}

addMouseDown(elements[i], changingDataValue);

Incorporating Closure within Another Function Alongside a Closure in the Event Listener

function addMouseDown(elem, data) {
    (function(d) {
        elem.addEventListener("mousedown", function () {
            (function (e) {
                _externalFunction(e);
                console.log("triggered - mouseDown: " + e.value);
            })(d);
        }, false);
    })(data);
    console.log("attached - mouseDown: " + data.value);
}

addMouseDown(elements[i], changingDataValue);

Implementing Closure within Another Function:

function addMouseDown(elem, data) {
    (function(d) {
        elem.addEventListener("mousedown", function () {
            _externalFunction(d);
            console.log("triggered - mouseDown: " + d.value);
        }, false);
    })(data);
    console.log("attached - mouseDown: " + data.value);
}

addMouseDown(elements[i], changingDataValue);

Closure Embedded within the Script Itself

(function (data) {
    elements[i].addEventListener("mousedown", function () {
       _externalFunction(data);
       console.log("triggered - mouseDown: " + data.value);
    }, false);
    console.log("attached - mouseDown: " + data.value);
})(changingDataValue);

Closure within the Event Handler

elements[i].addEventListener('mousedown', (function(data) {
    return function() {
        _externalFunction(data);
        console.log("triggered - mouseDown: " + data.value);
    };
})(changingDataValue), false);
console.log("attached - mouseDown: " + changingDataValue.value);

Performs flawlessly except for prematurely calling the external function before the event actually triggers, yet it does pass the desired value

(function (elem, data) {
    elem.addEventListener("mousedown", (function (d) {
        _externalFunction(d);
        console.log("triggered - mouseDown: " + d.value);
    })(data), false);
    console.log("attached - mouseDown: " + data.value);
})(elements[i], changingDataValue);

Once again, any assistance offered here will be highly valued. Thanks!

Answer №1

Your elem.addEventListener contains a self-executing anonymous function, which means it is sending the returned value instead of a reference to a function.

In simpler terms, the code below gets executed and the value (in this case, undefined) is passed as the 2nd argument in elem.addEventListener:

(function (d) {
    _externalFunction(d);
    console.log("triggered - mouseDown: " + d.value);
})(data), false)

If you convert that into a regular function call, your data variable will still be accessible when you refer to it in the callback since it is bound to that anonymous function. I recommend leveraging call/apply to change the this scope to the clicked element for future development purposes.

<a href="#link1" class="link">test1</a> | <a href="#link2" class="link">test2</a>
<script>
  // Select all links on the page
  var elements = document.getElementsByClassName('link');

  for (var i = 0, l = elements.length; i < l; i++) {

    // Get an identifying attribute about each link for easy testing
    changingDataValue = {
      value: elements[i].href
    };

    // This anonymous function sets the scope for elem/data vars in every loop iteration
    (function(elem, data) {
      console.log("attached - mouseDown: " + data.value);
      elem.addEventListener("mousedown", function() {
        console.log("triggered - mouseDown: " + data.value);

        // Use call to maintain "this" reference (link element) in your external function
        _externalFunction.call(this, data);
      });
    })(elements[i], changingDataValue);
  }

  function _externalFunction(d) {
    // console.log(this) would show the clicked link element
    console.log("external function: " + d.value);
  }
</script>

If I run the above code and click on link2 first, then link1, the output would be:

attached - mouseDown: #link1
attached - mouseDown: #link2
triggered - mouseDown: #link2
external function: #link2
triggered - mouseDown: #link1
external function: #link1

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

Navigate through chosen options by clicking on a button

It's a new day and I'm facing a simple challenge that seems complicated in the morning haze. I need to create a select dropdown with zoom percentage values, along with + and - buttons to navigate through the list. If I have the following setup: ...

There was a problem with the ajax request

Attempting to make an ajax request in my SpringMVC project has been challenging. $.ajax({ contentType : 'application/json; charset=utf-8', type : 'get', url : 'order/get/'+i, dataType : 'json', ...

The validation function is always one step ahead of React component props

I have developed a validation function that checks user input for errors as they type. Additionally, I have implemented an <Input/> component and included an error message <div>. My goal is to provide a string to the "message" prop on the <I ...

The act of loading a webpage without inserting any data into the database is not recommended

I've created an enroll.html page with the following code: <HTML> <HEAD> <script src="https://code.jquery.com/jquery-2.2.3.min.js" integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo=" crossorigin="anonymous"></scr ...

"Stopping the default behavior of an event can impact the remainder of the code

Within this project, there exist three .ejs pages, namely index.ejs, loading.ejs, and result.ejs. The initial page to load is index.ejs, which contains the following code within its script tag: document.addEventListener("DOMContentLoaded", functi ...

It's likely that the data source is incorrect for the 'GET_LIST' operation

Trying to utilize react-admin with a Hasura adapter. Encounter an error when attempting to use the cruds. The response to 'GET_LIST' must follow this format { data: ... }, however, the received response is missing a 'data' key. Authen ...

Transform a checkbox input into two distinct buttons

I am trying to change the input checkbox that toggles between light and dark mode into two separate buttons. How can I achieve this functionality? Check out the demo here: https://jsfiddle.net/ot1ecnxz/1 Here is the HTML code: <input type="checkb ...

Guide to testing Higher Order Components with React Testing Library

I've created a higher-order component (HOC) that adds props to a component for handling network requests and passing down data as props. Below is a simplified version of the HOC: export const withTags = (Component) => { class WithTags extends Pur ...

JavaScript radio button returning value as undefined issueThe problem with radio buttons

http://jsfiddle.net/jngpjbjm/ Take a look at the provided fiddle link. I'm having an issue where the radio button value is showing up as undefined. I can't figure out why this is happening. Any assistance would be greatly appreciated. <input ...

Using the `Array.find()` method in an attempt to dynamically retrieve a specific object value and then return it based on the object name, but unfortunately the function is

I have a collection of objects, each containing its own nested array of objects. My goal is to utilize the Array.find() method to target individual nodes within the array and extract a value from their subarray based on name. Despite having written my fu ...

Querying Denormalized Data in AngularFire 0.82: Best Practices and Strategies

I have a question that is related to querying denormalized data with AngularFire. I am looking for a solution specifically using AngularFire (current version 0.82). Here is an example of the data structure I am working with: { "users": { "user1": { ...

The user score tracking database, cataloging personal scoring history

In my database, I have a table called User. Each user in this table has a field named score. I am looking to display how the score of each user has evolved over time. My dilemma is whether to store this score separately. Should I create a new database t ...

Having difficulty getting my create-react-app to display on Heroku

I successfully managed to get my react-app running smoothly on my localhost server. However, when I attempted to deploy it on Heroku, I encountered a problem. Upon visiting the app address provided by Heroku, all I see is a blank page with none of the comp ...

The comparison between installing a JavaScript library and simply copying .js files

As I dive into the world of web development and JavaScript, I've noticed that many open-source JavaScript libraries like jqueryUI come with readme files containing installation instructions. These instructions often mention the need to install additio ...

Nextjs is facing challenges in enhancing LCP specifically for text content

I've been trying to boost my LCP score by optimizing the text on my page, but it seems stuck and I can't figure out why my LCP isn't improving. Take a look at the screenshot: https://i.stack.imgur.com/xfAeL.png The report indicates that &a ...

Fade in and out animation for flash notifications

Is there a way to create a flash message with a smooth fade in and out animation using jQuery? I would appreciate any recommendations on the most efficient approach for achieving this effect. ...

Switching up the image using a dropdown selection menu

I am struggling with updating an image based on the selection made in a dropdown menu. I am quite new to javascript, so I believe there might be a simple issue that I am overlooking. Here is my attempt at doing this: JS: <script type="text/javascript" ...

Clicking on the input triggers the appearance of a border using the OnClick function

I am currently developing my own website with a login feature that requires input tags of text-type. I would like to implement a functionality where clicking on these input tags will display a border, even when the mouse is not directly hovering over them. ...

Find the nearest minute when calculating the difference between two dates

To determine the difference between dates and round to the nearest minute, you can choose to either round date1 or date2 up or down. The result returned is already rounded up to the full minute. You have the flexibility to modify date1 and date2, but do no ...

Embracing the Legacy of jQuery's Event Handling Mechanism

I am in the process of developing an SDK for a website's API that relies on jQuery. I am interested in incorporating jQuery's custom events model into the SDK. How can I effectively integrate, encapsulate, or otherwise leverage jQuery's even ...