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
- Side Note: This inheritance actually works all the way up to the very top-most block, the script file.
Other Reading
ClassicPHP is a new library in development meant to make your life easier as a PHP web developer. It takes the most necessary tasks for any project, and allows you to do them by calling a method, rather than writing similar code in those projects. That’s ClassicPHP in a nutshell. What ClassicPHP Does Unfortunately many… Read More »Passing a Variable to and From an Event Listener Function