How to show current loop iteration in click function, javascript [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
JSFiddle
var arr = [ [0], [1], [2], [3] ];
for ( var i = 0; i < arr.length; i++ ) {
$('#btn-' + i).click(function() {
console.log(i);
});
}
When I'm clicking on corresponding button console.log always shows me last iteration instead of the current iteration. Why?

Try creating a closure, In other words, create a scope per iteration. Now in your code all the event handlers are created in a single scope and the i inside of that scope would get updated instantly to 4. So as a result, when you clicking on all the buttons the result would be same. That is the updated one of i
for ( var i = 0; i < arr.length; i++ ) {
var j = function(x) {
$('#btn-' + x).click(function() {
console.log(x);
});
}
j(i);
}
DEMO

Because of closure! For that you can do this:
for (var i = 0; i < arr.length; i++) {
(function(n) {
$('#btn-' + i).click(function() {
console.log(n);
});
})(i);
}
DEMO

Related

javascript how to fix pitfalls counter [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 4 months ago.
I'm trying to run a for loop and print the current index without use let
here my code:
function init() {
for (var index = 0; index < 5; ++index) {
setTimeout(() => {
console.log(index);
}, index);
}
}
I expected to: 0 1 2 3 4
but i get 5 5 5 5 5
Once the Var replace in Let the problem will be solved
I want to stay with Var
How can the problem be solved?
Thanks
function init() {
for (var index = 0; index < 5; ++index) {
const i = index;
setTimeout(() => {
console.log(i);
}, i);
}
}
This should work.

Javascript loop showing same value 10 times [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
Why is this function only sending the number 10 ten times. I want it to send 1... 2 ... 3 ... 4 ... 5 and so on
but instead its showing
10....10.... 10... 10... I'm not sure why it would.
How do I make a loop that returns distinct values?
for (i = 0; i < locations.length; i++) {
setTimeout(function() { alert("test"+i.toString()) ; }, 100);
}
How do I make a loop that returns distinct values?
You can do this by using a closure (pass i back into an immediately invoked function expression (IIFE)). This will maintain the value of i:
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() {
console.log("test" + i);
}, 100);
})(i);
}
To increment the timeout by using the i works the same way. Making sure to wrap the entire timeout call with the IIFE:
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() {
console.log("test" + i);
}, i * 100);
})(i);
}

JavaScript Closure in Loop [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I wanted to solve this question posted as a public question on testdome. Each as[i] should be a function that does alert(i).
The code to be bug-fixed is this:
function registerHandlers() {
var as = document.getElementsByTagName('a');
for (i = as.length; i-- >= 0;) {
as[i].onclick = function() {
alert(i);
return false;
}
}
}
The solution I attempted is this:
function registerHandlers() {
var as = document.getElementsByTagName('a');
//made the loop variables more explicit
for (i = as.length-1; i >=0; i--) {
var x = i;
as[x].onclick = function() {
alert(x);
return false;
}
}
}
I though that variable i is persistent, so I kept its copy in variable x, and use variable x instead of i. But it does not solve the problem completely. Please let me know what is my misunderstanding.
Your i and x values are declared in exactly the same scope, so by the time the function is executed x will be its final value. You could create a closure like this:
function registerHandlers() {
var links = document.getElementsByTagName('a');
for (var i = 0, len = links.length; i < len; i += 1) {
links[i].onclick = generateHandler(i);
}
function generateHandler (index) {
return function () {
alert(index);
return false;
}
}
}

Value gets overwritten because of access by reference

a = [];
for (var i = 0; i < 3; i++) {
a.push(function() {
console.log(i);
})
}
a[0]() // I want 0, but I get 3
I am trying to write a simple piece of code where I have an array of functions such that when I execute a function at a particular index, the index value should get printed.
However, the piece of code above shows the same result (3 in this case) for all index values. I understand that the value is pointing by reference and therefore points to the last value of i. Could someone point out how to do this in the right manner?
Wrap it around a function. Now each time the loop executes, the wrapper function has its own value of i.
a = [];
for (var i = 0; i < 3; i++) {
(function(i){
a.push(function() {
console.log(i);
})
})(i);
}
a[0]()
You can add a self executing function to act like a module. Doing this, the scope of the variable i is in that function.
a = [];
for (var i = 0; i < 3; i++) {
(function(i){
a.push(function() {
alert(i);
})
})(i);
}
a[0]()
Note: In this block (function(i){ ... })(i), i can have any name, there is no connection between i from loop and i from function, i.e. (function(r){ ... })(r).
Here is an alternate version to an anonymous function that gets created and executed all at once.
The issue that you are having is that when the function gets called, the loop has already been evaluated and the value of i has already reached the max value of 3. You need trap the current value of i while the loop is being evaluated.
var a = [];
for (var i = 0; i < 3; i++) {
var fn = function() {
console.log(arguments.callee.i);
}
fn.i = i; // Pass as 'i' parameter to 'fn'.
a.push(fn);
}
a[0](); // The value 0 will be printed, rather than 3.
There is more than one way to skin a cat. The code above is very similar to:
var a = [];
function fn(i) {
return function() {
console.log(i);
}
}
for (var i = 0; i < 3; i++) {
a.push(fn(i));
}
a[0](); // The value 0 will be printed, rather than 3.

FOR - getElementByName and i value [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
Following my code:
for(var i =0; i < document.getElementById('test').getElementsByTagName("li").length; i++){
document.getElementById('test').getElementsByTagName("li")[i].onmouseover= function(){
alert(document.getElementById('test').getElementsByTagName("li")[i].innerHTML);
}
}
HTML:
<div id="test">
<ul><li>test</li><li>test2</li><li>test3</li><li>test4</li></ul>
</div>
JSfiddle: http://jsfiddle.net/Pwddf/1/
"i" is always assigned the last value and then does not work. How to solve?
The problem is scoping. If you create a function inside of a loop, the loop variables will always have their last loop values. Basically, the loop executes, but the variables inside the function declaration are not evaluated until the function is called, at which point "i" is equal to the last value. You can use a closure to make the vars resolve immediately.
for(var i =0; i < document.getElementById('test').getElementsByTagName("li").length; i++){
(function(i) {
document.getElementById('test').getElementsByTagName("li")[i].onmouseover= function(){
alert(document.getElementById('test').getElementsByTagName("li")[i].innerHTML);
};
})(i);
}
I also agree with tymeJV that you should store your elements first, rather than reselecting them.
Looks like you want querySelectorAll instead:
var elems = document.querySelectorAll("#test ul li");
for (var i = 0; i < elems.length; i++) {
elems[i].onmouseover = function() {
console.log("See?");
}
}
If you actually need that i value, use a closure inside the for:
(function(i) {
elems[i].onmouseover = function() {
console.log("See?" + i);
}
})(i)
Demo: http://jsfiddle.net/Pwddf/2/
Here is a very concise solution that works in jsfiddle inside Firefox and IE9:
var elems = document.getElementById("test").getElementsByTagName("li");
for(var i =0; i < elems.length; i++){
elems[i].onmouseover= function(e){
console.log(this.innerHTML);
console.log(e);
}
}
http://jsfiddle.net/8LyhN/1/
Not knowing what all you are planning to do inside your mouseover event, I recommend passing in the event so you can reference it as 'e'.
You should do like this if you really want to use javascript than JQuery.
var ul = document.getElementById("test");
var li = ul.getElementsByTagName("li");
for(var i =0; i <li.length; i++){
li[i].onmouseover= function(){
alert(this.innerHTML);
}
}
check here : http://jsfiddle.net/alaminopu/Pwddf/5/
You need to cache i;
for(var i =0; i < document.getElementById('test').getElementsByTagName("li").length; i++)
{
var _i = i;
document.getElementById('test').getElementsByTagName("li")[i].onmouseover= function()
{
alert(document.getElementById('test').getElementsByTagName("li")[_i].innerHTML);
}
}
// Even better;
var elements = document.getElementById('test').getElementsByTagName("li");
for(var i =0; i < elements.length; i++)
{
elements[i].addEventListener('mouseover', function()
{
alert(this.innerHTML);
});
}

Categories