0

The problem : an event listener wants to remove itself from the target listeners list. The listener can be an anonymous function and/or dynamicaly generated (closure or bind)

Here is a solution (doesn't work in "mode strict") : (exemple for "click" event)

function(ev){
   // .... some stuff
   ev.target.removeEventListener("click",arguments.callee);
}

But this does'nt work in ES5 strict mode.

Question : is there another solution ?

Brn--
  • 1

4 Answers4

1

Just name it - which works even for function expressions.

… function myListener(ev){
   // … some stuff
   ev.target.removeEventListener("click", myListener);
} …
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

When you add event listener via addEventListener, you can do it through named function so that you will have a reference.

TheOpti
  • 1,641
  • 3
  • 21
  • 38
0

Thanks for answers an comments.

Naming function is a solution when using closure patterns, for instance. But not for bounded functions : function name references the original function, not the bounded instance.

Some example :

function listener(s,ev){
  "use strict";
  if (ev.target.value == s){
    console.log("<bounded> I found " + s+ ", Bye !");
    // Doesn't work : listener references original (not bounded) function
    ev.target.removeEventListener(ev.type, listener);
    // Who am I ?? ;-)
  } else {
    console.log("<bounded> still waiting for " +s + " " + new Date());
  }
}
window.addEventListener('load', function(){
  i = document.querySelector('input');
  i.addEventListener("change",listener.bind(i,"abc"));
  i.addEventListener("change",listener.bind(i,"def"));
});

I wrote this ugly workaround :

function autoRefBind(f, ...args){
  var o = {};
  o.me = f.bind(o,...args);
  return o.me;
}
function listener(s,ev){
  "use strict";
  if (ev.target.value == s){
    console.log("<bounded> I found " + s+ ", Bye !");
    ev.target.removeEventListener(ev.type, this.me);
  } else {
    console.log("<bounded> still waiting for " +s + " " + new Date());
  }
}
window.addEventListener('load', function(){
  i = document.querySelector('input');
  i.addEventListener("change",autoRefBind(listener,"abc"));
  i.addEventListener("change",autoRefBind(listener,"def"));
});

But it's very ... ugly : 'this' has to be this "stupid" object {me : }

Brn--
  • 1
0

Events binding works with registration of functions (handlers) instances per event names !

Basically when you call addEventListener you define a function address to be called when the given named event will be triggered.

Because you are using bind you break this mechanism, just because bind return a new function (see bind documentation).

But, from what I understand from your code, you are trying to run your event handler once (and self detaching from events registration list).

If so, why not tell addEventListener to just run hour handler once (see addEventListener documentation) ? Here is a much simpler code:

function listener(s,ev){
  "use strict";
  console.log("executing listener once with ", s)
}
window.addEventListener('load', function(){
  i = document.querySelector('input');
  i.addEventListener("change",listener.bind(i,"abc"), {once:true});
  i.addEventListener("change",listener.bind(i,"def"), {once:true});
});

You can test it here : https://jsfiddle.net/rptsrfLz/

John-Philip
  • 3,392
  • 2
  • 23
  • 52
  • Thanks. I know that bind creates a new function. Precisely, I'd like to access the reference of this new fonction inside itself. "once" can't be the solution, because detachment is conditional. Listener is about to be invoked several times before detachment condition is raised. – Brn-- Apr 23 '17 at 13:08