Passing a Variable to and From an Event Listener Function

HTML, PHP, and other web development code is shown, as seen in code editor software

It can be tricky getting variables into event listener/handler functions. It’s even harder to get variables back out of event handlers again.

Passing Variables into an Event Handler

Suppose you want to pass a variable into an event handler. First you might store a reference to a DOM element in a variable. Let’s use myElement for that. After that, you would create an event listener on the DOM element, perhaps using the addEventListener method belonging to that element.

let myElement = document.getElementById('that-element-id');

myElement.addEventListener('click', function() {

    // Event Handler Code Here
});

Here’s the problem: in this case you need your event handler to be defined within an object, and you need to pass a property belonging to the object into the event handler function. However, since all event handlers are called by the event listener interface, and not called directly, there is no way to specify an argument to pass to yours.

let myObject = {

    this.myVariable = ['data1', 'data2'];

    attachMyEventListener() {

        let myElement = document.getElementById('that-element-id');

        myElement.addEventListener('click', function() {

            // Event Handler Code Here
        });
     }
};

Problem 1: The Event Listener Interface Has No Argument Passing Functionality

You can’t setup an event handler to accept arguments, because the event handler interface isn’t designed to pass arguments through to the event handler. This is true with the addEventListener method, and with the various global event handler methods, such as onclick().

myElement.addEventListener('click', function(myParameter) {

    console.log(myParameter);

    /* This won't work! The myParameter argument is ignored. Logs the click event! */
});
myElement.onclick = function myCallBackFunction(myParameter) {

console.log(myParameter);

/* This won't work! The myParameter argument is ignored. Logs the click event! */
};

The first parameter of an event handler is always passed the click event by the event listener interface when the event fires. This results, in our attempts, in logging the click event instead of the argument we expected when the element was clicked.

function myCallBackFunction(myParameter) {

    console.log(myParameter);

    /* This won't work! The myParameter function with the provided arguments is executed when this code executes, and not when the click event fires. The event handler still logs the click event on an actual click event */
}

myElement.addEventListener('click', myCallBackFunction(myElement)); 

It doesn’t help any when we try to get tricky and use a predefined event handler function, which we then called with addEventListener, passing it an argument for the event handler. Unfortunately, in this case, the event handler function with the specified arguments was executed when the code that specifies the event handler was executed. (That’s not what we wanted to happen! But then, should we really be that surprised that this happened? Look at the last line again.) Then when the element was clicked, it did the same thing as before, and logged the click event.

Solution 1: It’s Simple to Access External Variables inside an Event Handler Because of the Event Handler’s Scope

In JavaScript, functions and methods defined within a block of code inherit the scope of that outer block of code.N1 For example:

let testVariable = 'SUCCESS!';

function writeSuccess() {

     console.log(testVariable); // Outputs "SUCCESS!" to the Console
};

writeSuccess(); 

This same principle applies to event handler functions. This means the simplest thing to do is to define a variable in the outer scope where the event listener is defined, and then use that variable within the event handler function.

For example, if we were trying to access a variable within a function that defines an event listener, we might do something like the following:

let myElement = document.getElementById('that-element-id');
let testVariable = 'Stop Clicking Me!';

myElement.addEventListener('click', function() {

    console.log(testVariable); // Outputs "Stop Click Me!" on Click
}); 

Problem 2: How Do We Use Variable Scope to Access Object Properties inside an Event Handler?

Back to our example of using a property within an event handler function defined within the same object, we do run into another problem. Within an object’s methods, we need to use this to specify other methods and properties belonging to the same class in order to access them. However, this has a different meaning within an event handler. Inside of an event handler this refers to the element the action is triggered on.

let myObject = {

    this.myVariable: ['data1', 'data2'];

    attachMyEventListener: function() {

        let myElement = document.getElementById('that-element-id');

        myElement.addEventListener('click', function() {

            console.log(this.myVariable); // this.myVariable is Undefined!
        });
    }
}; 

In this case, we have inadvertently tried to access the myVariable property of the myElement element (hence the undefined output)! Inside this particular event handler, this refers to myElement.

Solution 2: It’s Easy to Access the Entire Object and All of It’s Properties and Functions by Defining an in-Scope Variable Pointing to the Object

Since we already know that event handlers inherit the scope of all of the block scopes that lead to it being called (see solution 1), we can use that to our advantage when we want to reference an object property or method within the event handler.

let myObject = {

    this.myVariable: ['data1', 'data2'];

    attachMyEventListener: function() {

        let myElement = document.getElementById('that-element-id');
        let thisObject = this;

        myElement.addEventListener('click', function() {

            console.log(thisObject.myVariable); // thisObject refers to the this keyword within the class, which refers to the instantiated object itself
        });
    }
}; 

“Ah! Things are looking up!” you say. By creating a variable in the outer scope of the event handler which references the object itself, the event handler suddenly has a reference to the object that defined it! It get’s better, though. If you don’t want the event handler to have access to the entire object that defined it, you can specify one property or one method to allow the event handler to access.

let myObject = {

    this.myVariable: ['data1', 'data2'];

    attachMyEventListener: function() {

        let myElement = document.getElementById('that-element-id');
        let thisProperty = this.myVariable;

        myElement.addEventListener('click', function() {

            console.log(thisProperty); // Works!
        });
    }
}; 

In this case, thisProperty refers to the myVariable property of the object that was used to define the event handler.

Getting Variables out of an Event Handler

Still to come!

The main problem with getting variable data out of an event handler is that you don’t know when that event handler will fire. It probably won’t fire right after you define the event handler.

Notes

  1. Side Note: This inheritance actually works all the way up to the very top-most block, the script file.

Other Reading

Leave a Reply

Your email address will not be published. Required fields are marked *