Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding and removing event listeners with argument bearing functions

Tags:

javascript

Alright, first time posting here. I have been looking at posts regarding this issue for days now and I can't find a fix.

I have a matrix of images (basically arranged spheres) with unique id's. I want to add different functionalities to said spheres. So I proceed to add event listeners. All good so far. After the first event is triggered I want all the spheres to change their event listener, so I proceed to remove all event listeners and add new ones. I cannot remove the event listeners.

Adding event:

for (let i = 0; i < 11; i++) {
    for (let j = 0; j < 11; j++) {
        if ((i > 1 && i < 9 && j > 1 && j < 9) && checkCorners(i, j) === true) {
            let ball = document.getElementById(i.toString() + j.toString());
            ball.addEventListener('click', removeBall(i, j));
        }
    }
}

removeBall():

var removeBall = function(i, j) {
    return function curried_func(ii, jj) {
        let ball = document.getElementById(i.toString() + j.toString());
        ball.src = "./public/assets/ball_empty.png";
    }
}

I'm using the curried function method because it's the last method I have tried, besides retrieving object data from the e (event) argument, which did not seem to work as e was undefined. Or using a handler. Or using binding.

Removing event:

for (let i = 0; i < 11; i++) {
    for (let j = 0; j < 11; j++) {
        if ((i > 1 && i < 9 && j > 1 && j < 9) && checkCorners(i, j) === true) {
            let ball = document.getElementById(i.toString() + j.toString());
            // ball.somethingToRevmoveEvent?
        }
    }
}

I do feel the need to mention it's also my first javascript serious project so if anyone has a better solution or workaround (instead of adding and removing events 100 times for functionalities) please do share.

matrix for reference -the user should remove 1 ball , at which point the spot turns black, and then any ball can jump over another to fill the empty spot (the "jumped over ball" gets removed). I think it's a chinese checker puzzle of some kind.

like image 583
Andilozaur Avatar asked Oct 22 '19 02:10

Andilozaur


People also ask

How do you remove all event listeners from an element?

To remove all event listeners from an element: Use the cloneNode() method to clone the element. Replace the original element with the clone. The cloneNode() method copies the node's attributes and their values, but doesn't copy the event listeners.

How do you destroy event listeners?

The removeEventListener() is an inbuilt function in JavaScript which removes an event handler from an element for a attached event. for example, if a button is disabled after one click you can use removeEventListener() to remove a click event listener.

Should you remove event listeners?

TLDR; Always remove event listeners when you don't plan on using them any longer.


1 Answers

While the currying is nice, it means that it returns a new function each time it is called, rather than a copy of the same function. You need to somehow hold a reference to the function that is being bound, and then use it when removing the event listener. Without the context of the rest of your code I will attempt to pseudo-code it a bit below:

const eventMap = new Map();

function getMapKey(i, j) {
    return `${i},${j}`;
}

function addEvents() {
    for (let i = 0; i < 11; i++) {
        for (let j = 0; j < 11; j++) {
            if ((i > 1 && i < 9 && j > 1 && j < 9) && checkCorners(i, j) === true) {
                let ball = document.getElementById(i.toString() + j.toString());
                let removeBallFn = removeBall(i, j);
                let key = getMapKey(i, j);
                eventMap.set(key) = removeBallFn;
                ball.addEventListener('click', removeBallFn);
            }
        }
    }
}

function removeEvents() {
    for (let i = 0; i < 11; i++) {
        for (let j = 0; j < 11; j++) {
            if ((i > 1 && i < 9 && j > 1 && j < 9) && checkCorners(i, j) === true) {
                let ball = document.getElementById(i.toString() + j.toString());
                let key = getMapKey(i, j);
                let removeBallFn = eventMap.get(key) = removeBallFn;
                ball.removeEventListener('click', removeBallFn);
                eventMap.delete(key);
            }
        }
    }
}

This is untested as I don't have the rest of your code. The principle is that each time we generate a "remove" function, we store it in the Map (eventMap here) using a unique key based on a concatenation of the i and j values at that point in the loop. Then, when we got to remove, pull the same "remove" function out of the map using the same key, and pass it to removeEventListener. There are other ways to do this-- this is just one option. Adjust as needed given the larger context of your code. Hopefully this works for you!

like image 130
Alexander Nied Avatar answered Nov 08 '22 19:11

Alexander Nied