Removing event listeners - javascript

I have a canvas element in which I draw something using WebGL.
Depending on what is drawn I am adding an event listener.
Now when I am redrawing the canvas, I want to remove the old event listener and add a new one.
Simply doing this will not work:
canvas.removeEventListener("click", function(event){
colorbarClicked(event, viewdata);
}, false);
canvas.addEventListener("click", function(event){
colorbarClicked(event, viewdata);
}, false);
I think it is because the colorbarClicked function has already changed (maybe because its parameters have different values?) and not matching the old one which I want to remove any more.
So my problem is that each time I am redrawing event listeners get added and therefore doubled. But the colorbarClicked function depends on what is drawn in the canvas, so I definitely need to change it.

You need to remember the function you used when adding, and use that same function again when removing:
// Somewhere *outside* the code doing the adding/removing (in containing code)
var listener = null;
// In the code adding/removing
if (listener) {
canvas.removeEventListener("click", listener, false);
}
listener = function(event){ colorbarClicked(event, viewdata); };
canvas.addEventListener("click", listener, false);
Side note: Adding and removing a handler every time seems awkward. Normally, you'd want to just add the handler the once, and have it respond to whatever changes you make.

You can use named functions. Take the example below:
function foo(){
alert("this comes only once");
this.removeEventListener('click', foo);
}
dude.addEventListener('click', foo);
<button id="dude">Click Me</button>
What is happening here is that the function foo is defined in the global scope. It has a unique identity of it's own. What the function basically does is that it creates an alert, and then removes itself from the click event for the button. So when you click it, the listener is removed, and thus, you no longer see it.
Your code doesn't work as intended because the function you pass as callback to addEventListener has no unique identity, and Javascript doesn't know what to remove.
This method also prevents things like callback hell :)

Related

Stop function from functioning

So I'm modifying a webpage, it has a button, it is coded so mouseup goes to a link, I want to change this, adding mouseup functions don't work; mousedown works but I have to hold the mousedown for a second or two otherwise the original function still occurs.
var duma = $('input')[0].value;
var siq = $('.inline-nav-menu__link')[1];
$(siq).mousedown(function(){
window.location = 'https://www.google.com/search?q='+duma+'&sxsrf=APq-WBtOrInsFht_VAH6gWFlCceGK46ylQ:1649149133894&source=lnms&tbm=isch&sa=X&ved=2ahUKEwjdvbqix_z2AhWtxzgGHW7GCh0Q_AUoAXoECAIQAw&biw=1366&bih=696&dpr=1';
})
This works but I have to keep the mouse held down for a lil bit
Changing that to mouseup doesn't work
I inspected the element further, it had an attribute named formAction which had the link to the respective page. Changing said attribute solved the first problem. But now the page is going to google web instead of images...
var duma = $('input')[0].value;
var siq = $('.inline-nav-menu__link')[1];
$(siq)[0].formAction='https://www.google.com/search?tbm=isch&q='+duma+'';
When you add an event listener, you're creating a function (that is a Javascript object) and binding it to a specific event.
To remove the listener, you have to pass to .removeEventListener() a reference to that same function.
Working with jQuery, there's also the element.off('event_type') method, but it works only on listeners previously attached with the jQuery .on('event_type') method.
If the listener refers to a named function you can do element.removeEventListener('event', functionName).
If the listener is an anonymous function I'd do one of these:
A) clone the element with jQuery clone() method, so that the cloned element will not have any event listeners attached anymore. Then you could attach your own listeners.
B) if you don't need the original event listener, you can also disable it doing like this:
function stopEvent(event) {
event.stopImmediatePropagation();
}
element.addEventListener('mouseup', stopEvent, true);
This way, using the true option in .addEventListener, you stop any event propagation at the beginning of the capturing phase, so the event itself will never reach its target (for that mouseup event only).
The cons of the second option is that you cannot use that event anymore on that element, as it will never reach the target.
But, as you used a named function to stop the propagation, you can now remove it with element.removeEventListener('mouseup', stopEvent, true) and bring back the original event listener to work again (because removing stopEvent, now the event propagates again to its target).
Figured it out. Needed to change form values.
Used the info on google search forms from link.
https://stackoverflow.com/a/65032682/10824788
var duma = $('input')[0].value;
var siq = $('.inline-nav-menu__link')[1];
var derka = 'https://www.google.com/search?tbm=isch&';
$(siq)[0].form[2].name="q";
$(siq)[0].form[2].value=duma;
$(siq)[0].form[4].name="tbm"
$(siq)[0].form[4].value="isch"
$(siq)[0].formAction=derka;

How would I detect clicks in javascript?

I'm building a little web game in node.js, and I've been using event listeners for input, and it's worked fine for things like key presses and mouse movement.
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
window.removeEventListener("mousemove", onMouseInput);
(all of these have worked perfectly)
But when I tried using the mouseup/mousedown events (and also pointerup/pointerdown), they won't register. Is there something I'm doing wrong? Does it have to click on something?
window.addEventListener("pointerdown", changeShooting(true));
window.addEventListener("pointerup", changeShooting(false));
(doesn't work)
You have to pass a function to addEventListener, while you are passing the result of the call to changeShooting (which I assume does not return a function).
In order to do that, you can define an inline function like:
window.addEventListener("pointerdown", function() {
changeShooting(true)
});
If you need to remove the listener later, you have to define it explicitly:
function onPointerDown() {
changeShooting(true);
}
window.addEventListener("pointerdown", onPointerDown);
// later somewhere
window.removeEventListener("pointerdown", onPointerDown);

Should I / how do I clear a mousemove JQuery event listener?

When I use
$(".page").mousemove(function(event){});
As soon as the mouseup event comes, I no longer need this listener. Since I'll be applying the listener repetitively for different actions, it seems to me that these listeners might stick around and build up (needlessly wasting CPU) as the user activates the function many times. I'm not really sure how this works internally, that's just my guess.
Should I / how do I clear a mousemove JQuery event listener?
Here is the code:
$('.page').off('mousemove');
But please note that the following approach turns off all functions firing on mousemove. If you want to turn off a prticular function then you should do the following:
// Define function that fires on mousemove
function anyFunctionName () {
// Some code
}
// Set listener
$('.page').on('mousemove', anyFunctionName);
// Turn off only function called funcionName
$('.page').off('mousemove', anyFunctionName);
Another way for turning off a particular function would is defining a name for the event:
// Define function that fires on mousemove
function anyFunctionName () {
// Some code
}
// Set listener
$('.page').on('mousemove.anyEventName', anyFunctionName);
// Turn off only function fired on event called anyEventName
$('.page').off('mousemove.anyEventName');
I was able to get a working example using the more general .on and .off JQuery functions instead of their explicit handlers. Here is the code I used:
$('.page').on('mousedown', function() {
$(this).on('mousemove', function(event) {
// Do something meaningful
});
});
$('.page').on('mouseup', function() {
$(this).off('mousemove');
});
Here is a JFiddle Demo of it.

javascript/jquery How to cancel .on when a class is present

I have several places throughout my code where I use .on to attach events (usually to delegate the events). We're changing around how we're doing a few things, and we're now wanting to add a .disabled class to the elements that we want to be disabled. I'd like to block all the events on disabled items without having to refactor each location, I'm wondering if it's possible.
Example code: I've added this to the top of my script
$('body').on('click', '.disabled', function(event){
console.log("blocked");
event.stopImmediatePropagation();
// event.preventDefault();
// event.stopPropogation();
return false;
});
And an example of my normal events:
$('.ActionsContainer').on('click', '.Link', functions.ClickAction);
Problem is that even with the return false and all the others it still runs both the "blocked" and functions.ClickAction
Is there anyway around refactoring every one? I mean I can change that line below to:
$('.ActionsContainer').on('click', '.Link:not(.disabled)', functions.ClickAction);
but that's really annoying, and feels brittle.
It's not too hard. You'll need to take advantage of jQuery's special events and basically override calls to any of the original event handlers setup in the existing code. jQuery's special events hooks let you override a number of features of the event system. jQuery essentially sets up it's own handler on an element the first time a listener is attached, and then adds the callback for the listener to its queue. As other listeners get attached to the element later, their callbacks get added to this queue as well.
Using the 'events.special.click' hook, we can add a function that gets called prior to any callbacks on that element's event queue which lets us intercept the call and check for, as you mentioned, that the element has a 'disabled' class and if so, stop the original callback from executing; or if it doesn't have the class, allow the original callback to execute normally.
I've put together a jsFiddle to show how it works. See if that solves your issue. The code for the override using special events is embedded below the link:
http://jsfiddle.net/datchley/bthcv/
// ADDED TO OVERRIDE CLICKS ON 'DISABLED' ELEMENTS
(function($) {
$.event.special.click = {
add: function(handle) {
// Save original handler
var orig_handlefn = handle.handler,
$el = $(this);
// Reassign our new handler to intercept here
handle.handler = function(ev) {
if ($el.hasClass('disabled')) {
// Don't allow clicks on disabled elements
$('.output').html('<b>Warning</b> You clicked a disabled element!');
ev.preventDefault();
}
else {
return orig_handlefn.apply(this, arguments);
}
};
}
};
})(jQuery);
Assuming every .Link has that container and you're handling all events at that container, this is the most straightforward way:
$('.disabled').click( function(e){ e.stopPropagation(); } );
stopProp prevents that event from ever bubbling up to the action containers.

MooTools/JS: bindWithEvent

There's this piece in the codebase I'm working on:
this.element.addEvent('click', this.clickEvent.bindWithEvent(this));
I want to change it so that the click event makes sure the window is loaded first. So I tried:
var t = this;
this.element.addEvent('click', function() {
window.addEvent('load', function() {
t.clickEvent.bindWithEvent(t));
});
});
That doesn't seem to get it to work though. What am I missing?
You're adding a handler to the load event when the user clicks something, _aftertheload` event has already fired. Therefore, nothing happens.
You should probably add the click handler inside of an event handler for the load event. (swap the two addEvent lines)
in mootools you tend to use domready and not load but essentially, doing it as suggested will not work as it lacks the context here:
this.element.addEvent('click', this.clickEvent.bindWithEvent(this));
so you are working within a class here - therefore, make sure you instantiate it on the domready event instead, something like...
window.addEvent("domready", function() {
// whatever you need to do...
var foo = new myClass($("someElement"), {option: value}); // example instantiation
// if the binding is not in the .initialize, then call the right method...
// foo.bindMyEvents();
});
as long as the class instance is within domready, you're fine. if that's not an option, see which method binds the events and call that on the domready instead.

Categories

Resources