removeEventListener from body not working - javascript

I'm trying to remove an event listener after a function has been called. But the event listener for "keyup" stays attached to the body, no matter what I try. What is wrong with the code?
function displayImage() {
//this is a simplified version of the code
var outerFrame = document.createElement('div');
outerFrame.className = 'popup-outer';
document.body.appendChild(outerFrame);
document.body.addEventListener('keyup', hideImage.bind(outerFrame), false);
}
function hideImage(e) {
if (e.keyCode === 27) {
// this doesn't work, it stays attached to the body element
document.body.removeEventListener('keyup', hideImage, false);
document.body.removeChild(this);
}
e.preventDefault();
}

It's because technically
hideImage.bind(outerFrame)
is different from
hideImage
because the first one returns a copy of the function hideImage.
So when you try to unbind hideImage, the event manager does not find it because it registred a copy of it and thus nothing is removed :-/.
EDIT :
In your case, I guess you have no other choice but keeping track of your listeners. I went ahead and made this quickly, it should fix your problem.
var listeners = {};
function createDiv() {
var outerFrame = document.createElement('div');
outerFrame.className = 'popup-outer';
return outerFrame;
}
function displayImage() {
var div = createDiv();
bindEvent(div);
document.body.appendChild(div);
}
function bindEvent(el) {
var handler = function(e) {
hideImg.call(el, e);
}
listeners[el] = handler;
document.body.addEventListener('keyup', handler, false);
}
function hideImg(e) {
if (e.keyCode === 27) {
// listeners[this] refers to the "private" handler variable we created in the bindEvent function
document.body.removeEventListener('keyup', listeners[this], false);
delete listeners[this];
document.body.removeChild(this);
}
}

Related

Event handler isn't working

I have one input which have event listener onblur and button which have event listener onclick.
This is how I organized it
document.addEventListener("DOMContentLoaded", function() {
window.searchButton = document.getElementById("searchButton");
window.searchInput = document.getElementById("searchInput");
searchInput.onfocus = searchFocus;
searchInput.onblur = searchBlur;
searchButton.onclick = search;
});
var resize = function(self, newSize) {
self.setAttribute("size", newSize);
};
var searchFocus = function() {
event.stopPropagation();
resize(searchInput, 30);
};
var searchBlur = function() {
if (searchInput.value === "") {
resize(searchInput, 10);
}
};
var search = function() {
event.stopPropagation();
};
But when the input is focused and I am clicking on the button, working onblur function, but onclick function isn't working. Why and how can I fix that?
Your search callback should have event in its param list. Same is true for searchFocus
var search = function(event){
event.stopPropagation();
};
Also, you might want to check that your DOMContentLoaded handler is firing. Depending upon how your scripts are organized/loaded, it is possible that the DOM has already loaded and that event fired before you register the handler. That's a common oversight.
How to detect if DOMContentLoaded was fired

Event Listener Trouble

I am trying to use an event listener for when I click on an object.
My HTML file
<div id="left">
</div>
<div id="right">
</div>
My JavaScript file
function changeImg(which)
{
if(which === "left")
{
alert("left");
}
else
{
alert("right");
}
}
var leftClick = document.getElementById("left");
leftClick.addEventListener("click", changeImg("left"), true);
var rightClick = document.getElementById("right");
rightClick.addEventListener("click", changeImg("right"), false);
Here is my JSFiddle, https://jsfiddle.net/pb4759jh68/zqzdhcnw/1/
My question is, why does my function run as soon as I run the page, rather than waiting until I click on either the left or right div?
Thanks!!!
The problem is with these 2 lines:
leftClick.addEventListener("click", changeImg("left"), true);
rightClick.addEventListener("click", changeImg("right"), false);
The changeImg function is being called immediately, since you are using the parenthesis after the function name. You can do this to prevent it:
var leftClick = document.getElementById("left");
leftClick.addEventListener("click", function() {
changeImg('left');
}, true);
var rightClick = document.getElementById("right");
rightClick.addEventListener("click", function() {
changeImg('right');
}, false);
Here, we pass an anonymous function as a refernce, which will be called by the browser upon the click event. Inside the function, we are calling our own function changeImg.
addEventListener requires a function as second argument. You're currently evaluating the handler function changeImg("left"), and assigning the result as the event handler. Try this instead:
var leftClick = document.getElementById("left");
leftClick.addEventListener("click", function() { return changeImg("left") }, true);
var rightClick = document.getElementById("right");
rightClick.addEventListener("click", function() { return changeImg("right") }, false);

how to pass self(this) to addEventListener without breaking removeEventListener?

I'm adding checkboxchange event to checkbox here. (moveButton is a checkBox because im using CSS checkbox hack)
var self = this;
this.moveButton.addEventListener("change", function(e){self.toggleMove(e, self)});
if the checkbox is checked it adds an eventListener to body.document
DR.prototype.toggleMove = function(e, self){
if(self.moveButton.checked){
document.body.addEventListener("click", function bodyEvent(e){self.removeableEventHandler(e, self)}, false);
}else{
console.log("unchecked");
document.body.removeEventListener("click", function bodyEvent(e){self.removeableEventHandler(e, self)}, false);
}
}
if i don't wrap self.removeableEventHandler in a function i am unable to attach self to the function, but when i wrap it in a function i will be unable to remove the event when the checkbox is unchecked.
DR.prototype.removeableEventHandler = function(e, self){
console.log(e.clientX, e.clientY);
self.ele.style.top = e.clientY + "px";
self.ele.style.left = e.clientX + "px";
};
So it seems to be like I'm having a bit of a scope conundrum here. Not sure how to fix it. I'm trying to make a form moveable when the checkbox is checked and then removing the move event when the checkbox is unchecked.
removeEventListener works by passing the original function reference. If you pass a copy it wont work.
You can do:
DR.prototype.toggleMove = (function () {
var boundBodyEvent;
function bodyEvent(e) {
this.removeableEventHandler(e);
}
return function (e) {
if (this.moveButton.checked) {
boundBodyEvent= bodyEvent.bind(this);
document.body.addEventListener("click", boundBodyEvent, false);
} else {
document.body.removeEventListener("click", boundBodyEvent, false);
}
};
}());
I don't think you need to pass self around, that seems strange to me. I'm using bind to override the this in bodyEvent to refernce your DR instance instead of the DOM Element.
I'm also using immediate invocation to avoid having to put the bodyEvent in the global scope.
Alternatively, you could also not bother removing the event listener and have a switch inside the event listener:
DR.prototype.init = function () {
var self = this;
document.body.addEventListener("click", function (e) {
if (self.moveButton.checked) {
self.removeableEventHandler(e);
}
}, false);
}
removeEventListener callbak function need to be reference to the same function as in addEventListener, try this:
function bodyEvent(e) {
self.removeableEventHandler(e, self);
}
DR.prototype.toggleMove = function(e, self) {
if (self.moveButton.checked) {
document.body.addEventListener("click", bodyEvent, false);
} else {
console.log("unchecked");
document.body.removeEventListener("click", bodyEvent, false);
}
};

How to assing new mouse event on node without overriding those set earlier?

Example:
domNode.onmouseover = function() {
this.innerHTML = "The mighty mouse is over me!"
}
domNode.onmouseover = function() {
this.style.backgroundColor = "yellow";
}
In this example the text won't change, but the thing is also that I don't always know what was assigned before, so is there a way to tell to js: Run everything that was eventually assigned without knowing what was that and then run my function?
It's possible to do this by passing the current event handler to the new handler:
domNode.onmouseover = function()
{
console.log('first handler');
}
domNode.onmouseover = (function (current)
{
return function()
{
current();//call handler that was set when this handler was created
console.log('new handler');
};
})(domNode.onmouseover);//pass reference to current handler
See this fiddle, to see it in actionYou can keep on doing this as much as you want/need:
domNode.onmouseover = function()
{
console.log('first handler');
}
domNode.onmouseover = (function (current)
{
return function()
{
current();
console.log('second handler');
};
})(domNode.onmouseover);
domNode.onmouseover = (function (current)
{
return function()
{
current();
console.log('third handler');
};
})(domNode.onmouseover);
This will log:
first handler
second handler
third handler
That's all there is to it!
First of all, place it in a document.ready. (not sure if you done that)
If you want 2 actions for one action place it in once function.
You can also create 2 functions and call them in your mouseover.
$(document).ready(function(){
domNode.onmouseover = function() {
this.innerHTML = "The mighty mouse is over me!"
this.style.backgroundColor = "yellow";
}
});

Can multiple event listeners/handlers be added to the same element using Javascript?

I have:
if (window.addEventListener) {
window.addEventListener('load',videoPlayer,false);
}
else if (window.attachEvent) {
window.attachEvent('onload',videoPlayer);
}
and then later I have:
if (window.addEventListener) {
window.addEventListener('load',somethingelse,false);
} else if (window.attachEvent) {
window.attachEvent('onload',somethingelse);
}
Is it preferred/functional to have them all together? Like
if (window.addEventListener) {
window.addEventListener('load',videoPlayer,false);
window.addEventListener('load',somethingelse,false);
} else if (window.attachEvent) {
window.attachEvent('onload',videoPlayer,false);
window.attachEvent('onload',somethingelse);
}
You can do how ever you want it to do. They don't have to be together, it depends on the context of the code. Of course, if you can put them together, then you should, as this probably makes the structure of your code more clear (in the sense of "now we are adding all the event handlers").
But sometimes you have to add event listeners dynamically. However, it is unnecessary to test multiple times whether you are dealing with IE or not.
Better would be to abstract from this and test only once which method is available when the page is loaded. Something like this:
var addEventListener = (function() {
if(document.addEventListener) {
return function(element, event, handler) {
element.addEventListener(event, handler, false);
};
}
else {
return function(element, event, handler) {
element.attachEvent('on' + event, handler);
};
}
}());
This will test once which method to use. Then you can attach events throughout your script with:
addEventListener(window, 'load',videoPlayer);
addEventListener(window, 'load',somethingelse);
I use this function:
function addEvent (obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
} else if (obj.attachEvent) {
obj.attachEvent('on' + type, function () {
return fn.call(obj, window.event);
});
}
}
/**
* multipleEventsListeners.js
* Add the capability to attach multiple events to an element, just like jQuery does
* https://gist.github.com/juanbrujo/a1f77db1e6f7cb17b42b
*/
multipleEventsListeners(events, func, elem) {
elem = elem || document;
var event = events.split(' ');
for (var i = 0; i < event.length; i++) {
elem.addEventListener(event[i], func, false);
}
}
/*
Use:
var input = document.querySelector('input');
multipleEventsListeners(input, 'keyup change', function(e){
console.log = this.value;
});
*/
from: https://gist.github.com/juanbrujo/a1f77db1e6f7cb17b42b
by using a named function and passing that into your event listener, you can avoid having to write the same code over and over again.
// Setup our function to run on various events
var someFunction = function (event) {
// Do something...
};
// Add our event listeners
window.addEventListener('click', someFunction, false);
window.addEventListener('mouseover', someFunction, false);
addEventListener automatically passes the event object into your function as an

Categories

Resources