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>
Related
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
};
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 have a animation that runs right before a stack of functions. I need the functions to run only after the animation is complete....a promise like behavior. I have a eventlistener for this. But the issue is, for efficiency I only want to have one event listener that all the page functions can use.
Is this possible to achieve with a single event listener? and how can I implement a promise like behavior when the event listener fires?
var mainPanelContent = document.getElementById('mainPanelContent');
mainPanelContent.addEventListener('webkitAnimationEnd', function (eve) {
console.log('anamation is done');
});
page('/', function (event) {
if (currentPage !== 0) {
//ON 'webkitAnimationEnd' do the below code
clickOnHome();
pageName = elementList[currentPage].localName;
toggleAllButActivePage(pageName);
findContentAndShow('home');
}
});
page('/portfolio', function () {
if (currentPage !=1) {
//ON 'webkitAnimationEnd' do the below code
toggleAllButActivePage('portfolio-page');
findContentAndShow('portfolio-page');
clickOnPage('rgb(68, 89, 99)');
}
});
page('/resume', function () {
if (currentPage !=2) {
//ON 'webkitAnimationEnd' do the below code
toggleAllButActivePage('resume-page');
findContentAndShow('resume-page');
clickOnPage('#424242');
});
Solution:
Thank you for your suggestions, I ended up going with this to keep the code lighter, otherwise I would have to remove the eventlistener after every promise wrap:
var afterSlideDown = { runStack: function() {} }
mainPanelContent.addEventListener('webkitAnimationEnd', function (animationEvent) {
if (animationEvent.animationName === "slide-down") {
afterSlideDown.runStack();
mainPanelContent.classList.remove('slide-down-now')
}
});
function portfolio() {
toggleAllButActivePage('portfolio-page');
findContentAndShow('portfolio-page');
clickOnPage('rgb(68, 89, 99)');
}
page('/portfolio', function () {
if (currentPage !=1) {
afterSlideDown.runStack = portfolio;
mainPanelContent.classList.add('slide-down-now');
}
});
Something like this should help?
var mainPanelContent = document.getElementById('mainPanelContent');
function addCustomEventListener()
{
return new Promise(function(resolve, reject){
mainPanelContent.addEventListener('webkitAnimationEnd', function (eve) {
resolve(true);
// you can come up with some logic to do a reject() ;-)
});
});
}
addCustomEventListener().then(function(){
// should be called when promise is resolved
console.log('anamation is done');
});
Event listener can work, it'd be just as if you were using callbacks. You can do this for a promise:
var p = new Promise(function(resolve){
function handler(e){
//just one time
mainPanelContent.removeEventListener('webkitAnimationEnd', handler);
resolve(e);
}
var mainPanelContent = document.getElementById('mainPanelContent');
//probs best to do animation here?
mainPanelContent.addEventListener('webkitAnimationEnd', handler);
});
p.then(function(e){
//animationEnded here:
//e = event data from the animationEnd handler.
});
I am trying to have one div box act as a main button for multiple functions; and these functions would fire consecutively after each other; but per new CLICK. Eg, Click = Function fires. Click = next function in line fires, and so forth. Currently I have the below; which is fine, but it is not firing the functions consecutively as they are coded, per click as needed; one after another. Live demo of my dilemma at 'http://bit.ly/10BW89N'
So how to create one button and 30 functions that will be called on each click. If function is defined it will call the function otherwise it will alert the click number?
$(document).ready(function () {
var a1_Events = [function1, function2, function3, function4, function5, function6, function7, function8],
a1_c = 0;
function function1() {
alert('Click 1!');
}
function function2() {
alert('Click 2!');
}
function function3() {
$("#area1").hide();
$("#area2").show();
alert('Click 3!');
}
function function4() {
alert('Click 4!');
}
function function5() {
alert('Click 5!');
}
function function6() {
$("#bg_div").hide(0).delay(1500).show(0);
$("#bg_skew").show(0).delay(1500).hide(0);
alert('Click 6!');
}
function function7() {
alert('Click 7!');
}
function function8() {
$("#area1").hide(0).delay(1500).show(0);
$("#area2").hide(0).delay(1500).show(0);
$("#sound1").show(0).delay(4500).hide(0);
document.getElementById("id1").play();
$("#hammer").show(0).delay(1500).hide(0);
$("#youwin").show(0).delay(3500).hide(0);
alert('Click 8!');
}
$('#area1').click(function () {
a1_Events[a1_c++ % a1_Events.length]();
});
$("#area2").click(function () {
$("#area1").show();
$("#area2").hide();
alert('Click 9!');
});
});
function alert(msg) {
$("#alert").text(msg).show(0).delay(1500).hide(0);
}
You can simplify your code by using a switch or if statement based on the number of times the button/div has been clicked. Each case would control your actions, fire your functions, whatever...
$('button').click(function(){
++funcNum;
switch(funcNum){
case 1:
alert('This is click ' + funcNum);
break;
Here is an example fiddle - http://jsfiddle.net/juf5u/2
I would try this:
var a1_Events = [function1, function2, function3, function4, function5, function6, function7, function8];
$('#area1').click(function () {
if (a1_Events.length > 0)
{
var tfunc = a1_Events.shift();
tfunc();
}
else
{
// all functions have been executed
}
});
This code removes each function from the array as it is executed until it gets to the end. You will still need all the function declarations from the original code.
You could try this also:
$(document).ready(function () {
var a1_Events = function1,
a1_c = 0;
function function1() {
a1_Events=function2;
alert('Click 1!');
}
function function2() {
a1_Events=function3;
alert('Click 2!');
}
function function3() {
a1_Events=function4;
$("#area1").hide();
$("#area2").show();
alert('Click 3!');
}.... so on