Can't remove event listener - javascript

Can anyone tell why bt2 event listener is not getting removed in if block. As when I remove the event listener in the p function, it's getting removed without any error or bug. I am pretty sure there might be any stack or scope problem due to which event listener is not getting removed but I can't figure out what that could be. And I know that event listener is not getting removed as with the succeeding clicks on bt2 element all the preceding event listeners are also running again, as the same function is running multiple times. Please tell me what's the problem.
Here's the full code:
(function()
{
if(window.addEventListener) window.addEventListener('load',init,false);
function init()
{ var i=0;
var get=document.getElementById('bt1').addEventListener('click',function() { pro(0);},false);
function pro(x)
{ alert('yeah');
if(!x) x=0
if(x!=0) //I dont want to remove event listener in the first time , so i want it to function with the next call to pro,in which the value of x is bigger than 0
{
//alert('right');
document.getElementById('bt2').removeEventListener('click',p,false); //event listener is not getting removed .
}
document.getElementById('bt2').innerHTML='this is a button '+x;
function passTo(y)
{
pro(y);
}
document.getElementById('bt2').addEventListener('click',p,false);
function p()
{ //document.getElementById('bt2').removeEventListener('click',p,false); //here the event listener is getting removed easily
passTo(x+1);
}
}
}
}());

removeEventListener requires that you pass it the same function, but your p functions are not the same: A new one is created every time pro is called. So the one you're trying to remove isn't the one you added, and so it isn't removed.
Removing it within p works, because within each p function, the identifier p refers to that specific p function. So if that one's been added, it will successfully remove itself.
You can prove this to yourself by putting a unique identifier on your function (see comments):
(function() {
if (window.addEventListener) window.addEventListener('load', init, false);
var functionId = 0; // Something to give us unique IDs
function init() {
var i = 0;
var get = document.getElementById('bt1').addEventListener('click', function() {
pro(0);
}, false);
function pro(x) {
snippet.log('yeah');
// We ALWAYS to into the body of this if, the condition
// is just here for emphasis
if (!p.id) {
p.id = ++functionId;
}
if (!x) x = 0
if (x != 0)
{
snippet.log("Removing #" + p.id); // <===
document.getElementById('bt2').removeEventListener('click', p, false);
}
document.getElementById('bt2').innerHTML = 'this is a button ' + x;
function passTo(y) {
pro(y);
}
snippet.log("Adding #" + p.id); // <===
document.getElementById('bt2').addEventListener('click', p, false);
function p() {
passTo(x + 1);
}
}
}
}());
<button id="bt1">bt1</button>
<button id="bt2">bt2</button>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
If we run that and click bt1 once, then repeatedly click bt2, we see:
yeah
Adding #1
yeah
Removing #2
Adding #2
yeah
Removing #3
Adding #3
yeah
Removing #4
Adding #4
Note how each time we're trying to remove a different function than we added.
If you want to remove the previous one, you need to remember it elsewhere (see comments):
(function() {
if (window.addEventListener) window.addEventListener('load', init, false);
var functionID = 0;
var lastp = null; // <===
function init() {
var i = 0;
var get = document.getElementById('bt1').addEventListener('click', function() {
pro(0);
}, false);
function pro(x) {
snippet.log('yeah');
if (!p.id) { // Again, always true
p.id = ++functionID;
}
if (!x) x = 0;
if (lastp) // <===
{
snippet.log("Removing #" + lastp.id);
document.getElementById('bt2').removeEventListener('click', lastp, false);
}
document.getElementById('bt2').innerHTML = 'this is a button ' + x;
function passTo(y) {
pro(y);
}
lastp = p; // <===
snippet.log("Adding #" + p.id);
document.getElementById('bt2').addEventListener('click', p, false);
function p() {
passTo(x + 1);
}
}
}
}());
<button id="bt1">bt1</button>
<button id="bt2">bt2</button>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Related

Removing an event listener the proper way

How do I properly remove an event listener...
function createMaze() {
var x;
for (x = 0; x < 4; x++) {
var mazeBlock = document.createElement('div');
document.body.appendChild(mazeBlock);
mazeBlock.setAttribute('class', 'blockStyle');
mazeBlock.setAttribute('id', 'mazeBlock'+x);
mazeBlock.addEventListener( 'click', function(){ eventCall(this) } );
}
}
function eventCall(t) {
alert( t.id );
t.removeEventListener(); //...know that I'm missing something here.
// Also in my code, this remove will not happen here but be initiated somewhere else in the script.
}
I did bunch of digging and the top answer there suggest to add the listener to an object for easier removal but... I'm not sure how to accomplish that
While you could save a reference to the function you call addEventListener with so you can remove it:
for (let x = 0; x < 4; x++) {
const mazeBlock = document.createElement('div');
document.body.appendChild(mazeBlock);
mazeBlock.className = 'blockStyle';
mazeBlock.id = 'mazeBlock' + x;
mazeBlock.addEventListener('click', function handler() {
mazeBlock.removeEventListener('click', handler);
eventCall(mazeBlock);
});
}
(above, eventCall is called with the <div> as the first argument)
It would be easier to make sure the function can only be called once by passing { once: true } as a third argument to addEventListener:
mazeBlock.addEventListener( 'click', eventCall, { once: true });
(above, eventCall is called with the event as the first argument - to get to the <div>, access the .target of the argument)
If you need to remove listeners for all such elements, you might consider a different approach - rather than attaching lots of listeners and then removing them all, use event delegation instead. That way, all you have to do is remove the single delegated listener:
document.body.addEventListener('click', function handler(event) {
if (!event.target.matches('.blockStyle')) return;
// A block was clicked on, remove the listener:
document.body.removeEventListener('click', handler);
// Do stuff with the clicked element:
eventCall(event.target);
});
If you're forced by weird school rules to add listeners to each element, create the listener function outside the loop, then iterate over all elements and remove the listener from each when needed:
const handler = (event) => {
document.querySelectorAll('.blockStyle').forEach((div) => {
div.removeEventListener('click', handler);
});
// do stuff with event and event.target
};
...ended up doing this:
function createMaze() {
var x;
for (x = 0; x < 4; x++) {
const mazeBlock = document.createElement('div');
document.body.appendChild(mazeBlock);
mazeBlock.className = 'blockStyle';
mazeBlock.id = 'mazeBlock' + x;
mazeBlock.addEventListener( 'click', eventCall );
}
}
function eventCall() {
alert( this.id );
}
//...this is called from another piece of the script on a separate occasion
function removeListeners() {
var blocks = document.getElementsByClassName('blockStyle');
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
block.removeEventListener( 'click', eventCall );
}
}
#CertainPerformance Thanks for all your help! :)

Stop function after certain number of clicks on a certain element

OK so I am making a reaction tester, and I have a function that makes shapes appear on screen, So what I want is some sort of function were after 5 clicks on a certain element it will end a function. Is there a way of doing that? sorry if its a dumb question, its because I am new to the whole coding...
Here you go
var clickHandler = (function (e) {
var count = 0;
return function () {
count += 1;
if (count > 5) {
return;
}
// do other stuff here
}
}());
aDiv.addEventListener('click', clickHandler, false);
You Can use static variable to count how many times the object has been clicked.
and here is how you can create static variable in javascript.
You can unbind the click event once the counter reaches 5. See the example below
function test(sender) {
sender.dataset.clicked++;
console.log("I've been clicked", sender.dataset.clicked);
if (+sender.dataset.clicked === 5) {
// unbind the event
sender.onclick = null;
}
return;
}
<div onclick="test(this);" data-clicked="0">click me</div>
You may use global variable which may remain counting on click function
<script>
var globalvar = 0;
onclickfunct()
{
globalvar += 1;
if(globalvar == 5)
{
//do my work
}
else
{
//give alert
}
}
</script>

I want to click to implement the event once, then remove event from the element that clicked

As in the title of the question.
I have many elements, because I have used getElementsByTagName('*').
Then, I have added a click event on every element, and I have used loop for that.
See the code:
HTML
<div id="box">
<span class="box"> span</span><br/>
<span class="box">span 2</span><br/>
<span class="box">span 3</span><br/>
</div>
<div id="result"></div>
Javascript
var element = document.getElementsByTagName('*'),
len = element.length, result = document.getElementById('result'), i, timer;
for (i = 0; i < len; i++) {
element[i].addEventListener('click', fn = function (e) {
clearTimeout(timer);
result.style.display = 'inline';
result.innerHTML = "<pre>" + e.target.innerHTML + "</pre>";
timer = window.setTimeout(function () {
result.style.display = 'none';
}, '2000');
e.target.removeEventListener('click', fn);
});
}
I want to when a user clicks on a specific element, implement the
event once, then removes the event from this element only.
Also, I want to add the function(callback) name to the removeEventListener function automatically, not like this e.target.removeEventListener('click', fn) //fn is the callback name.
the event callback gets called with the context of element, you have added the listener to it, here this would point to element[i],so you can change it like:
element[i].addEventListener('click', function fn(e) {
//your stuff
this.removeEventListener('click', fn);
});
note that if you create fn function this way, it is kind of private in the function body, we used to use arguments.callee which is not a good practice these days, you can not use it in strict mode.
all I am saying is by the time strict mode showed up since:
The 5th edition of ECMAScript (ES5) forbids use of arguments.callee()
in strict mode.
we could do that like this:
element[i].addEventListener('click', function(e) {
//your stuff
this.removeEventListener('click', arguments.callee);
});
but the new alternative is using function's label, for instance if you do:
var myfunc = function func(){
//you have access to the current function using func
//and you can add or remove it to/from something
someThing.removeEventListener('click', func);
};
//but if you want to do it here you can have it using myfunc
someOtherThing.removeEventListener('click', myfunc);
So that's what I mean by:
kind of private in the function body
you have access to that function in the function body using its label func, but out there in the code you don't have it.
Define function before as a variable. http://jsfiddle.net/m8UgC/
var element = document.getElementsByTagName('*'),
len = element.length, result = document.getElementById('result'), i, timer;
var fn = function (e) {
clearTimeout(timer);
result.style.display = 'inline';
result.innerHTML = "<pre>" + e.target.innerHTML + "</pre>";
timer = window.setTimeout(function () {
result.style.display = 'none';
}, '2000');
this.removeEventListener('click', fn);
}
for (i = 0; i < len; i++) {
element[i].addEventListener('click', fn);
}

How to add onclick event to exist element by Javascript? (document.getElementbyID)

I have a button in my project that when you click over it a function call and add onclick event to all certain elements in my project and show my hidden popup element container.
I have a function that search all exist element in my page and add onclick event to some of elements that they have certain class.
My element is stored in a list array. in each cell of this array (array name is list) stored an element like below:
list[0] = document.getElementById("my_div_id");
list[1] = document.getElementById("my_div_id_1");
list[2] = document.getElementById("my_div_id_2");
...
list[n] = document.getElementById("my_div_id_n");
and I have a function like below in top of my Javascript code:
function say_hello(e, msg) {
if (e == null) e = window.event;
//now e handler mouse event in all browser !!!
alert (e + "::" + msg);
}
I have a function to add onclick event to each element in array. I add onclick event in type of below (separated with (*) comment) but doesn't work any of them:
function search_and_add_events_to_all_dragable_elements (list) {
for (var z = 0; z < list.length; z++) {
list[z].href = "javascript:;";
var e;
var test_msg = "VAYYYYYYYYYY";
/**************
element.onclick = new Function { alert ('hi'); };
element.onclick = new Function () { alert ('hi'); };
element.onclick = new function { alert ('hi'); };
element.onclick = new function () { alert ('hi'); };
element.onclick = new function () { return alert ('hi'); };
element.onclick = function () { return alert ('hi'); };
element.onclick = alert ('hi');
element.onclick = "alert ('hi');";
element.onclick = say_hello(e, test_msg);
element.onclick = "say_hello();";
element.onclick = (function (e, test_msg) { return function(e) { sib(e, test_msg); };
element.onclick = (function () { return function() { alert("ahaaay"); };
**************/
list[z].style["padding"] = "20px";
list[z].style["border"] = "solid 10px";
list[z].style["backgroundColor"] = "#CCC";
}
}
I change style in end of my code to perform my code is work and end truly. style change every time but onclick event doesn't add to my div.
only one way add onclick to my project. that is same as below:
list[z].setAttribute("onclick", "alert(\"hi\");");
but are there better ways?
There is a better way. My first mistake was using JavaScript before my all element load on my page. to solve it you must call element in end of page load or put your javascript code in end of your project. then your code execute exactly when your elements are exist in your page.
for more details about it see links below:
JavaScript that executes after page load
http://www.w3schools.com/jsref/event_onload.asp
My second mistake was hurt :(
I has a div that hold all of my other elements in itself. it was styled display: none; on load. when I call my function it was displayed none and all thins work well (like my new styling) but onclick event didn't work :(( and I spent two days to solve this :((
only be careful your element should not be display: none styled when you are adding your onclick event to it.
then you can use this type of creation onclick event dynamically to your project:
list[z].onclick = (function (e, test_msg) {
return function(e) {
sib(e, test_msg);
};
})(e, test_msg);
this is best way that I know. you can manage event handler and send your arguments also to your function.
I use several time another way of dynamically add onclick event in my project.

How do I stop this event listener from automatically firing

I've got this self-executing function, which adds event listeners to a series of links. But the event listeners are automatically firing when the page loads, as opposed to onmouseover/out. Have I got the syntax wrong? How do I stop them autofiring?
;(function(){
var menuLink = $('.navItem');
var menuItem = $('.menuLinks');
for (a = 0; a <= 5; ++a) {
menuLink[a].addEventListener('onmouseover', linkChanger(), true);
menuLink[a].addEventListener('onmouseout', linkChanger(), true);
}
function linkChanger(event){
if (menuItem[a].style.color == "white") {
console.log("This is white")
menuItem[a].style.color = "black";
}
else {
console.log("This is black");
menuItem[a].style.color = "white";
}
}
})()
menuLink[a].addEventListener('onmouseover', linkChanger, true);
menuLink[a].addEventListener('onmouseout', linkChanger, true);
When you write linkChanger(), it is executing the function and giving the result to the Listener. Either wrap it with function() { linkChanger(); } or replace with linkChanger. The first option allows you to pass arguments and run other functions too.

Categories

Resources