mouse eventlistener isnt being removed - javascript

Im trying to remove an eventlistener that I initialize somewhere in the code and then remove later in a function. I know that you have to remove the same listener that you initialized, but it doesnt seem to be working. I store the eventlistener in a variable that I believe has global scope, so Im not sure what the issue is. The eventlistener itself works fine, and starts as expected.
I have also tried not storing the eventlistener in a variable but that didnt work either.
mainFunction = function (){
mousee = document.addEventListener('mouseout', mouseEvent);
if ($(".message_input").val().replace(/\s/g, "").length > 0){
unbindAll(true); // unbind all functions
message = getMessageText(); // retrieve the users message text
$(".message_input_wrapper").html("");
printMessage(message, "right"); // display there message on the screen
if (message=="stop"){
document.removeEventListener(mousee);
initiateStopSection();
} else {
//async_elipsis();
response = async_bot(message);
};
};
};
Just for clarification, I was initially using
document.removeEventListener("mouseout", mouseEvent)
but it wasnt working

When using removeEventListener, you have to pass the event type and the event handler, so in this case you would use
document.removeEventListener("mouseout", mouseEvent)

removeEventListener takes 2 arguments. The first is the event you are trying to target, in this case mouseout, and the second is the function you wish to remove.
For your example it would be this:
document.removeEventListener("mouseout", mouseEvent)
There is no need to set the initial listener to a variable with this implementation.

Related

What is the returned value of a clicked <button>?

I want to get the returned value of a clicked button, and then use it to make an if statement. All the answers that I read here about people trying to do that are either very old using old script that doesn't work anymore, or not the same case.
function remove() {
if (document.getElementById("removing").value == true) {
document.getElementById("test").style.backgroundColor = "red";
}
}
<div id="test">test</div>
<button id="removing" onclick="remove()">Remove a word</button>
I have tried using the value property, and onclick, but non of them equal true when the button is clicked.
I tried using alert to display the value, but it displays nothing.
Does clicking a button actually returns a value, and if so, what is it?
DOM Events are handled by an EventListener's callback function.
Thus such a handler function, if triggered by an event and forwarded by an event listener's handleEvent method, always will be invoked with an event object as this function's single argument.
All information related to this event are carried by the event itself. Its properties can be read and some even can be written/changed.
It is obvious from the provided example that the OP wants to assure that an event handler has been triggered by just a specific html element. Thus any valid approach just needs to look into the event's currentTarget property ...
// the way the OP might want to handle the problem.
function handleRemoveWord(evt) {
const elmNode = evt.currentTarget;
// make sure the handler was
// triggered by the intended element ...
// ... here by comparing node properties.
if (
(elmNode.tagName.toUpperCase() === 'BUTTON')
&& (elmNode.id === 'remove')
) {
document
.getElementById('test')
.style.backgroundColor = 'red';
}
}
// another way the OP might want to handle the problem.
function handleRemoveAnotherWord(evt) {
// `this` referres to the element which got
// bound to the handler via `addEventListener`.
const targetNode = this;
// make sure the handler was
// triggered by the intended element ...
// ... here by comparing node references.
if (targetNode === evt.currentTarget) {
document
.getElementById('test')
.style.backgroundColor = 'cyan';
}
}
// an alternative way of solving the problem
// of always being assured about the correct
// element having triggering the event handling.
function handleRestoreWordWithBoundContext(evt) {
const context = this;
const { elmTest, elmRestore } = context;
// make sure the handler was
// triggered by the intended element ...
// ... here by comparing node references.
if (elmRestore === evt.currentTarget) {
elmTest.style.backgroundColor = '';
}
}
function initialize() {
// the way(s) the OP might want to handle the problem.
document
.getElementById('remove')
.addEventListener('click', handleRemoveWord);
document
.querySelector('#removeAnother')
.addEventListener('click', handleRemoveAnotherWord);
// an alternative way of soving the problem
// of always being assured about the correct
// element having triggering the event handling.
const elmTest = document.querySelector('#test');
const elmRestore = document.querySelector('#restore');
elmRestore.addEventListener(
'click',
handleRestoreWordWithBoundContext.bind({
elmTest,
elmRestore,
})
);
}
initialize();
<div id="test">test</div>
<button id="remove">Remove a word</button>
<button id="removeAnother">Remove another word</button>
<button id="restore">Restore a word</button>
As one might have noticed, the example features a third button with yet another way of implementing an event handler. This additional handler assumes its this context to carry additional information. This is possible by invoking bind on this handler function and providing exactly the information one wants to be present as the event handlers this context. Every time this function specific method is invoked it creates another function which does have access to the bound information via the this keyword.
Simply change background color onClick of button as:
function remove() {
document.getElementById("test").style.backgroundColor = "red";
}
<div id="test">test</div>
<button id="removing" onclick="remove()">Remove a word</button>
Dispatching Javascript event handlers always returns true, even if it returns false, which we all know is used to prevent default behaviour of an event. We don't usually use the return values of Event handlers or even return anything for that matter.
In your case, I think you're trying to acess the value of the currentTarget element(the button 'removing' in your case). For this you can use the event object, which gets passed on as parameter to your event handler.
event.currentTarget is a way of referencing the element on which an event is being dispatched(triggered) on. It's just like using 'this' inside the event handler, except it also works on arrow functions.
So do something like this:
function remove(event) {
let button = event.currentTarget;
if (buttton.value) {
document.getElementById("test").style.backgroundColor ="red";
}
}
and in HTML,
<div id="test">test</div>
<button id="removing" onclick="remove(event)">Remove a word</button>
Notice I've used remove(event).
Edit Based on comment below:
Using onclick will require you to create you a global 'remove' function.
If you do, '...onclick="remove(event)" what it basically does is creates the function below, a wrapper basically:
// In the global scope
[reference element].onclick = () => {
remove(event);
}
So you must have a global 'remove' function. So this won't work in modules cause each modules have their own top level scope. And you're gonna wanna have to use modules if you plan to work on sophisticated projects.
NOTE Using inline 'onclick' attributes in html has following disadvantages on heavy requests from a comment below:
-separation of concern : You usually don't want to mix up your UI logic(what happens on clicking a button) with presentation. You want a clear split between content, style and script.
-only one handler can be assigned using onclick.
-if an event is specified inline, the JS is specified as a string (attribute values are always strings) and evaluated when the event fires.(extra wrapper code builds internally).
-as I've mentioned before, you are faced with having to reference named functions. This is not ideal and has implications on the function needing to be global which will really bite you back when you use modules.
In short, handle events centrally via the dedicated addEventListener API.

removeEventListener doesn't work, and no error's are returned

As you can see in the code below I'm trying to remove an mouse move event listener however this listener doesn't get removed, and no errors are returned, as you can see the first time you double click on the menu the listener gets added, this works fine. the second time you double click it should get removed..
but it does not. I'm I removing it the wrong way ? can someone please help me with this problem I would really appreciate it..
function DragMenus()
{
ClickedSoManyTimes = 0;
Menu = document.getElementsByClassName("Box1");
AllMns = [Menu[1], Menu[2], Menu[3], Menu[4]];
var i;
for (i = 0; i < AllMns.length; i++)
{
AllMns[i].addEventListener("dblclick", function(i)
{
function MouseMove()
{
// Do Something
};
ClickedSoManyTimes = ClickedSoManyTimes + 1;
if(Number.isInteger(ClickedSoManyTimes/2))
{
console.log("Stop");
// delete Listener
document.removeEventListener("mousemove", MouseMove); // Fails
}
else
{
console.log("Start");
document.addEventListener("mousemove", MouseMove);
};
});
};
};
As described in this answer, the event listener can only be removed by using a reference to the original function that you referenced when you created it. In your code, multiple event listeners are created on the document, and each gets its own function MouseMove. When you then double-click another one of the items, it tries to remove an event listener related to its copy of MouseMove, but that may not be the copy that was originally used.
The best remedy is to take the definition of MouseMove out of your double-click-eventhandler, so it is one function instead of many that have the same name but are not the same function.

Listen to a mouse event on condition

I want to "listen to" a mouse event only if a checkbox is clicked. Therefore I have the following code:
HTML
<input type="checkbox" id="magicLens" onchange="magicLens()">
<label for="magicLens">Magic Lens</label>
JS
function magicLens(){
const magicLens_checked = document.getElementById('magicLens').checked;
if (magicLens_checked === true){
canvas.addEventListener('mousemove', e => {
myAnonymous = arguments.callee;
...
// draw something at the current mouse position
// and therefore use the 'e' event object
});
}
else {
canvas.removeEventListener('mousemove', myAnonymous);
}
}
Problem is, that the drawing (a lens) also occurs when the checkbox is not checked (false). I'm not even sure if removeEventListener() is the right way to deal with it (though I already tried the whole thing without it and result was the same).
Maybe you have a better idea to describe the issue in the title. Feel free to edit!
It's easier to actually always listen to the event and in there check whether the checkbox is checked.
const canvas = document.getElementById('canvas');
canvas.addEventListener('mousemove', e => {
const magicLens_checked = document.getElementById('magicLens').checked;
if (!magicLens_checked) {
return;
}
// Do something with e
console.log(e);
});
You can check it out in this Fiddle. (I added the event listener to document, to avoid creating an arbitrary canvas, but it works the same way)
The Javascript engine sees what you pass to addEventListener and removeEventListener as two different functions which is why the removeEventListener is not working. Create a named function outside of these and pass it into them.

How to remove an event listener in Hammer.js 2.0 and bind the recognizer to a new function

I am a bit confused on how to correctly remove an event listener in Hammer.js 2.0
Following the advice in this question it seems I just need to use
mc.off(eventString, functionEvent);
However I can't seem to get this to work, when I have 2 functions which I need to call with the same recognizer. My example is I need someone to panleft, then I need to remove this listener and listen for another panleft.
As you can see in my simplified codepen example I try to call mc.off in the first function, then set up the next event, but it runs both simultaneously.
So what I want in my example is for the first panleft to trigger the first function, then the second panleft to trigger a new function
var myElement = document.getElementById('myElement');
var mc = new Hammer(myElement);
mc.on("panleft", function(ev) {
selectFirst('first')
});
function selectFirst (text) {
myElement.textContent = text;
mc.off('panleft', selectFirst);
mc.on("panleft", function(ev) {
selectSecond('second')
});
}
function selectSecond (text) {
myElement.textContent = text;
}
As indicated in the question I linked to above and its jsfiddle
As was mentioned in that answer, you can fix the issue by not using an anonymous function.
hammertime.on("touch", callback);
However it didn't seem to fix my issue of trying to remove the initial function and bind to a new one with the same recognizer.
I ended up just adding a new element and binding this to the second function. I suggest the same as you probably should only have 1 panleft event for the element and if it needs to do something different just add another hammer element with the panleft on it.

How remove onClick, and then add it again later?

I need a method to enable and disable any element. Disable meaning set the opacity to 0.6 and remove the onClick callbacks. Enable meaning set the opacity to 1 and add the callback again.
My first two attempts failed miserably, the callback methods just got stacked and instead of running it once after each click the method was running more and more times.
function disableElement(element){
var el = $('#'+element);
el.css('opacity','0.6');
el.on('click',null); //this doesn't work
el.removeAttr('onClick'); // this doesn't help either.
}
function enableElement(element,callback){
var el = $('#'+element);
el.css('opacity','1');
el.on('click',callback);
}
Then i tried using the el.data:
disableElement:function(element){
var el = $('#'+element);
el.css('opacity','0.6');
el.data('element-enabled','false');
//el.click(function (){
// alert('disabled');
//});
},
enableElement:function(element,callback){
console.log('enabling');
var el = $('#'+element);
console.log(el);
if(el.data('element-enabled') == "true")
return;
console.log("setOpacity");
el.css('opacity','1');
el.data('element-enabled','true');
el.click(function(){
if(el.data('element-enabled') == "true")
callback();
});
}
Now they don't stack, as long as I don't disable it. If I disable and then enable it again, it gets stacked. Which means, if i run enableElement multiple times the callbacks don't stack. But once I run disableElement and then enableElement, if i click in the item, it'll happen twice.
Can achieve that somehow?
UPDATE
That was close. The off worked for me but i also had to remove it on the enableElement. Occasionally I have to call it twice, so it was still stacking. Finally this worked, thank you!
disableElement:function(element){
var el = $('#'+element);
el.css('opacity','0.6');
el.off('click');
},
enableElement:function(element,callback){
var el = $('#'+element);
el.off('click');
el.css('opacity','1');
el.on('click',callback);
}
To remove the event just use .off()
el.off('click');
To add the event back you can just do
el.on('click',callback);
You need to use .off as in .off('click'). That will remove all bound events of the click type. Documentation for .off
Note that if you use .off it doesn't return the event or anything, and you can't simply rebind with .on. However, since you have defined the callback in a separate function, you're good to go since you do re-bind as .on('click', function_name). It's just something to be aware of.
Unbind will remove all handlers assigned to the object for some event:
$('#foo').unbind('click');
You can also set this to some specific function by adding it as a second argument
$('#foo').unbind('click', myfunctionname);

Categories