2

I'm trying to remove event listeners from elements after they've been clicked on and although I seem to have a working solution, it's not ideal and I'm not sure why it works differently to the broken code.

Although I realise there are simpler ways of doing this, this is taken from a JS class I'm working on so need to retain some of the structure.

This relates to a previous post I made which was answered correctly (but didn't work when I expanded the example) - Removing event listeners with anonymous function calls in JavaScript.

In this example, the last created div removes the listener correctly but earlier ones don't (fiddle here - http://jsfiddle.net/richwilliamsuk/NEmbd/):

var ctnr = document.getElementById('ctnr');
var listener = null;

function removeDiv (d) {
    alert('testing');
    d.removeEventListener('click', listener, false);
}

function addDiv () {
    var div = document.createElement('div');
    div.innerHTML = 'test';
    ctnr.appendChild(div);
    div.addEventListener('click', (function (d) { return listener = function () { removeDiv(d); } })(div), false);
}

addDiv();
addDiv();
addDiv();

In the version I got working I create an array which holds all the listeners (fiddle here - http://jsfiddle.net/richwilliamsuk/3zZRj/):

var ctnr = document.getElementById('ctnr');
var listeners = [];

function removeDiv(d) {
    alert('testing');
    d.removeEventListener('click', listeners[d.id], false);
}

function addDiv() {
    var div = document.createElement('div');
    div.innerHTML = 'test';
    ctnr.appendChild(div);
    div.id = listeners.length;
    div.addEventListener('click', (function(d) {
        return listeners[listeners.length] = function() {
            removeDiv(d);
        }
    })(div), false);
}


addDiv();
addDiv();
addDiv();

document.getElementById('btn').addEventListener('click', function() {
    alert(listeners);
}, false);​

The final one works fine but I'm sure the listener array shouldn't be necessary. Maybe I'm worrying too much but I'd like to know the optimal solution.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Rich
  • 357
  • 4
  • 10

2 Answers2

2

you are right, you don't need an array, just hold every listener in a variable, than pass eventlistener in your remove() function,

var ctnr = document.getElementById('ctnr');

function removeDiv(d, ev) {
    alert('testing');
    d.removeEventListener('click', ev, false);
}

function addDiv() {
    var div = document.createElement('div');
    div.innerHTML = 'test';
    ctnr.appendChild(div);
    div.addEventListener('click', (function(d) {
        var myfunc;
        return myfunc = function() {
            removeDiv(d, myfunc);
        }
    })(div), false);
}


addDiv();
addDiv();
addDiv();

document.getElementById('btn').addEventListener('click', function() {
    alert(listeners);
}, false);​​

updated jsfiddle page

Okan Kocyigit
  • 13,203
  • 18
  • 70
  • 129
1

You have to save each and every listener if they are unequal, so you need a relation between listener and element. Since an element is represented by an object (DOM: document object model) you can add custom properties to them (although it's not recommended: Can I add arbitrary properties to DOM objects?) (demo):

var ctnr = document.getElementById('ctnr');

function removeDiv (d) {
    alert('testing');
    d.removeEventListener('click', d.custom_Listener , false);
}

function addDiv () {
    var div = document.createElement('div');
    div.innerHTML = 'test';
    div.custom_Listener = function(){removeDiv(this)};
    ctnr.appendChild(div);
    div.addEventListener('click', div.custom_Listener , false);
}

But since your using the same listener in every div its even better not to use a separate function for every div but the same (demo):

var ctnr = document.getElementById('ctnr');
var listener = function(){
    removeDiv(this);
};

function removeDiv (d) {
    alert('testing');
    d.style.backgroundColor = '#36f';
    d.removeEventListener('click', listener, false);
}

function addDiv () {
    var div = document.createElement('div');
    div.innerHTML = 'test';
    ctnr.appendChild(div);
    div.addEventListener('click', listener , false);
}
Community
  • 1
  • 1
Zeta
  • 103,620
  • 13
  • 194
  • 236
  • Sorry, looking at my question, I really should put it back in a Object Oriented context (the reason the listener was within a closure). This works but can't be applied to my class (my fault for not showing it all properly). Thanks though - will edit the question! – Rich Apr 06 '12 at 10:02