This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
What I am trying to do is to set the same function to different elements with similar id, for example "icon-1","icon-2","icon-3". The function opens up a window that corresponds to those ids -- "window-1", "window-2","window-3". I was trying to use this code block:
for (var i=1; i<=3; i++) {
$("#icon"+i.toString()).click(function(){
$("#window"+i.toString()).show();
)};
)};
Ideally, when "icon-1" is clicked, it opens "window-1", etc. But it's not working.
And I checked console.log(i), every time when a click event occurs, it prints out the final count of i, which is 4.
Is there any way to fix or walk around this?
Thanks a lot!
When you say 'opens up a window', do you mean to open up a popup window or just showing an existing element?
Assuming it's the latter, I would give each of your icons a class that they all share and attach the click handler to elements with that class rather than using three different click handlers. Then use the data attribute to store the corresponding window number:
<div class="icon" data-window="1">This is an icon</div>
<div class="icon" data-window="2">This is an icon</div>
$('.icon').click(function(){
var windowNum = $(this).data();
$('#window-' + windowNum).show();
});
Try classes to achieve that.
$('.yourIconClass').each(function() {
$(this).click(function(){
$('.yourWindowClass').eq($(this).index).show();
});
});
I wouldn't use a for loop for this. I don't use query, so I'll speak in javascript.
I would assign the buttons/icons to variables in javascript and then just have an event listener for each of the buttons. That event listener will send a value to a function that will determine which window to open:
var button1 = document.getElementById("button_1_id");
var button2 = document.getElementById("button_2_id");
var button2 = document.getElementById("button_2_id");
button1.addEventListener('click',function(){
triggerWindow(1);
});
button2.addEventListener('click',function(){
triggerWindow(2);
});
button3.addEventListener('click',function(){
triggerWindow(3);
});
function triggerWindow(input) {
if(input === 1){
/* code to trigger window one */
}
else if(input === 2){
/* code to trigger window two */
}
else if(input === 3){
/* code to trigger window three */
}
}
Related
This question already has answers here:
How to ignore multiple classes using the :not selector?
(2 answers)
Closed 5 years ago.
I have a click function in my card game that I would like to include not() in to exclude certain classes but I can't seem to get it to work.
Basically, I would like to make it so that as long as the class does not equal "match" or "open", to proceed with the click event. If they match then do not run the function.
Here is snippet of the updated basic code I am working with now:
function addCardListener() {
$( '.card:not(.match, .open, .show)').on('click', function(){
alert("TEST");
$(this).addClass('open show');
});
}
I tried replacing:
$('.card').on('click', function() {
with:
$( '.card:not(".match, .open")').bind('click', function(){
but it doesn't work. I can proceed with clicking anything in my deck whether or not those classes are defined on the card. What am I doing wrong? Thanks in advance for any help!
Update:
I stripped out all my code and still can't get it to work. Not sure if you will see this update but my board creation is done like this:
function createBoard() {
shuffle(symbols);
match = 0;
moves = 0;
for (var i = 0; i < symbols.length; i++) {
deck.append($('<li class="card"><i class="fa fa-' +
symbols[i] + '"></i></li>'));
}
addCardListener();
};
The click function goes off whether or not the card's class has open match or show on it. I guess I"m confused, I thought with not() the function would not run if the card had those classes. I updated the stripped down version of the function above. Any advice would be greatly appreciated!
Try this - delegate if the cards are inserted dynamically:
$('body').on('click', '.card:not(.match,.open)', function(e) {
console.log(e);
});
Change 'body' to a closer container if possible to speed up the delegation
This question already has answers here:
Is it possible to append to innerHTML without destroying descendants' event listeners?
(13 answers)
Closed 6 years ago.
This has now been answered. Not an issue with ES6 or event listeners, but rather how innerHTML is working. It is removing all the html (breaking the listeners) and then adding the html back in with only the latest listener attached. Thank you.
Basically I am having issues with ES6 Classes and event listeners. Or it could very well just be my understanding of the whole thing.
I am dynamically creating 5 instances of the same class called 'Thing'. Each 'Thing' writes a piece of HTML to the DOM containing a button and adds an event listener to handle clicks. Elements are being selected using document.querySelector and based off a data attribute called 'indexNumber' to uniquely identify each button.
As each thing is its own instance I imagined that each button would work but only the last button does. Why is one instance of a class overwriting another?
Can anyone explain what is happening here?
HTML
<h1>Things</h1>
<span class="output"></span>
<div class="thingHolder"></div>
JS (Babel)
class Thing {
constructor(index) {
this.Index = index;
this.html = '<div class="thing" data-index-number="'+ index +'">Thing ' + index + '<button type="button">Click Me!</button></div>';
this.renderDom();
}
renderDom(){
const thingHolder = document.querySelector(".thingHolder");
thingHolder.innerHTML += this.html;
this.addEventListeners();
}
addEventListeners(){
const button = document.querySelector('.thingHolder .thing[data-index-number="' + this.Index + '"] button');
button.addEventListener("click", () => {
this.doSomething()
}, false);
}
doSomething(){
const output = document.querySelector(".output");
output.innerHTML = 'You clicked thing #' + this.Index;
console.log('You clicked thing #' + this.Index)
}
}
for(var i = 0; i < 5; i++) {
var thing = new Thing(i);
}
The problem has nothing to do with ES6 or JavaScript.
thingHolder.innerHTML += this.html;
will destroy and recreate all existing children of thingHolder. In that process, existing event handlers are destroyed.
Instead of creating HTML and using innerHTML you should be using the DOM API to create and append new element.
Example:
var div = document.createElement('div');
div.addEventListener('click', () => { ... });
// ...
thingHolder.appendChild(div);
When you use thingHolder.innerHTML += html the old objects in the container are removed and recreated, but without their event listeners. So you are recreating them all every time you insert a new node that way.
The fact that the first button is the only one that works is because you are attaching an event only to the first element you encounter inside the parent (with querySelector), just after you removed all other events.
So the solution would be to create your elements with JS (or whatever is used in Babel) instead of using innerHTML.
This question already has answers here:
Ignore table click function when clicking on a link
(2 answers)
Closed 8 years ago.
I have a table in which I have the following event:
$("#tp-active-list-table td").click(function () {
var transactionNbr = parseInt($(this).parent("tr").children('td.td-transaction-nbr').html());
DoSomething(transactionNbr);
});
It works fine and basically it calls the DoSomething with the Number gathered from the respective td.
But I do have a problem, since in one of the tds I have an anchor, and if the click is performed on that anchor, then the DoSomething will run, and the page will correctly navigate to another URL.
Is there anyway to check if the click was on that anchor to avoid running the DoSomething function?
Use event.stopPropagation() to prevent bubbling of events.
$('td a').click(function (e) {
e.stopPropagation()
});
Other option would be : e.target.tagName
$("#tp-active-list-table td").click(function (e) {
if(e.target.tagName.toLowerCase() === 'a'){
var transactionNbr = parseInt($(this).parent("tr").children('td.td-transaction-nbr').html());
DoSomething(transactionNbr);
}
});
the object that is passed to your handler function as the first argument has property target if target.tagName == 'a' then you clicked on an anchor.
I think Shaunak's answer very effective. Just to point out another approach, on the click event you can check if there's an hovered a tag. http://jsfiddle.net/Zx7S5/
$("#tp-active-list-table td").click(function(event) {
if($(this).find("a:hover").length <= 0) {
/* ..... */
}
});
I have browsed the internet extensively on this issue, including stackoverflow.
My problem is that I have a set of 'li', and I want multiple 'li' added to an array when I use ctrl+click gesture. I keep on getting (e) is not defined. I have found this: Detect CTRL and SHIFT key without keydown event?
But the answer provided, which seems to have worked for many, doesn't for me. Whenever I use that, even as the sole item in my script, firebug doesn't respond in the console, but I get: " ReferenceError: e is not defined." I'm using Firefox.
My biggest problem is getting this to add this to a function, and the function, which fires as an event, can distinguish between the a ctrl+click and normal click.
Any expertise to help me out? Vanilla Javascript preferred.
The point of this exercise is to remove the LI when clicked, but I want to delete multiple at once if I hold down ctrl. Perhaps by storing them in an array.
EDIT: Some Code
<ul id = "ulItem">
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
</ul>
<script>
window.onload = function(){
var ulItem = document.getElementById("ulItem"); //gets UL with the "ulItem" ID.
var ulList = ulItem.getElementsByTagName("li"); //gets ulItem's "li" in an array.
///prepareLI function.///
var prepareLi = function(){
for(i = 0; i < ulList.length; i++){
ulList[i].addEventListener('click', elementClick);
}
}
//adds the same event listener to each of the "li" inside "UlList" array. Each activated by a click.
///elementClick function.///
var elementClick = function(){
ulItem.removeChild(this);
} //if this is a child of parent, UlList, remove it.
prepareLi();
}
The browser is correctly telling you that you never declared e, while the example in Detect CTRL and SHIFT key without keydown event? has defined e, by declaring it as a formal argument to the listener function.
var elementClick = function(e){
if(e.ctrlKey) {
ulItem.removeChild(this);
}
}
Note the use of function(e){ rather than function(){
I think I found an alternative way to do this.
If you want to emulate a Ctrl+click in order to select multiple objects, this worked for me as a workaround:
make two variables, loader and loaderArray:
var loader = 1;
var loaderArray = [];
set a document event:
document.addEventListener('mousedown', MultiSelect);
and a click event on the item:
document.addEventListener('click', singleSelect);
Make sure the window event is is a mousedown item, also, that Ctrl is defined as keyCode == 17. The number part is VERY important. Here is code I used:
function loadArray(e) {
if (e.keyCode === 17) {
//console.log("key down");
loader = 2;
};
}
Then I set a separate function on the singleSelect event stating that if loader ==2, use loaderArray.push(this) rather than the normal way of doing things when loader == 1.
The loader Array then collects the variables, and you can do whatever you want with the array using for() or some other loop.
Now, whenever I click the Ctrl key, the mousevent on the document turns the loader variable to 2, and it can distinguish between Ctrl+click and normal click this way.
Thanks for all those that helped, and I hope this will help others! :)
This question already has answers here:
In jQuery, how can I tell between a programmatic and user click?
(7 answers)
Closed 8 years ago.
In javascript/jquery, I have a button that have a click event defined like:
$("#target").click(function() {
var mouse_click = ________________;
// do stuff
if (mouse_click) {
// do stuff
}
// do stuff
});
and I also have code to do
$('#target').click();
How can I get the variable mouse_click to be true, if the user manually clicked the tag using the mouse, and the variable to be false when I click the tag using the .click() function?
Thanks
You could use this:
$("#target").click(function(e) {
var mouse_click = !(e.originalEvent === undefined);
// do stuff
if (mouse_click) {
// do stuff
}
// do stuff
});
or you could check e.isTrigger which is set whenever an event is triggered within jQuery. You'd just need to change the second line to:
var mouse_click = !e.isTrigger;
Both will work but you might prefer the second option as it's a little more concise.
Here it is working: http://jsfiddle.net/2U3Us/4/