This question already has answers here:
Javascript removeEventListener not working
(13 answers)
Closed 6 years ago.
I have 1 div (a message) which appears on the page when the page is loaded. When a user clicks somewhere on a page outside this message I want this message to disappear and show (ONCE) a log in the console that the message has disappeared. The problem is I continue receiving my console messages every time I click everywhere on my page though the message is already gone. I.E. I cannot detach 'click' event from my page. The code is following:
var elems = document.querySelectorAll(':not(#my-widget)'); //all elements in my page except message
var promptwidget = document.getElementById('my-widget');
console.log('WIDGET==> ' + promptwidget);
if (typeof(promptwidget) != 'undefined' && promptwidget != 'null') {
for (var i = 0; i < elems.length; i++) //add click eventlistener to the rest document
{
elems[i].addEventListener("click", function(e) {
e.preventDefault(),
removeWidget(["my-widget"]), //parentNode.removeChild wrapper, works OK
console.log('widget removed'), //received everytime I click on a page but I need only ONCE
promptwidget = document.getElementById('my-widget'); //tried to reassign a null value to my promptwidget var and call removeEventListener but no work
});
}
} else //this code never called, but I want it after my-widget removal
{
for (var i = 0; i < elems.length; i++) {
elems[i].removeEventListener("click", function(e) {
e.preventDefault(),
console.log("clickevent removed")
});
}
}
Any help would be appreciated.
EDIT_1:
Thank you everyone, the problem was solved as follows:
var elems = document.querySelectorAll(':not(#my-widget)');
var promptwidget = document.getElementById('my-widget');
for(var i = 0; i<elems.length; i++)
{
elems[i].addEventListener("click", function(e)
{
e.preventDefault();
if(typeof(promptwidget) != 'undefined' && promptwidget != null)
{
removeWidget(["my-widget"]),
console.log('widget removed'), //now showed once
promptwidget = undefined
}
});
}
This code was very helpful
addEventListener allows you to specify more than one event handler for each event type, so to remove a specific event handler you need to specify not only the event type, but also which handler you want to remove:
addEventListener(eventType, eventHandler);
removeEventListener(eventType, eventHandler);
// arguments passed to removeEventListener must be exactly the same
// as in addEventListener so you cannot pass an anonymous function
It doesn't make sense to pass a newly declared anonymous function as the 2nd parameter to removeEventListener. You need to pass a reference to the actual function to be removed. You will have to define this function with a name outside of the scope, and then you can use the name as a reference to remove it.
function removeWidgetFn (e) {
e.preventDefault(),
removeWidget(["my-widget"]),
console.log('widget removed'),
promptwidget = document.getElementById('my-widget');
});
And then,
elems[i].addEventListener("click", removeWidgetFn);
And then,
elems[i].removeEventListener("click", removeWidgetFn);
An element can have many click handlers, so you need to specify which click handler you want to remove.
Related
I am dynamically creating a table where i am adding onclick function to each column.
for (var x = 0; x < r.length; x++) {
//Setting the columns
if (i === 1) {
var headerCell = document.createElement("TH");
headerCell.innerHTML = r[x];
headerCell.id = x;
headerCell.onclick = function () {
sortTable(this.id, name);
}
row.appendChild(headerCell);
}
}
In a specific situation I want to disable the onclick function. Here is the code and it works.
$('#errorTable TH').prop("onclick", null).off("click");
and in another situation i want to reattach the onclick function. And that doesn't work. I want to enable the original function....
Any ideas ?
The way you created your table and adding/removing events are not easily maintainable. I also have some suggestions:
Review your code and define code click handler separately.
If you use jQuery in your project use it every where, if not, do not use it anywhere.
In your code i is undefined.
Add Remove Event Listener with jQuery
First define your handler function:
var myClickHandler = function(){
// this is your click handler
alert('Yes!!!');
}
Select your element and assign to a variable. <div id="clickable">Click Me!</div> must be in the DOM at the time of below script executed.
var element = $('#clickable');
// assign event listener
element.on('click',myClickHandler);
// remove event listener:
element.off('click',myClickHandler);
note that you must have to inform jQuery which handler should be removed.
See a sample https://codepen.io/softberry/pen/BEpove
An alternative is to build a click handler that checks a "kill switch".
var tableClickable = true;
headerCell.onclick = function () {
if (tableClickable) {
sortTable(this.id, name);
}
}
//In a specific situation I want to disable the onclick function.
something.addEventListener('someEvent', function () {
tableClickable = false;
});
//and in another situation i want to reattach the onclick function.
something.addEventListener('someOtherEvent', function () {
tableClickable = true;
});
My question is little weird as i have two html buttons
as
<button>ok</button>
<button>ok</button>
and i am attaching onclick events on them like this
var buttons=document.getElementsByTagName('button');
for(var i=0;i < buttons.length; i++){
buttons[i].onclick = function() {
focus = this;
alert("ok i am clicked")
}
}
now after this i am doing
now i have an event attach on window as
window.onclick = function(e) {
console.log(e.target == focus)
}
according to me this console.log(e.target == focus) condition should be true if i click on first button but its also true for second button!
please tell me where i am wrong and please give vanilla JavaScript solution and in my scenario i can't use id i am will br very thankful to you :)
here is its bin.
From the edit, the solution to your problem is quite simple :
You set the focus element on click of each button, then the window listener fires and checks if the target (the button) is the focus element.
Obviously, it will always be true, since you just set it to be the focus element.
You could add the window listener with target.addEventListener(type, listener, useCapture); and set the useCapture to true.
Then it will fire before the button's onclick, and you'll have to click twice for your callback returns true.
You could use an "Immediately-invoked function expression".
This pattern will ensure that during the time of the click i will still hold the correct value as it has its own scope:
var buttons = document.getElementsByTagName('button');
for (var i = 0; i < buttons.length; i++) {
(function (i) {
buttons[i].onclick = function () {
alert("button " + i + " was clicked");
}
}(i));
}
See the fiddle
I have a list of controls contained in a parent div called overlay-controls.
There is many list controls that each have their own overlay-controls.
I am using a for loop to add the event listener to each button that contains the class delete.
Before the user can delete the item, they must confirm. I am trying to attach this to every delete button found in overlay-controls.
I got it to work using a for loop but I know there is a better way using bubbling and capturing. I am having trouble targeting only the delete class inside overlay-controls by bubbling up to parent div.
See the live demo here by clicking on each delete button: http://jsfiddle.net/8qqfeoa2/1/
Here is my code using the for loop:
(function() {
function getConfirmation(e){
var retVal = confirm("Are you sure you want to delete this request?");
if( retVal == true ){
return true;
}else{
e.preventDefault();
return false;
}
}
var del = document.querySelectorAll('.delete');
for(var i = 0, len = del.length; i < len; i++){
del[i].addEventListener('click', function(e) {
getConfirmation(e);
}, false);
}
}());
You dont event need the For / .each loop
Jquery takes care of it internally
$('.delete').on('click', function(e){
getConfirmation(e);
});
Provided you are using jQuery and in getConfirmation method you may also get that specific (clicked) element by using e.target which returns the target on which click happened.
Only Javascript solution
As you requested one
var deletebuttons = document.getElementsByClassName('delete');
for(var button in deletebuttons) {
button.onclick = getConfirmation;
}
I have a list of elements with its event listeners like this :
var h1 = document.getElementById("h1"),
h2 = document.getElementById("h2"),
h3 = document.getElementById("h3");
var elemArray = [h1,h2,h3];
for(var i=0;i<elemArray.length;i++){
elemArray[i].addEventListener("click",mouseListener,false);
}
function mouseListener(e){
// code goes here
// whenever it's called i want to know from
// which element it's been called
}
Now what i want is whenever i click on one of the elements,
I want to know which one has been clicked without using different functions for each element.
Just use this variable inside your callback, it will point to the target element:
function mouseListener(e) {
console.log( this.id );
}
function mouseListener(e){
var elementEventWasSet = this;
var clickedEl = e.target; // in case of bubbling, this is the one that was clicked
// code goes here
// whenever it's called i want to know from
// which element it's been called
}
You can do something like this
function mouseListener(e){
if(this === h1){
console.log("First was pressed");
}else if(this === h2){
console.log("Second was pressed");
}else if(this === h3){
console.log("Third was pressed");
}
}
This will work only if h1,h2 and h3 are global variable.
You can see this approach in action on this site:
http://jsfiddle.net/94xMu/2/
I'll keep this short - I've got a list of buttons, that I create using a loop, and when one of them gets clicked I want to be able to pass its id attribute to another file in order to dynamically generate a new page.
Here's the code:
for (var i in data.contacts) {
var temp = document.createElement('div');
temp.className = "contacts";
var dude = document.createElement('input');
dude.type = "button";
dude.value = data.contacts[i];
dude.id = data.contacts[i];
dude.className = "dude_button" + data.contacts[i];
dude.addEventListener('click', function(event) { gotoProfile(dude.id); }, false);
temp.appendChild(dude);
temp.appendChild(document.createElement('br'));
theDiv.appendChild(temp);
}
// and now in another file, there's gotoProfile():
function gotoProfile(x) {
var username = document.getElementById(x).value;
if (xmlHttp) {
try {
.... etc.
Now see this works, sort of, but the problem is that when I click any button, it only passes the last dude.id value from the list data.contacts. Obviously I want every button's addEventListener to pass its own data.contacts[i] value, instead of just the last one.
Help appreciated, thanks guys.
Because JavaScript has no block scope, dude will refer to the last assigned element (because the loop finished) when the event handler is called. You have to capture the reference to the current dude by e.g. using an immediate function:
dude.addEventListener('click', (function(d) {
return function(event) {
gotoProfile(d.id);
}
}(dude)), false);
This is a common error when creating functions in a loop.
But you can make it even easier. The event object has a property target that points to the element the event was raised on. So you can just do:
dude.addEventListener('click', function(event) {
gotoProfile(event.target.id);
}, false);
And with that said, you don't need to add a handler for every button. As you are doing the same for every button, you could attach the same event handler above to the parent of the buttons (or a common ancestor) and it would still work. You just have to filter out the clicks that don't happen on a button:
parent.addEventListener('click', function(event) {
if(event.target.nodeName == 'INPUT' && event.target.type == "button") {
gotoProfile(event.target.id);
}
}, false);