Reputation: 451
I am using addEventListener to react to certain events.
From what I read, it is possible to register multiple identical EventListeners on the same EventTarget, and the EventListener will only be called once.
Here's the quote from MDN:
If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded. They do not cause the EventListener to be called twice, and they do not need to be removed manually with the removeEventListener() method. Note however that when using an anonymous function as the handler, such listeners will NOT be identical since anonymous functions are not identical even if defined using the SAME unchanging source-code simply called repeatedly, even if in a loop. However, repeatedly defining the same named function in such cases can be more problematic. (see Memory issues below.)
I am not sure why this does not happen in this example? Running this code will call the EventListener twice: (Codepen here)
function _callback() { console.log("fnFunction"); }
function init() {
attachGesture("panel-anchor", _callback);
attachGesture("panel-anchor", _callback);
}
function attachGesture(sElementId, fnFunction) {
var oElement = document.getElementById(sElementId);
function foo() {
console.log("Foo");
fnFunction();
}
oElement.addEventListener("click", foo, false);
}
window.onload = init;
How can I make sure the EventListener is called only once?
Upvotes: 2
Views: 2982
Reputation: 716
Based on what I've read, since you're recreating foo
inside attachGesture
every time you're calling it, the above-mentioned function foo
is pertaining to a different instance of itself every time. Thus, they are not the same (which violates what was mentioned in your MDN reference). Storing a reference to foo
somewhere and assigning that one instead should fix the problem.
Simply put, you could try something like this
let _callback = ()=>{ console.log("fnFunction"); }
let foo = undefined;
function init() {
attachGesture("btn_click", _callback);
attachGesture("btn_click", _callback);
}
function attachGesture(sElementId, fnFunction) {
var oElement = document.getElementById(sElementId);
foo = !foo ? ()=>{console.log('foo!'); fnFunction()} : foo;
oElement.addEventListener("click", foo);
}
window.onload = init;
<input type="button" id="btn_click" value="the button">
Also, here's a working example :)
Upvotes: 2
Reputation: 33449
As Quentin already mentioned and is written in the MDN documentation, the event listener functions must be identical to do what you want to achieve.
(emphasize mine)
If multiple identical EventListeners are registered on the same EventTarget with the same parameters, the duplicate instances are discarded.
I tried to use Function.prototype.bind
to achieve this, but that returns a copy of the original function and so won't work.
I think you cannot do it without doing your own housekeeping.
"use strict";
console.clear();
function _callback() { console.log("foo fnFunction"); }
function _callback2() { console.log("bar fnFunction"); }
function init() {
var btn = document.getElementById('btn');
attachGesture(btn, 'click', _callback);
attachGesture(btn, 'click', _callback);
attachGesture(btn, 'click', _callback);
attachGesture(btn, 'click', _callback2);
attachGesture(btn, 'click', _callback);
attachGesture(btn, 'click', _callback);
attachGesture(btn, 'click', _callback2);
attachGesture(btn, 'click', _callback);
attachGesture(btn, 'click', _callback);
}
;(function() {
var houseKeeping = new Map();
function _attachGesture(element, eventName, callback) {
if (!houseKeeping.has([element, eventName, callback])) {
houseKeeping.set([element, eventName, callback], true);
element.addEventListener(eventName, callback);
}
}
window.attachGesture = _attachGesture
})();
window.onload = init;
<button id="btn">Click</button>
Upvotes: 2
Reputation: 944568
it is possible to register multiple identical EventListeners on the same EventTarget, and the EventListener will only be called once.
It isn't.
If you register the same event handler multiple times, then it will only be called once.
Identical but not ===
event handlers are not the same event handler.
You need to change your logic to avoid attempting to register identical handlers.
Upvotes: 3