Let me describe my scenario before I say my question:
Let counter be defined already as a number starting from 0.
I have 2 a tags: let them be a1 and a2
I first dynamically added a1 into my html and then used this:
jQuery("a.adder").click(function(){adder(this, counter)});
then I did counter++
then I dynamically added a2 into my html and then used this again on both my a tags
jQuery("a.adder").click(function(){adder(this, counter)});
then I did counter++
also, in my adder(param1, param2) , all I do is alert(counter)
Okay here's my question: After doing all that, when I clicked on a1 which has 2 handlers, the alert output is 2 (it alerts twice for each handler) and for a2, the alert is also 2 when clicked. Why is this happening?
The reason it returns 2 for both is that your anonymous functions are creating a closure over the counter variable. What this means is that those methods don't just have the current value of counter when you bind them, they have a reference to the variable.
Any changes in that variable later on will be reflected in the captured variable.
You can prevent this by creating a new variable for the second binding:
var counter = 0;
function adder(e, counter) {
alert(counter);
}
jQuery("<a class='adder'>a1</a><br />')").appendTo("body");
jQuery("a.adder").click(function(){adder(this, counter)});
counter++;
var newCounter = counter;
jQuery("<a class='adder'>a2</a>')").appendTo("body");
jQuery("a.adder").click(function(){adder(this, c)});
counter++;
Here is created a new counter variable called newCounter which is capture by the second event handler.
you made two click events, and your click events return the current value of 'counter'
Related
While creating an array of table data, I'm trying to pass the current ID of an image into a function using an onClick event. What am I doing wrong here? I had the impression a simple solution such as this.id or an event handler would function correctly. Any ideas? Thank you!
function deleteRecord(event)
{
alert(event.target.id);
}
let j = 0;
for(let i in dataRes)
{
j++;
arr.push
(
<tr>
<td><div><img id={j} src={"RANDOM IMAGE"} onClick={(event)=>deleteRecord(event)} /><span id={"item"+j}>{DATA}</span></div></td>
<td>{DATA}</td>
<td>{DATA}</td>
</tr>
);
}
You're passing in the onClick event into the function, when all you need to pass is the value of j. However, we want to pass the value of j at the point in the loop, so we need to make a copy of j before passing it in.
So right after j++;, we need to create a new copy let j_copy = j;
Then your onClick function should be:
onClick={()=>deleteRecord(j_copy)}
and your deleteRecord function:
function deleteRecord(index)
{
alert(index); // alerts the value of j_copy
}
This hard-codes the value of j each time the loop runs. Note that each time the loop runs, a new HTML fragment with a different onClick handler gets generated with that hard-coded value. So the first time, it's equal to onClick={()=>deleteRecord(1)}, the second time it's onClick={()=>deleteRecord(2)}, and so on.
I have a code where I draw an object when the mouse is clicked using mouseClicked = function(){} and then I need to have a number to show how many objects have been drawn. the problem is that the number won't increase. what do I do?
Rather than declaring and incrementing a global variable - you could set the count as a HTML 5 data attribute on the button and then on clicking the button, get the data attribute value, increment it and update the display and the new count on the button.
Note that data-attributes are always strings - hence the need for the parseInt() method, though if I was being a purist - I would have put the radix in as well, but that defaults to 10 - so no need in this case.
It is always better to avoid global variable when possible and data attributes offer a very conveniant way of storing local data.
Thanks to #Sven.hig for the skeletn code of the solution - which I then modified to my approach.
var res=document.getElementById("res")
var btn=document.getElementById("btn")
btn.addEventListener("click",()=>{
const newCount = parseInt(btn.getAttribute('data-count'))+1;
res.textContent = newCount;
btn.setAttribute('data-count', newCount)
})
<div id="res"></div>
<button id="btn" data-count="0">Draw</button>
Here is a simple example that will give you an idea about how to increment a counter
var res=document.getElementById("res")
var btn=document.getElementById("btn")
var count=1
btn.addEventListener("click",()=>{
res.textContent=count
count++
})
<div id="res"></div>
<button id="btn">Draw</button>
If the count variable is defined inside the mouseClicked function as the title say, you are recreating it in every mouseClick. In this case, you should define it outter the function with value = 0 and, inside the function, sum 1 to that value. Anyway, like the comments say, it's necessary that you include the code to your question to give a better answer.
this is an easy way to counter the clicks on a html document.
let counter = 0;
document.onclick = () => {
counter++;
console.log(counter);
}
I expect I'm misunderstanding how hoisting works but I'm confused by why returning i++ is not being hoisted up to the initial declaration of var i. For context I'm trying to create previous/next buttons that utilize scrollIntoView() to cycle between divs.
I have it working as intended for the next button (click and it cycles to next div) but the problem is I can't seem to store the current value of i outside the for loop so that I can use stepsTotal[i] inside another function (for handling the previous button on click).
Here is the code I have working for the next button (previous button function not included). I'm trying to get console.log(i) to print 0,1,2,3, etc. when the next button is clicked.)
const stepsTotal = document.getElementsByClassName("question-steps");
const currentStep = (function() {
var i;
console.log(i); // How do I have this print the current value of i instead of undefined? (i.e. match the results of the second console.log)
for (i=0; i<stepsTotal.length; i++) {
document.getElementById("next-button").addEventListener("click", scrollToCurrentStep);
function scrollToCurrentStep() {
stepsTotal[i].scrollIntoView(true);
i++;
console.log(i); // I want the first console.log to match this one
return
}
return
}
}());
WHAT I WANT TO HAPPEN
So what I want to happen is function partA() to click button [z] every 2 seconds. The button that is being clicked should change, because the script is a looping script, so for instance. The first loop, it would click button 1, then button 2, then button 3, because var z = 1 + i++. Is this possible? z is supposed to equal the number 1, plus the loop number. This should loop as long as variable i is less than 50.
WHAT IS HAPPENING
It works properly, looping and all, if I test the script without variable z. However, without variable z, I have to manually change the number that would equal z, which is painstaking, and annoying.
var z = 1 + i++
for(i=0;i<50;i++) {
setInterval(partA, 2000);
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[z].click();
}
}
Should i++ be defined another way? The error I'm getting when running the script in console is:
Uncaught ReferenceError: i is not defined (...)
at :2:13
at Object.InjectedScript._evaluateOn (:878:140)
at Object.InjectedScript._evaluateAndWrap (:811:34)
at Object.InjectedScript.evaluate (:667:21)
There's a couple of suggestions I could advise with your code so I'll try and address each one individually.
Firstly define your function outside of your loop. If you would like to know the reasons behind this please read: Don't make functions within a loop
Secondly you should really declare i as a variable to set the scope to which it applies. Some good information on this is at: Declaring variables without var keyword
Thirdly when you run your loop you could run the code inside an IIFE. The reason for this is when you run setInterval, by the time it runs i will actually be 3 (or the last number of your loop). This is due to the asynchronous nature of setInterval, and that the reference to i is bound to the function, not the value of i.
Example
for(var i=0;i<3;i++) {
(function(i) {
setInterval(clickButton(i), 2000);
})(i)
}
function clickButton(idx) {
return function() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[idx].click();
}
}
JSBin Demo
http://jsbin.com/harigewuze/edit?html,js,output
Why are you trying to define z outside the loop? Just use i.
for (var i = 0; i < 50; i++) {
...
document.getElementsByTagName('button')[i].click();
}
without changing your code too much I would write it like this...
you know its looping 50 times, you know i is incrementing from 0 to 49, use i to change the button name and you don't need z...
for(i=0;i<50;i++) {
setInterval(partA, 2000);
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[i + 1].click();
}
}
1) This is how you want your code to look like :
var z;
for(i=0;i<50;i++) {
z=i;
setInterval(partA, 2000);
}
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[z].click();
}
2) Unfortunately, in javascript you have a problem with this code due to the fact of scopes. My recommendation is to read this link first http://www.mennovanslooten.nl/blog/post/62 and understand how it works.
If you did understand it, then thumb up..you just promoted yourself to a higher level in javascript ;)
3) If you are still having issues, post it on JSFiddle
I want to increment a value in a array when a link is pressed in JavaScript
i Used the following code
<script type="text/javascript">
var i=0;
var numbers = new Array();
function go(val){
numbers[i]=val;
i++;
alert(numbers[i]);
}
</script>
Called the Function like this
<a href='javascript:go(1)' </a>
but always the alert prompts me 'undefined'
The alert is correct -- before you do your alert, you incremented i. You're looking at the next element after the one you just entered.
After calling the method once, your array looks like this:
numbers[0] = 1;
numbers[1] = undefined;
and i == 1.
After calling it again, the array looks like:
numbers[0] = 1;
numbers[1] = 1;
numbers[2] = undefined;
and i == 2.
Hopefully you can see that this method will always alert undefined
That's because you increment "i"
i++;
right before you put up the alert! Thus "i" will alwuays refer to the next array slot to use, not the one you just populated.
You could change the alert to use "i-1"
alert(numbers[i - 1]);
You are setting numbers[0] = 1 and then incrementing i which becomes 1 so alert(numbers[1]) is undefined, because it is undefined.
Do the alert before you increment. Also, use onclick or even better unobtrusively attach the event handlers in JS, not in the HTML.
Yes, it does that because you:
Create a completely empty array, and a pointer at 0.
When the function is called, you set the current pointer value to whatever was passed in...
...and then increment the pointer, so it's now pointing past the end of all the elements.
Now you look at the element in the array that's being pointed at, which has to be undefined because of the way you're managing the i pointer.
What were you hoping for this to do, by the way?
The question doesn't even match the code... or the code doesn't match the question?
"I want to increment a value in a array"
Your code is not incrementing the value, it's incrementing the index!
function go(val){
numbers[i]=val;
i++;
}
(where i is the index of the next undefined array element) is just the same as
numbers.push(val);
and if you need i to equal what will be the index of the next undefined array element then
i = numbers.length;
To increment the value you would have to first have numeric values for some array elements; then your function would need the index of which value to increment
var numbers = [0,0,0,0];
function go(i){
numbers[i]++;
}
// testing
go(1);
go(3);
go(1);
alert(numbers);
will show 0,2,0,1
But if your entire goal is to put a value into a new element on the end of an array then just use .push()
and .length will tell you how many elements there are; there is no need to increment an i