addEventListeners trigger automatically [duplicate] - javascript

This question already has answers here:
onclick function runs automatically
(4 answers)
Why does click event handler fire immediately upon page load?
(4 answers)
Closed 2 years ago.
Ok, I am a super newbie here, so keep that in mind. I have several messages in li items saved in bskt_messages. It is an HTML Collection. I am trying to add a click event listener, but every time I run the page, it calls the return_value function automatically. I have used code from similar posts on this site but there seems to be no difference. What am I doing wrong here?
$(document).ready(function() {
var bskt_messages = document.querySelectorAll('.message_item');
for (let i = 0; i < bskt_messages.length; i++) {
bskt_messages[i].style.cursor = 'pointer';
bskt_messages[i].addEventListener("click", return_value(i));
};
});
function return_value(i) {
console.log("clicked " + i);
}

That's because you're executing the function. You want to nest your function call within the click method.
$(document).ready(function() {
var bskt_messages = document.querySelectorAll('.message_item');
for (let i = 0; i < bskt_messages.length; i++) {
bskt_messages[i].style.cursor = 'pointer';
bskt_messages[i].addEventListener("click", function (event) {
event.preventDefault();
return_value(i);
}
);
};
});
function return_value(i) {
console.log("clicked " + i);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" class="message_item">btn0</button>
<button type="button" class="message_item">btn1</button>
<button type="button" class="message_item">btn2</button>
Note that it's not a good practice to spawn too many event listeners. For three buttons you're fine, but with dozens of items, you should listen to events on the parent element and compare the event target with your desired element (e. g. a button Node perhaps stored in an array).
const wrapper = document.querySelector('#wrapper_around_buttons');
const myButtons = wrapper.querySelectorAll('button');
wrapper && wrapper.addEventListener('click', event => {
let button = event.target.closest('button');
if (button && myButtons.include(button)) {
console.log("clicked a button!");
}
});

Related

How to not lose my event listener in Javascript each time I use .insertBefore?

I am attempting to move a div (which contains text and other elements) each time the user clicks the up or down arrow. The goal is to simply allow users to rearrange divs to their liking, based on clicking the appropriate arrows.
The issue I'm running into is -- when I use .insertBefore to rearrange these elements? It only allows me to click the arrow and perform that action once. After that, nothing happens. It appears that I'm losing my event listener each time I do this. Is there a way for me to somehow say: "Keep that old event listener after it gets moved?"
Here is the code:
for (let i = 0; i < NumberOfSavedIdeas; i++) {
document.getElementById('DeleteIdeaButton' + [i]).addEventListener('click', () => {
var DivToDelete = document.getElementById("SavedIdeaDiv" + [i]);
DivToDelete.remove();
let ArrayContentMatch = FullSavedIdeasArray.indexOf(FullSavedIdeasArray[i])
FullSavedIdeasArray.splice(ArrayContentMatch, 1);
chrome.storage.local.set({SavedIdeas: FullSavedIdeasArray});
});
document.getElementById('MoveIdeaUp' + [i]).addEventListener('click', () => {
var DivToMove1 = document.getElementById("SavedIdeaDiv" + [i]);
var ParentDiv1 = document.getElementById("DivTesting");
ParentDiv1.insertBefore(DivToMove1, ParentDiv1.children[i-1]);
});
document.getElementById('MoveIdeaDown' + [i]).addEventListener('click', () => {
alert('move down')
});
}
Thanks!
This is because new element doesn't exist in DOM when all event listeners are set. Add an event listener on document instead of an element.
It should be wrapped like:
for (let i = 0; i < NumberOfSavedIdeas; i++) {
document.body.addEventListener( 'click', function (e) {
if (e.target.id == 'YourId' + [i]) {
yourFunction();
}
} );
}

Onclick event for "li" in a for loop when using createElement

I'm trying to add an event listener (onclick) onto every li element that gets created in a specific for loop - using JavaScript.
First I tried using tempLi.onclick (see code below for context), but it wouldn't run the function. After that I searched for the issue here on Stackoverflow, and I read that this method I'm using below should work - but it doesn't (not in my case at least).
if (users.length !== 0) {
for (let i = 0; i < users.length; i++) {
let tempLi = d.createElement('li');
tempLi.className = 'btn btn-primary knappur'
tempLi.innerHTML = users[i];
getId('usersUl').appendChild(tempLi);
(function(value) {
tempLi.addEventListener("click", function() {
alert(value);
}, false);
})(users[i]);
getId('usersUl').innerHTML += '<br>';
}
}
The code is in a function called loginPrepare:
let loginPrepare = () => { ... }
How can I execute code when I click on the generated li (tempLi)?
EDIT: The code that I'd like to run when clicked on the "li" is login(users[i])
I would put the event handler on your ul and rely on event bubbling instead of attaching an event handler to each. It would look something like this.
document.getElementById('usersUl')
.addEventListener('click', function(e) {
if (e.target.hasClass('knappur') {
// Do your work
}
});
You are creating a function inside a loop, referencing the ever-changing index i, which, when the loop is done might be a completely different value than what you think it is.
Also, I think this way you are attaching the event-listener before the tempLi has had time to be properly integrated into the dom.
Third: you don't need to create a new event-listener for each list item. One is enough.//
Try this instead:
if (users.length !== 0) {
const list = getId('usersUl')
for (let i = 0; i < users.length; i++) {
let tempLi = d.createElement('li');
tempLi.className = 'btn btn-primary knappur';
tempLi.innerHTML = users[i];
tempLi.setAttribute('data-user', users[i])
list.appendChild(tempLi);
//list.innerHTML += '<br>'; don't do this btw, <br />s aren't valid children of lists!
}
list.addEventListener("click", event => {
const user = event.target.getAttribute('data-user');
alert(user);
});
}
We can achieve event binding to HTML in very simple way using JQuery like below:
$("#usersUl").on('click',function(e){
//what we do
});

addEventListener firing automatically within loop - or only last element works

I have a loop, and I am creating a button within each iteration. I am attaching an event listener to each newly created button, and I need to pass unique parameters through. Please see the code below (in this case, just passing the index from the loop through the event listener)
for (i = 0; i <= worklog.worklogs.length; i++) {
if (worklog.total > 0) {
var theButton = document.createElement("button");
theButton.addEventListener("click", alertButton(i));
theButton.innerHTML = "Add";
mySpan.appendChild(theButton);
}
}
function alertButton(arg) {
return function () {
alert(arg);
};
}
Currently, the event listener fires on only the button implemented on the very last iteration. If I remove the "return function(){}" within my alertButton function, then the event listener is fired on each iteration without the user clicking on the button.
If you have any ideas I would be extremely appreciative. I am finding other people who have had this problem, yet the solutions provided don't seem to work so well for me. Hopefully I am overlooking something simple.
Thanks!
Issue is in the way you are assigning listener:
theButton.addEventListener("click", alertButton(i));
in above code, alertButton(i) will call function and not assign to it. If you want to pass a value to a function assignment, you should bind value.
theButton.addEventListener("click", alertButton.bind(this,i));
As pointed by #Andreas, a working example.
function createButtons() {
for (var i = 0; i < 5; i++) {
var theButton = document.createElement("button");
theButton.addEventListener("click", alertButton.bind(this, i));
theButton.innerHTML = "Add";
content.appendChild(theButton);
}
}
function alertButton(arg) {
console.log(arg)
}
createButtons();
<div id="content"></div>

Dynamically create necessary jQuery(document).on [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I'm using a plugin that uses jQuery(document).on() to activate a modal. I have a bunch of modals on the page.
If I manually create an .on for each modal opening/closing everything works as
jQuery(document).on('opened', '[data-remodal-id=modal-1]',
function() {
player1.api('play')
});
jQuery(document).on('closed', '[data-remodal-id=modal-1]',
function(e) {
player1.api('unload')
});
jQuery(document).on('opened', '[data-remodal-id=modal-2]',
function() {
player2.api('play');
});
jQuery(document).on('closed', '[data-remodal-id=modal-2]',
function(e) {
player2.api('unload');
});
However this is a managed page, that could need 2,3 or 10 modals with their own content. I'm trying to do what I did above, only dynamically. Here's my attempt, and I can see why it doesn't work, but I have no idea how to approach this properly.
var countPlusOne;
for (i=0;i<players.length;i++){
countPlusOne=i+1;
var dataSelector = '[data-remodal-id=modal-'+countPlusOne+']';
jQuery(document).on('opened', dataSelector, function () {
players[i].api('play');
});
jQuery(document).on('closed', dataSelector, function (e) {
players[i].api('unload');
});
}
Hopefully it gives you some idea of what i'm trying to do? Is it even possible?
Per my understanding, you have dynamic elements and have to bind events to them.
You can try something like this:
var count = 1;
function addInput(){
var content = document.getElementById("content");
var input = "<input id='txt_"+count+"' class='input'>";
count++;
content.innerHTML+=input;
}
function registerEvents(){
$(document).on("blur", ".input", function(){
console.log($(this).attr("id"));
})
}
registerEvents();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="content"></div>
<button onclick="addInput()">Add input</button>
If playerX are global vars, you could refactorize your code to this:
jQuery(document).on('opened closed', '[data-remodal-id]', function (e) {
window["player" + $(this).data("remodalId").replace('modal-' ,'')].api(e.type === "opened" ? 'play' : 'unload');
});
But i guess you don't need all this different playerX variables anyway.
Ultimately, your api() should handle player id and it would be called like that e.g:
player.api(1, 'play');
EDIT: Ok i'm miss this part in OP
I'm using a plugin
So you shouldn't override api() method.
EDIT2: to answer your question, using closure, you could use:
var countPlusOne;
for (i = 0; i < players.length; i++) {
(function(i) {
countPlusOne = i + 1;
var dataSelector = '[data-remodal-id=modal-' + countPlusOne + ']';
jQuery(document).on('opened', dataSelector, function() {
players[i].api('play');
});
jQuery(document).on('closed', dataSelector, function(e) {
players[i].api('unload');
});
})(i);
}

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.

Categories

Resources