index.ts
if(audio.paused) {
audio.play()
audio.addEventListener('timeupdate', (e) => handleAudioPlayer(<HTMLAudioElement>e.target,
<HTMLDivElement>audio.parentElement), true);
}
else {
audio.pause()
audio.removeEventListener('timeupdate', () => handleAudioPlayer, true);
}
Basically I have a handleAudioPlayer function that takes 2 arguments, when the audio is playing the event listener is added, and when its paused it should get removed, but here the eventListeners are getting duplicated which is bad, any help is appreciated!
You're trying to remove a different function than you added in the first place. Instead, try to add and remove the same handler.
const handler = (e) => handleAudioPlayer(<HTMLAudioElement>e.target,
<HTMLDivElement>audio.parentElement)
audio.addEventListener('timeupdate', handler, true)
audio.removeEventListener('timeupdate', handler, true)
In your case you should declare your function to a variable. Then you can remove the eventListener.
if(audio.paused) {
audio.play()
audio.addEventListener('timeupdate', handleAudioPlayer, true);
}
else {
audio.pause()
audio.removeEventListener('timeupdate', handleAudioPlayer, true);
}
let handleAudioPlayer = (evt) => {
// do something
};
Related
I added a handler for the 'cuechange' event to a Text Track" This works fine. But I can not find a way to remove this handler. I tried each of instructions below to remove the handler, but it still gets called.
onHiliteSpeech() {
const textTrack = this.videojsComponent.getTextTrack();
const handleCueChange = () => {
...
console.log(in event handler);
}
};
if (this.bevents) {
textTrack.addEventListener('cuechange', handleCueChange);
} else {
// none of the below instructions remove the handler.
textTrack.removeEventListener('cuechange', handleCueChange);
// textTrack.removeAllListeners();
// textTrack.removeAllListeners('cuechange');
// textTrack.eventListeners = null;
}
}
In my videojsComponent:
getTextTrack(): TextTrack {
return this.player.textTracks()[0];
}
After some trial and error, I found the problem. The function "handleCueChange" should not be a nested function within onHiliteSpeech.
I moved handleCueChange outside of onHiliteSpeech. (This also involved some work to allow handleCueChange to access some OnHiliteSpeech properties.) The new working code became:
const handleCueChange = () => {
...
console.log(in event handler);
}
};
onHiliteSpeech() {
textTrack.addEventListener('cuechange', this.handleCueChange);
...
textTrack.removeEventListener('cuechange', this.handleCueChange);
}
This function is needed for some time. But when tasks are completed I need to disable it, that after clicking on 'board' it wouldn't work.
board.addEventListener('click', event => {
if (event.target.classList.contains('circle')) {
score++
event.target.remove()
createRandomCircle()
} else if (!event.target.classList.contains('circle')) {
fault++
}
})
//Here I want to deactivate this event listener
I would call a handler function that returns a new named function (a closure) to act as the listener. You can then go through your tasks, and remove the listener when they're complete.
const board = document.querySelector('#board');
board.addEventListener('click', handler(), false);
function handler() {
// This is the function the listener uses
return function listener(e) {
console.log(e.target);
console.log('Task one');
console.log('Task two');
board.removeEventListener('click', listener);
console.log('The button no longer works.');
}
}
<button id="board">Board</button>
I have a button. When this button is clicked I do two things
Open up a search menu
Attach an event listener to the document body to listen for close events.
However, I cannot seem to be able to remove the eventlistener from the document on the close function. That is, the second time I try to open the menu, it immediately calls the close function
My question is...
How do I remove the document event listener?
And how do I make it so that if the user clicks the search menu, it does not trigger the document click event
openDesktopSearchMenu() {
this.$desktopSearchMenu.style.height = '330px';
document.addEventListener('click', this.closeDesktopSearchMenu.bind(this), true);
}
closeDesktopSearchMenu() {
this.$desktopSearchMenu.style.height = '0px';
document.removeEventListener('click', this.closeDesktopSearchMenu.bind(this), true);
}
Update July 24
Nick's answer definitely put me in the right direction. However, the document was always being called first due to the capture parameter. So if the user clicks inside the search menu, it's automatically closed.
Removing the capture parameter causes the close function to be invoked immediately after it opens.
The way around this that worked for me is to wrap the listener inside a timeout when I add it. And then naturally I had to call stopPropagation() on search menu click
searchMenuClick = (e) => {
e.stopPropagation();
}
/** open the desktop search menu */
openDesktopSearchMenu = () => {
this.$desktopSearchMenu.style.height = '330px';
this.$navBar.classList.add('search');
setTimeout(() => {
document.addEventListener('click', this.closeDesktopSearchMenu, { capture: false });
});
}
closeDesktopSearchMenu = () => {
this.$desktopSearchMenu.style.height = '0px';
setTimeout(() => {
this.$navBar.classList.remove('search');
}, 300);
document.removeEventListener('click', this.closeDesktopSearchMenu, { capture: false });
}
The .bind() method returns a new function, so the function which you're adding as the callback to addEventListener is a different reference to the one you're trying to remove. As a result, the event listener doesn't get removed.
You could consider binding in your constructor like so:
constructor() {
...
this.closeDesktopSearchMenu = this.closeDesktopSearchMenu.bind(this);
...
}
And then use your method like so (without the bind, as that's now done in the constructor):
openDesktopSearchMenu() {
this.$desktopSearchMenu.style.height = '330px';
document.addEventListener('click', this.closeDesktopSearchMenu, true);
}
closeDesktopSearchMenu() {
this.$desktopSearchMenu.style.height = '0px';
document.removeEventListener('click', this.closeDesktopSearchMen, true);
}
See example snippet below:
class Test {
constructor() {
this.prop = "bar";
this.foo = this.foo.bind(this);
}
foo() {
console.log('Foo', this.prop);
}
a() {
document.addEventListener('click', this.foo, true);
}
b() {
document.removeEventListener('click', this.foo, true);
}
}
const test = new Test();
console.log("Event listener added");
test.a();
setTimeout(() => {
console.log("Event listener removed");
test.b();
}, 3000);
for some reason ,I need to delay click and preventDefault for some time when scroll page end.So I write something like this :
// const disableClickDuringScrollHandler=(e)=> {
// e.preventDefault();
// };
this.scrollHandler = e => {
console.log('scrolling');
const disableClickDuringScrollHandler = (e) => {
e.preventDefault();
};
document.addEventListener('click', disableClickDuringScrollHandler);
window.clearTimeout(this.scrollTimer);
this.scrollTimer = window.setTimeout(() => {
console.log('scroll end');
document.removeEventListener('click', disableClickDuringScrollHandler);
}, 300);
}
window.addEventListener('scroll', this.scrollHandler);
I also has been write a codepen: https://codepen.io/zhangolve/pen/gRNMoX
my question is when I put disableClickDuringScrollHandler outside of the scrollHandler ,removeEventListener can work well,but when I put disableClickDuringScrollHandler inside of the scrollHandler ,removeEventListener doesn't seem to work .
I have tried so many times to found why but failed.So I get here to ask your help.
The problem is that each time the user scrolls, you create a new disableClicksDuringScroll closure and add it as a click listener. When this timer runs, it removes the latest click listener, but not the previous ones (because they're different closures, so they aren't equal to the function you're removing this time).
You should define disableClicksDuringScroll function just once, outside the scroll handler, since it doesn't refer to any local variables here. Then when you call removeEventListener it will find this handler.
You can also use a variable so you only add the click listener once, when scrolling starts, not every time you reset the timer.
this.disableClickDuringScrollHandler = (e) => {
e.preventDefault();
};
this.inScroll = false;
this.scrollHandler = e => {
console.log('scrolling');
if (!this.inScroll) {
document.addEventListener('click', this.disableClickDuringScrollHandler);
this.inScroll = true;
}
window.clearTimeout(this.scrollTimer);
this.scrollTimer = window.setTimeout(() => {
this.inScroll = false;
console.log('scroll end');
document.removeEventListener('click', disableClickDuringScrollHandler);
}, 300);
}
window.addEventListener('scroll', this.scrollHandler);
I want the call function to run every 1.5 seconds.
However, if you are clicking continuously on a mobile machine
From the moment the call function is called in succession.
This is the code I am using:
$('#sendVideo').unbind('click');
$('#sendVideo').bind('click', function (event) {
$("#sendVideo").prop("disabled", true);
call();
setTimeout("$('#sendVideo').prop('disabled', false);", 1500);
});
Is there a solution for this?
You can use a clever hack:
var clickInProgress = false;
$('#sendVideo').bind('click', function (event) {
if(clickInProgress) return;
clickInProgress = true;
$("#sendVideo").prop("disabled", true);
call();
setTimeout("$('#sendVideo').prop('disabled', false); clickInProgress=false;", 1500);
});
You can set a flag on the element during the capture phase and delete it during bubble phase. I am not sure about jQuery but in simple java-script you can achieve it like this:
// set the flag on at capture
document.querySelector("#sendVideo").addEventListener('click', function(e) {
if (this.flagOn) {
e.preventDefault();
return false;
}
this.flagOn = true;
return true;
}, true);
// delete on bubble
document.querySelector("#sendVideo").addEventListener('click', function(e) {
delete this.flagOn;
}, false);
This should handle that for you without any modification in your own code.