Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

removeeventlistener

25 views
Skip to first unread message

Andrew Poulos

unread,
Oct 15, 2017, 11:30:06 PM10/15/17
to
I have code that looks like this

function elementOver() {
return function() {
this.style...
};
}

function setOver(elem) {
for (var i = 0; elem.length; i++) {
elem[i].addEventListener("mouseover", elementOver() );
}
}

function disableOver(elem) {
for (var i = 0; i < elem.length; i++) {
elem[i].removeEventListener("mouseover", elementOver() );
}
}

Adding the listener works but removing it doesn't. I don't understand
why not nor how to remove the listeners?

Andrew Poulos

Julio Di Egidio

unread,
Oct 16, 2017, 12:08:14 AM10/16/17
to
Because you need to pass references to the same handler, but your two
separate invocations of the constructor create distinct instances.

To fix it, initialise a variable that is in the closure of both your
functions and pass that as a reference to add/removeEventListener.

(The extra-complexity of using a constructor function instead of
directly a function for the handler is pointless in your example,
but I'm assuming you know that.)

Julio

Richard Maher

unread,
Oct 16, 2017, 1:06:27 AM10/16/17
to
My Guess is you're not passing the same "elem" to both functions.

BTW you should use delegation and let the event bubble up to a parent
and then decide which child target the mouse was on from that.

Thomas 'PointedEars' Lahn

unread,
Oct 16, 2017, 4:18:10 PM10/16/17
to
Every time you call elementOver(), you create a *new* Function instance and
return a reference to *that*.

--
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

Thomas 'PointedEars' Lahn

unread,
Oct 28, 2017, 1:48:49 PM10/28/17
to
Thomas 'PointedEars' Lahn wrote:

> Andrew Poulos wrote:
>> I have code that looks like this
>>
>> function elementOver() {
>> return function() {
>> this.style...
>> };
>> }
>>
>> function setOver(elem) {
>> for (var i = 0; elem.length; i++) {
>> elem[i].addEventListener("mouseover", elementOver() );
>> }
>> }
>>
>> function disableOver(elem) {
>> for (var i = 0; i < elem.length; i++) {
>> elem[i].removeEventListener("mouseover", elementOver() );
>> }
>> }
>>
>> Adding the listener works but removing it doesn't. I don't understand
>> why not nor how to remove the listeners?
>
> Every time you call elementOver(), you create a *new* Function instance
> and return a reference to *that*.

This answers the “why not” part of your question.

The answer to the “how” part (which I noticed only now) may not be obvious
if you could not find the answer to the “why not” part by yourself:

You need to store references to the listeners so that you can reuse them.

/*
* NOTE:
* Easily maintainable code uses _plurals_ in the names of iterables
*/
var elementOvers = [];

function setOver (elements)
{
/*
* NOTE:
* You may want to use ES 5 [].forEach.apply(elements, …) or
* ES 6 “for … of” on [].slice.call(elements) instead.
*
* In loops, cache the value of the “length” property unless you
* expect its value to change and want to handle that.
*/
for (var i = 0, len = elements.length; i < len; ++i)
{
/* NOTE:
* You can still return the function reference instead.
* Just keep in mind that in the way it is used here,
* there is a closure over “i”.
*
* Consider using CSS “:hover” selectors based on class selectors
* instead of setting style properties here.
*/
var elementOver = elementOvers[i] = function () {
this.style...
};

/* NOTE: The third argument may not be “false” by default. */
elements[i].addEventListener("mouseover", elementOver, false);
}
}

function disableOver (elements)
{
for (var i = 0, len = elements.length; i < len; ++i)
{
elements[i].removeEventListener("mouseover", elementOvers[i]);
}
}

Usually one implements an event registry object for this purpose (which,
if the built-in Map object is supported, can register event listeners per
element object even without using additional identifying properties now,
and certainly without host object augmentation), and one does not use many
user-defined *global* variables and functions.

HTH.

Thomas 'PointedEars' Lahn

unread,
Oct 28, 2017, 2:00:35 PM10/28/17
to
Thomas 'PointedEars' Lahn wrote:

> var elementOvers = [];
>
> function setOver (elements)
> {
> /*
> * NOTE:
> * You may want to use ES 5 [].forEach.apply(elements, …) or
> * ES 6 “for … of” on [].slice.call(elements) instead.
> *
> * In loops, cache the value of the “length” property unless you
> * expect its value to change and want to handle that.
> */
> for (var i = 0, len = elements.length; i < len; ++i)
> {
> /* NOTE:
> * You can still return the function reference instead.
> * Just keep in mind that in the way it is used here,
> * there is a closure over “i”.
> *
> * Consider using CSS “:hover” selectors based on class selectors
> * instead of setting style properties here.
> */
> var elementOver = elementOvers[i] = function () {
> this.style...
> };

Supplemental:

If all listeners for the same event implement the same algorithm, you only
need to define *one* such function such that it can be shared across
function execution contexts –

var elementOver = function () {
// …
};

–, and re-use the reference to it:

function (…)
{
for (…)
{
elements[i].addEventListener("mouseover", elementOver, false);
}
}



function (…)
{
for (…)
{
elements[i].removeEventListener("mouseover", elementOver);
}
}

That would be much more efficient then.
0 new messages