Is there there an initial keypress event in JavaScript? [duplicate] - javascript

I want to have a onkeydown event fire a function only once. for that function to fire again, the user has to release the key and press/hold again.
I know its fairly simple but I'm new at JS. Also I prefer to avoid using jQuery or other libs.
One more thing, this should work for both ie and firefox.

I'm surprised it's not mentioned, there's also event.repeat:
document.addEventListener('keydown', (e) => {
if (e.repeat) return;
console.log(e.key);
});
This will only fire once per each keypress, since event.repeat turns true after holding the key down.
https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key#keyboardevent_sequence

You could set a flag:
var fired = false;
element.onkeydown = function() {
if(!fired) {
fired = true;
// do something
}
};
element.onkeyup = function() {
fired = false;
};
Or unbind and rebind the event handler (might be better):
function keyHandler() {
this.onkeydown = null;
// do something
}
element.onkeydown = keyHandler;
element.onkeyup = function() {
this.onkeydown = keyHandler;
};
More information about "traditional" event handling.
You might also want to use addEventListener and attachEvent to bind the event handlers. For more information about that, have a look at quirksmode.org - Advanced event registration models.

There's a "once" parameter you can use
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
Eg:
element.addEventListener('keydown', function(event) {
doSomething()
}, {once: true});
It'll remove it as soon as it's been called.
Alternatively you can use removeEventListener if it's a named function

Here is a method that uses addEventListener and removeEventListener
var textBox = document.getElementById("textBox");
function oneKeyDown(){
$("body").append("<h1>KeyDown<h1>"); //just to show the keypress
textBox.removeEventListener('keydown', oneKeyDown, false);
}
function bindKeyDown(){
textBox.addEventListener('keydown', oneKeyDown, false);
}
textBox.addEventListener('keyup', bindKeyDown, false)
bindKeyDown();
Code example on jsfiddle.
One note, for IE you will need to use attachEvent, detachEvent.

Here you go:
test.onkeydown = function() {
if ( this.className === 'hold' ) { return false; }
this.className = 'hold';
// call your function here
};
test.onkeyup = function() {
this.className = '';
};
Live demo: http://jsfiddle.net/simevidas/xAReL/2/

JQuery's one will help you.
What it does is, bind the eventHandler to event, and when event occurs, it runs the eventHandler and unbinds it, so that its not fired at next event.

as stated in the other answers, there is no 'onkeyfirstdown' or similar event to listen for.
the best solution is to keep track of which keys are already down in a js-object:
var keysdown = {};
element.addEventListener('keydown', function(evt) {
if(!(evt.key in keysdown)) {
keysdown[evt.key] = true;
// key first pressed
}
});
element.addEventListener('keyup', function(evt) {
delete keysdown[evt.key];
});
this way, you will not be skipping 'keyfirstpressed' events if more than one key is held down.
(many of the other solutions posted here will only fire when no other keys are down).

Here is my solution that will only run the function you pass it when a key is FIRST pressed on the target (eg window or some input field). If the user wants to trigger a key again, they'll have to release it and press it again.
Vanilla JS
const onKeyPress = (func, target = window) => {
// persistent "store" to track what keys are being pressed
let pressed = {};
// whenever a keydown event is fired ontarget element
const onKeyDown = (event) => {
// if key isn't already pressed, run func
if (!pressed[event.which])
func(event);
// add key to store
pressed = { ...pressed, [event.which]: true };
};
// whenever a keyup event is fired on the window element
const onKeyUp = (event) => {
const { [event.which]: id, ...rest } = pressed;
// remove key from store
pressed = rest;
};
// add listeners
target.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
// return a function that can be called to remove listeners
return () => {
target.removeEventListener('keydown', onKeyDown);
window.removeEventListener('keyup', onKeyUp);
};
};
And then to use it:
const removeListener = onKeyPress((event) => console.log(event.which + ' key pressed'))
removeListener(); // when you want to remove listeners later
React and React Hooks
import { useState } from 'react';
import { useEffect } from 'react';
import { useCallback } from 'react';
export const useKeyPress = (func, target = window) => {
// persistent "store" to track what keys are being pressed
const [pressed, setPressed] = useState({});
// whenever a keydown event is fired ontarget element
const onKeyDown = useCallback(
(event) => {
// if key isn't already pressed, run func
if (!pressed[event.which])
func(event);
// add key to store
setPressed({ ...pressed, [event.which]: true });
},
[func, pressed]
);
// whenever a keyup event is fired on the window element
const onKeyUp = useCallback((event) => {
// remove key from store
const { [event.which]: id, ...rest } = pressed;
setPressed(rest);
}, [pressed]);
useEffect(() => {
// add listeners when component mounts/changes
target.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
// cleanup/remove listeners when component unmounts/changes
return () => {
target.removeEventListener('keydown', onKeyDown);
window.removeEventListener('keyup', onKeyUp);
};
}, [target, onKeyDown, onKeyUp]);
};
And then to use it:
import { useKeyPress } from 'wherever';
useKeyPress((event) => console.log(event.which + ' key pressed'))

Related

Remove event listener doesn't work as it should

I simply tried to addEventListener and removeEventListener to element, but it doesn't remove.
I suppose that the problem could be with parameters, but I used them to follow the DRY. So I could simply reuse it like nextSection.addEventListener('mouseover', showContent(event, nextSection)) and so on and so on so I do not need any if statements or stuff like that.
* EDIT *
I made some more examples of elements that I will be using. There’s a chance, that there will be event more. If I do not use parameter, there would be a lot more of functions. Also, there will be click instead of mouse events on mobile, so I need to remove them.
As I understand now, the problem is with return statement. If I use event instead of parameter and so event.target I get some weird bug.
const loginSection = document.querySelector('#js-login-section');
const searchSection = document.querySelector('#js-search-section');
const shoppingBagSection = document.querySelector('#js-shopping-bag-section');
const wishlistSection = document.querySelector('#js-wishlist-section');
function showContent(element) {
return () => {
const toggle = element.lastElementChild;
toggle.style.maxHeight = toggle.scrollHeight + 'px';
}
}
function hideContent(element) {
return () => {
const toggle = element.lastElementChild;
toggle.style.maxHeight = null;
}
}
/* Media queries - min width 992px */
loginSection.addEventListener('mouseover', showContent(loginSection));
loginSection.addEventListener('mouseout', hideContent(loginSection));
searchSection.addEventListener('mouseover', showContent(searchSection));
searchSection.addEventListener('mouseout', hideContent(searchSection));
shoppingBagSection.addEventListener('mouseover', showContent(shoppingBagSection));
shoppingBagSection.addEventListener('mouseout', hideContent(shoppingBagSection));
wishlistSection.addEventListener('mouseover', showContent(wishlistSection));
wishlistSection.addEventListener('mouseout', hideContent(wishlistSection));
/* Media queries - max width 992px */
loginSection.removeEventListener('mouseover', showContent(loginSection));
loginSection.removeEventListener('mouseout', hideContent(loginSection));
searchSection.removeEventListener('mouseover', showContent(searchSection));
searchSection.removeEventListener('mouseout', hideContent(searchSection));
shoppingBagSection.removeEventListener('mouseover', showContent(shoppingBagSection));
shoppingBagSection.removeEventListener('mouseout', hideContent(shoppingBagSection));
wishlistSection.removeEventListener('mouseover', showContent(wishlistSection));
wishlistSection.removeEventListener('mouseout', hideContent(wishlistSection));
Thank you in advance!
What is happening is that return () => {}; is returning a new function every time it's run. So every time you call one of your functions a new event handler is being created.
This means that the handler that is added is different to the one you're trying to remove.
To remedy this, I'd keep it simple:
const loginSection = document.querySelector('#js-login-section');
function showContent(e)
{
const toggle = e.currentTarget.lastElementChild;
toggle.style.maxHeight = toggle.scrollHeight + 'px';
}
function hideContent(e)
{
const toggle = e.currentTarget.lastElementChild;
toggle.style.maxHeight = null;
}
loginSection.addEventListener('mouseover', showContent);
loginSection.addEventListener('mouseout', hideContent);
loginSection.removeEventListener('mouseover', showContent);
loginSection.removeEventListener('mouseout', hideContent);
I'm not sure what you want to avoid repeating, so I can't advise on that, but I'm sure you'll figure it out.
const loginSection = document.querySelector('#js-login-section');
function showContent(event) {
var element = event.target;
return () => {
const toggle = element.lastElementChild;
toggle.style.maxHeight = toggle.scrollHeight + 'px';
}
}
function hideContent(event) {
var element = event.target;
return () => {
const toggle = element.lastElementChild;
toggle.style.maxHeight = null;
}
}
loginSection.addEventListener('mouseover', showContent);
loginSection.addEventListener('mouseout', hideContent);
loginSection.removeEventListener('mouseover', showContent);
loginSection.removeEventListener('mouseout', hideContent);
You must set in events method function without call. Element you can get from event event.target
In your code, I found the following errors,
param 'event' will be always undefined - the event should go as a parameter to inner function.
you don't need closure here - You can directly assign the function without creating an inner function and access the element with event.target or this
with your implementation, you should pass the same handler reference used in addEventListener to removeEventListener. So, you should store the handler in a variable and pass it to both addEventListener and removeEventListener
Solution:
if you don't know the handler name, you can use window.getEventListeners to do the magic,
window.getEventListeners returns a dictionary of events associated with the element.
function removeEventListener(el, eventName) {
if (!el) {
throw new Error('Invalid DOM reference passed');
}
const listeners = getEventListeners(el)[eventName] || [];
listeners.forEach(({
listener
}) => {
removeEventListener(eventName, listener);
});
}
function removeAllEventListener(el) {
if (!el) {
throw new Error('Invalid DOM reference passed');
}
const events = Object.entries(getEventListeners(el) || {});
events.forEach(([eventName, listeners]) => {
listeners.forEach(({
listener
}) => {
removeEventListener(eventName, listener);
});
});
}
// example
// remove mouseout event
removeEventListener(loginSection, 'mouseout');
// remove all event listeners
removeAllEventListener(loginSection);

Use Javascript onclick or keydown for event

I'm using JavaScript and CSS to create keys that flips and play a sound. On the front side there is an image then when the key is pressed, it plays a sound and flips to revels the back which displays a different img and flips back over after the key is released. The code works for that purpose, but I want the same functionality for when someone also clicks the key. Can I have both?
function removeTransition(e) {
if (e.propertyName !== 'transform') return;
e.target.classList.remove('playing');
}
function playSound(e) {
const audio = document.querySelector(`audio[data-key="${e.keyCode}"]`);
const key = document.querySelector(`div[data-key="${e.keyCode}"]`);
if (!audio) return;
key.classList.add('playing');
audio.currentTime = 0;
audio.play();
}
const keys = Array.from(document.querySelectorAll('.key'));
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
window.addEventListener('keydown', playSound);
Yes, you can have both, you can do something like this:
function removeTransition(e) {
if (e.propertyName !== 'transform') return;
e.target.classList.remove('playing');
}
function playSound(e) {
let keyCode;
if (e.type === 'click') {
keyCode = e.currentTarget.dataset.key;
} else {
keyCode = e.keyCode;
}
const audio = document.querySelector(`audio[data-key="${keyCode}"]`);
const key = document.querySelector(`div[data-key="${keyCode}"]`);
if (!audio) return;
key.classList.add('playing');
audio.currentTime = 0;
audio.play();
}
const keys = Array.from(document.querySelectorAll('.key'));
keys.forEach(key => key.addEventListener('transitionend', removeTransition));
window.addEventListener('keydown', playSound);
keys.forEach(key => key.addEventListener('click', playSound))
I've used event.type to determine if the event is a click or a keydown and used element.dataset to retrieve the appropriate key in case of click events (these events don't have the keyCode property).
Also, in case of click events, event.target is actually the clicked key, you can use that instead of looking for the key in the DOM (the querySelector(`div[data-key="${keyCode}"]`) call).
Yes, as far as I am concerned, you can have as many event listeners per object as you want. Just use the relevant event listeners and attach them to the relevant HTML objects. Remember, in Javascript you need an event listener for each event.
For example: (from https://gomakethings.com/listening-to-multiple-events-in-vanilla-js/)
This doesn't work:
document.addEventListener('click mouseover', function (event) {
// this doesn't work
}, false);
Instead, you'll have to do something like this:
var someFunction = function (event) {
// Do something...
};
// Add our event listeners
window.addEventListener('click', someFunction, false);
window.addEventListener('mouseover', someFunction, false);

Can't remove all event listeners

I am trying to remove event listeners from some website but I don't succeed to do it.
This is the event listeners from the website:
There is a javascript script that creates these events with:
document.addEventListener('contextmenu', function (ev) {
ev.preventDefault();
}
)
I tried to remove it with:
document.removeEventListener('contextmenu', function (ev) {
ev.preventDefault();
})
I also tried with:
(getEventListeners(document)).contextmenu = null
But it didn't work, I think because I am using a new function which is not the same one.
Is there a way just to clear all the events ?
Referenced:
Can't remove event listener
You need to specify the function that was bound to removeEventListener
You can do this by creating a function and passing a reference to both addEventListener and removeEventListener.
// create a function
function onRightClick(ev) {
ev.preventDefault();
console.log('onRightClick')
}
// pass the function to both add and remove
document.addEventListener('contextmenu', onRightClick)
document.removeEventListener('contextmenu', onRightClick)
Here is a full example that will cache all the events to the element allowing you to remove specific events, all events for a type of all events.
It's also got a MutationObserver watching the DOM for changes, if an element get's removed so will the events attached to it.
const Events = (() => {
const cache = new Map
const observer = new MutationObserver(function(mutations) {
for (let mutation of mutations) {
if (mutation.type === 'childList') {
if (mutation.removedNodes.length) {
console.log('element removed from the dom, removing all events for the element')
mutation.removedNodes.forEach(x => Events.remove(x))
}
}
}
})
// watch the dom for the element being deleted
observer.observe(document.body, { childList: true })
return {
add(el, type, fn, capture = false) {
let cached = cache.get(el)
if (!cached) {
cached = {}
cache.set(el, cached)
}
if (!cached[type]) {
cached[type] = new Set
}
cached[type].add(fn)
el.addEventListener(type, fn, capture)
},
remove(el, type, fn) {
const cached = cache.get(el)
if (!cached) {
return false
}
// remove all events for an event type
if (type && !fn) {
cached[type].forEach(fn => {
el.removeEventListener(type, fn)
})
cached[type] = new Set
}
// remove a specific event
else if (type && fn) {
el.removeEventListener(type, fn)
// remove the event from the cache
cached[type].delete(fn)
}
// remove all events for the element
else {
for (key in cached) {
cached[key].forEach(fn => {
el.removeEventListener(key, fn)
})
}
cache.delete(el)
}
},
show(el, type) {
const cached = cache.get(el)
if (!cached) {
return false
}
if (type) {
return cached[type]
}
return cached
}
}
})()
function onRightClick() {}
Events.add(document, 'contextmenu', onRightClick)
Events.remove(document, 'contextmenu', onRightClick) // remove a specific event callback
Events.remove(document, 'contextmenu') // remove specific event types from an element
Events.remove(document) // remove all events from an element
const testElement = document.querySelector('#test_element')
Events.add(testElement, 'click', function deleteSelf(e) {
this.parentNode.removeChild(this)
})
<div id="test_element">
when you <strong>click me</strong> I will be deleted from the DOM which will fire the MutationObserver to remove all my events
</div>
You can try cloning the element to which you've added all the listeners and add it back to its parent. With cloning, you lose all the listeners attached to the element. Try this,
var element = document.getElementById('myElement'),
clone = el.cloneNode(true);
element.parentNode.replaceChild(clone, element);
However, this won't work on global event listeners, or simply, those set directly on document instead of an element as the document is the root of hierarchy (can't have parentNode)
To get rid of unknown event listeners you can clone the element and then move the original's content into the cloned one and then replace the original one with the clone.
If you don't care about the contained elements' event listeners, you can also deep clone the original with .clone(true) (or false, can't remember). Then you don't have to move the contents over.

Angular2 Custom Events

I'm trying to find out how to handle custom DOM events emitted by something outside of Angular, for example the following:
document.querySelector('my-custom-element').dispatchEvent(new Event('my.customEvent'));
So far I have tried to register a new EventManagerPlugin that supports everything starting with 'my.' but if I print out all events that come by all 'normal' event like 'click' and 'submit' are printed out; but none of my custom events.
html:
<my-custom-element (my.customEvent)="handleCustomEvent($event)"></my-custom-element>
ts:
supports(eventName: string):boolean {
var ret = false;
if (eventName.indexOf('my.') === 0) {
ret = true;
}
console.log('supports event?', eventName, ret);
return ret;
}
The console.log line only prints native events and ng*events but not my custom event :(
EDIT Fixed solution
I've moved the (my.customEvent) inside the component annd the log showed the custom event.
Binding an external event to the angular2 internal event while seperating the 2 is fixed by using a custom eventHandler in the EventManagerPlugin
Relevate code
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
let zone = this.manager.getZone();
// Entering back into angular to trigger changeDetection
var outsideHandler = (event: any) => {
zone.run(() => handler(event));
};
// Executed outside of angular so that change detection is not constantly triggered.
var addAndRemoveHostListenersForOutsideEvents = () => {
this.manager.addEventListener(element, 'external.' + eventName, outsideHandler);
}
return this.manager.getZone().runOutsideAngular(addAndRemoveHostListenersForOutsideEvents);
}
Trigger the event via DOM:
document.querySelector('my-custom-element').dispatchEvent(new Event('external.my.customEvent'));
Now you can trigger an event from the DOM which is pushed into angular2 world and can the code is handled from within the component.
Try to extend the DomEventsPlugin, for example:
import {DomEventsPlugin} from 'angular2/platform/common_dom';
// Have to pull DOM from src because platform/common_dom returns DOM as null.
// I believe its a TS bug.
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {Injectable} from 'angular2/core';
import {noop} from 'angular2/src/facade/lang';
#Injectable()
export class DOMOutsideEventPlugin extends DomEventsPlugin {
eventMap: Object = {
"clickOutside": "click",
"mousedownOutside": "mousedown",
"mouseupOutside": "mouseup",
"mousemoveOutside": "mousemove"
}
supports(eventName: string): boolean {
return this.eventMap.hasOwnProperty(eventName);
}
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
var zone = this.manager.getZone();
var documentEvent = this.eventMap[eventName];
// Entering back into angular to trigger changeDetection
var outsideHandler = (event) => {
zone.run(() => handler(event))
};
// Executed outside of angular so that change detection is not constantly triggered.
var addAndRemoveHostListenersForOutsideEvents = () => {
DOM.onAndCancel(DOM.getGlobalEventTarget('document'), documentEvent,
(event) => {
let current = event.target;
// if the element/event is propagating from the element its bound to, don't handle it.
if (current.parentNode && current !== element) {
outsideHandler(event);
}
});
}
return this.manager.getZone().runOutsideAngular(addAndRemoveHostListenersForOutsideEvents);
}
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
var element = DOM.getGlobalEventTarget(target);
var zone = this.manager.getZone();
var outsideHandler = (event) => zone.run(() => handler(event));
if ((target === "document") || (target === "window" )) {
return noop;
}
return this.manager.getZone().runOutsideAngular(
() => DOM.onAndCancel(element, eventName, outsideHandler)
);
}
}
source: https://medium.com/#TheLarkInn/creating-custom-dom-events-in-angular2-f326d348dc8b#.so0jvssnz

Remove All Event Listeners of Specific Type

I want to remove all event listeners of a specific type that were added using addEventListener(). All the resources I'm seeing are saying you need to do this:
elem.addEventListener('mousedown',specific_function);
elem.removeEventListener('mousedown',specific_function);
But I want to be able to clear it without knowing what it is currently, like this:
elem.addEventListener('mousedown',specific_function);
elem.removeEventListener('mousedown');
That is not possible without intercepting addEventListener calls and keep track of the listeners or use a library that allows such features unfortunately. It would have been if the listeners collection was accessible but the feature wasn't implemented.
The closest thing you can do is to remove all listeners by cloning the element, which will not clone the listeners collection.
Note: This will also remove listeners on element's children.
var el = document.getElementById('el-id'),
elClone = el.cloneNode(true);
el.parentNode.replaceChild(elClone, el);
If your only goal by removing the listeners is to stop them from running, you can add an event listener to the window capturing and canceling all events of the given type:
window.addEventListener(type, function(event) {
event.stopImmediatePropagation();
}, true);
Passing in true for the third parameter causes the event to be captured on the way down. Stopping propagation means that the event never reaches the listeners that are listening for it.
Keep in mind though that this has very limited use as you can't add new listeners for the given type (they will all be blocked). There are ways to get around this somewhat, e.g., by firing a new kind of event that only your listeners would know to listen for. Here is how you can do that:
window.addEventListener('click', function (event) {
// (note: not cross-browser)
var event2 = new CustomEvent('click2', {detail: {original: event}});
event.target.dispatchEvent(event2);
event.stopPropagation();
}, true);
element.addEventListener('click2', function(event) {
if (event.detail && event.detail.original) {
event = event.detail.original
}
// Do something with event
});
However, note that this may not work as well for fast events like mousemove, given that the re-dispatching of the event introduces a delay.
Better would be to just keep track of the listeners added in the first place, as outlined in Martin Wantke's answer, if you need to do this.
You must override EventTarget.prototype.addEventListener to build an trap function for logging all 'add listener' calls. Something like this:
var _listeners = [];
EventTarget.prototype.addEventListenerBase = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener)
{
_listeners.push({target: this, type: type, listener: listener});
this.addEventListenerBase(type, listener);
};
Then you can build an EventTarget.prototype.removeEventListeners:
EventTarget.prototype.removeEventListeners = function(targetType)
{
for(var index = 0; index != _listeners.length; index++)
{
var item = _listeners[index];
var target = item.target;
var type = item.type;
var listener = item.listener;
if(target == this && type == targetType)
{
this.removeEventListener(type, listener);
}
}
}
In ES6 you can use a Symbol, to hide the original function and the list of all added listener directly in the instantiated object self.
(function()
{
let target = EventTarget.prototype;
let functionName = 'addEventListener';
let func = target[functionName];
let symbolHidden = Symbol('hidden');
function hidden(instance)
{
if(instance[symbolHidden] === undefined)
{
let area = {};
instance[symbolHidden] = area;
return area;
}
return instance[symbolHidden];
}
function listenersFrom(instance)
{
let area = hidden(instance);
if(!area.listeners) { area.listeners = []; }
return area.listeners;
}
target[functionName] = function(type, listener)
{
let listeners = listenersFrom(this);
listeners.push({ type, listener });
func.apply(this, [type, listener]);
};
target['removeEventListeners'] = function(targetType)
{
let self = this;
let listeners = listenersFrom(this);
let removed = [];
listeners.forEach(item =>
{
let type = item.type;
let listener = item.listener;
if(type == targetType)
{
self.removeEventListener(type, listener);
}
});
};
})();
You can test this code with this little snipper:
document.addEventListener("DOMContentLoaded", event => { console.log('event 1'); });
document.addEventListener("DOMContentLoaded", event => { console.log('event 2'); });
document.addEventListener("click", event => { console.log('click event'); });
document.dispatchEvent(new Event('DOMContentLoaded'));
document.removeEventListeners('DOMContentLoaded');
document.dispatchEvent(new Event('DOMContentLoaded'));
// click event still works, just do a click in the browser
Remove all listeners on a global event
element.onmousedown = null;
now you can go back to adding event listeners via
element.addEventListener('mousedown', handler, ...);
This solution only works on "Global" events. Custom events won't work. Here's a list of all global events: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers
I know this is old, but I had a similar issue with no real answers, where I wanted to remove all keydown event listeners from the document. Instead of removing them, I override the addEventListener to ignore them before they were even added, similar to Toms answer above, by adding this before any other scripts are loaded:
<script type="text/javascript">
var current = document.addEventListener;
document.addEventListener = function (type, listener) {
if(type =="keydown")
{
//do nothing
}
else
{
var args = [];
args[0] = type;
args[1] = listener;
current.apply(this, args);
}
};
</script>
A modern way to remove event listeners without referencing the original function is to use AbortController. A caveat being that you can only abort the listeners that you added yourself.
const buttonOne = document.querySelector('#button-one');
const buttonTwo = document.querySelector('#button-two');
const abortController = new AbortController();
// Add multiple click event listeners to button one
buttonOne.addEventListener(
'click',
() => alert('First'),
{ signal: abortController.signal }
);
buttonOne.addEventListener(
'click',
() => alert('Second'),
{ signal: abortController.signal }
);
// Add listener to remove first button's listeners
buttonTwo.addEventListener(
'click',
() => abortController.abort()
);
<p>The first button will fire two alert dialogs when clicked. Click the second button to remove those listeners from the first button.</p>
<button type="button" id="button-one">Click for alerts</button>
<button type="button" id="button-two">Remove listeners</button>
Remove all listeners in element by one js line:
element.parentNode.innerHTML += '';
You cant remove a single event, but all? at once? just do
document.body.innerHTML = document.body.innerHTML
In the extreme case of not knowing which callback is attached to a window listener, an handler can be wrapper around window addEventListener and a variable can store ever listeners to properly remove each one of those through a removeAllEventListener('scroll') for example.
var listeners = {};
var originalEventListener = window.addEventListener;
window.addEventListener = function(type, fn, options) {
if (!listeners[type])
listeners[type] = [];
listeners[type].push(fn);
return originalEventListener(type, fn, options);
}
var removeAllEventListener = function(type) {
if (!listeners[type] || !listeners[type].length)
return;
for (let i = 0; i < listeners[type].length; i++)
window.removeEventListener(type, listeners[type][i]);
}
So this function gets rid of most of a specified listener type on an element:
function removeListenersFromElement(element, listenerType){
const listeners = getEventListeners(element)[listenerType];
let l = listeners.length;
for(let i = l-1; i >=0; i--){
removeEventListener(listenerType, listeners[i].listener);
}
}
There have been a few rare exceptions where one can't be removed for some reason.
You could alternatively overwrite the 'yourElement.addEventListener()' method and use the '.apply()' method to execute the listener like normal, but intercepting the function in the process. Like:
<script type="text/javascript">
var args = [];
var orginalAddEvent = yourElement.addEventListener;
yourElement.addEventListener = function() {
//console.log(arguments);
args[args.length] = arguments[0];
args[args.length] = arguments[1];
orginalAddEvent.apply(this, arguments);
};
function removeListeners() {
for(var n=0;n<args.length;n+=2) {
yourElement.removeEventListener(args[n], args[n+1]);
}
}
removeListeners();
</script>
This script must be run on page load or it might not intercept all event listeners.
Make sure to remove the 'removeListeners()' call before using.
var events = [event_1, event_2,event_3] // your events
//make a for loop of your events and remove them all in a single instance
for (let i in events){
canvas_1.removeEventListener("mousedown", events[i], false)
}

Categories