I am writing a vanilla JavaScript tool, that when enabled adds event listeners to each of the elements passed into it.
I would like to do something
This can be done quite easily, just not as you have it right now.
Instead of trying to add and remove random anonymouse functions, you need to add or remove a function that handles the execution of your other functions.
var
// Here we are going to save references to our events to execute
cache = {},
// Create a unique string to mark our elements with
expando = String( Math.random() ).split( '.' )[ 1 ],
// Global unique ID; we use this to keep track of what events to fire on what elements
guid = 1,
// The function to add or remove. We use this to handler all of other
handler = function ( event ) {
// Grab the list of functions to fire
var handlers = ( cache[ this[ expando ] ] && cache[ this[ expando ] ][ event.type ] ) || false;
// Make sure the list of functions we have is valid
if ( !handlers || !handlers.length ) {
return;
}
// Iterate over our individual handlers and call them as we go. Make sure we remeber to pass in the event Object
handlers.forEach( function ( handler ) {
handler.call( this, event );
});
},
// If we want to add an event to an element, we use this function
add = function ( element, type, fn ) {
// We test if an element already has a guid assigned
if ( !element[ expando ] ) {
element[ expando ] = guid++;
}
// Grab the guid number
var id = element[ expando ];
// Make sure the element exists in our global cache
cache[ id ] = cache[ id ] || {};
// Grab the Array that we are going to store our handles in
var handlers = cache[id ][ type ] = cache[ id ][ type ] || [];
// Make sure the handle that was passed in is actually a function
if ( typeof fn === 'function' ) {
handlers.push( fn );
}
// Bind our master handler function to the element
element.addEventListener( type, handler, false );
};
// Add a click event to the body element
add( document.body, 'click', function ( event ) {
console.log( 1 );
});
This is just a cut down version of what I've written before, but you can get the gist of it I hope.
This is invalid:
arr[i].el.addEventListener('click', do_something(arr[i]));
The listener must be a function reference. You cannot specify parameters at the time of listener assignment. A handler function will always be called with the event
being passed as the first argument. To pass other arguments, you can wrap your listener into an anonymous function like so:
elem.addEventListener('click', function(event) {
do_something( ... )
}
To be able to remove via removeEventListener
you just name the handler function:
function myListener(event) {
do_something( ... );
}
elem.addEventListener('click', myListener);
To have access other variables in the handler function, you can use closures. E.g.:
function someFunc() {
var a = 1,
b = 2;
function myListener(event) {
do_something(a, b);
}
elem.addEventListener('click', myListener);
}
To 'addEventListener
' with some parameters, you can use the following code:
{
myButton.addEventListener("click",myFunction.bind(null,event,myParameter1,myParameter2));
}
And the function 'myFunction
' should be something like this:
{
function myFunction(event, para1, para2){...}
}
To pass arguments to event handlers bind
can be used or handler returning a function can be used
// using bind
var do_something = function (obj) {
// do something
}
for (var i = 0; i < arr.length; i++) {
arr[i].el.addEventListener('click', do_something.bind(this, arr[i]))
}
// using returning function
var do_something = obj => e {
// do something
}
for (var i = 0; i < arr.length; i++) {
arr[i].el.addEventListener('click', do_something(arr[i]))
}
But in both the cases to remove the event handlers it is not possible as bind
will give a new referenced function and returning function also does return a new function every time for loop is executed.
To handle this problem we need to store the references of the functions in an Array
and remove from that.
// using bind
var do_something = function (obj) {
// do something
}
var handlers = []
for (var i = 0; i < arr.length; i++) {
const wrappedFunc = do_something.bind(this, arr[i])
handlers.push(wrappedFunc)
arr[i].el.addEventListener('click', wrappedFunc);
}
//removing handlers
function removeHandlers() {
for (var i = 0; i < arr.length; i++) {
arr[i].el.removeEventListener('click', handlers[i]);
}
handlers = []
}