I'm employing Object-Oriented Javascript, in conjunction with registering event listeners. From what I understand about event listeners, if the function applied to eventtarget has already been registered, repeated attempts to add this same event listener will be ignored. In other words, it should only fire once. But that is not the case in the code below (also can be seen on jsfiddle).
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
Multiple identical event listeners
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 since the duplicates are discarded, they do not need to be removed manually with the removeEventListener method.
http://jsfiddle.net/qd1e8f6c/
HTML
<div id="wrapper">
<input id="t1" type="text" />
<input id="btn" type="button" />
</div>
JS
var namespace = namespace || {};
namespace.event = {
addListener: function(el, type) {
var handle = function() {
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
el.addEventListener(type, handle, false);
}
};
namespace.ExampleClass = function() {
this.init = function(el1, el2) {
el1.value = "123";
el2.value = "Click Me";
};
};
var textbox = document.getElementById("t1");
var button = document.getElementById("btn");
var inst = new namespace.ExampleClass();
inst.init( textbox, button );
namespace.event.addListener(textbox, "focus");
namespace.event.addListener(button, "click");
// same handle -- shoudln't it only add the event once?
namespace.event.addListener(textbox, "focus");
namespace.event.addListener(button, "click");
As you can see in the last few lines of the code above, a function called addListener
is executed twice, which registers an event to each input. Then, addListener
is executed again. I'm expecting it to not register again and ignore, but it actually registers. I don't get it. The function in the namespace called handle
is exactly the same. What am I doing wrong here?
Any help would be great.
This symptom is indicative that you've registered the same listener more than once. You must remember to deregister events when your component unloads to prevent his problem.
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 since they are discarded they do not need to be removed with the removeEventListener method.
Adding event listener to multiple elements To add the event listener to the multiple elements, first we need to access the multiple elements with the same class name or id using document. querySelectorAll() method then we need to loop through each element using the forEach() method and add an event listener to it.
So You need to write a custom function to iterate over multiple events. This is being handled in jQuery by using . split(" ") and then iterating over the list to set the eventListeners for each types .
You cannot bind the same type/function pair to an element. However, that is not what you are doing, you are explicitly creating a new handler
function on every call to your namespace.addEventListener
function.
What you have:
namespace.event = {
addListener: function(el, type) {
var handle = function() {
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
el.addEventListener(type, handle, false);
}
};
What would do what you expect:
var handle = function(evt) {
var el = evt.currentTarget;
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
namespace.event = {
addListener: function(el, type) {
el.addEventListener(type, handle, false);
}
};
because there is only one instance of handle
in the second case.
What you have is one approach to namespacing, but most often these days, JS namespacing is done via the Module Pattern
For your case for example, you don't even appear to really care about making your code globally accessible via this 'namespace' variable since it is only used in your code, so you could do:
var namespace = (function(){
function handle(evt) {
var el = evt.currentTarget;
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
function addListener(el, type) {
el.addEventListener(type, handle, false);
}
function ExampleClass() {
this.init = function(el1, el2) {
el1.value = "123";
el2.value = "Click Me";
};
};
var textbox = document.getElementById("t1");
var button = document.getElementById("btn");
var inst = new ExampleClass();
inst.init( textbox, button );
addListener(textbox, "focus");
addListener(button, "click");
// And if you do care about 'inst' being global, you'd explicitly add it to the window.
window.inst = inst;
// Whatever functions you want to expose as 'namespace' would go here.
return {
event: {
addEventListener: addEventListener
}
};
})();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With