I have some code that generates a bunch of button elements and appends them to a div in the body via some DOM functions. It dynamically sets a bunch of anonymous functions (event handlers) to the onclick event of each button.
This is performed by iterating from 0 to 20.
The problem is, I want to use the loop counter, i, in the event handler -- but, as the value it is at that iteration in the loop not as the final value i attains. At first, I thought that I could do this through closure, but then I realized that it did not perform how I thought it initially would. i keeps changing each iteration, and all the other anon functions (through closure?) must see the same i in that the i in scope to it all points to the same value. Since they all report the same value when you trigger the onclick.
So I guess, how can I go about fixing that? I tried setting i to another variable and so on, but that all results in the same because that new variable just has its value updated each iteration just as i. I think I'm missing something simple here.
<!DOCTYPE html>
<html>
<head>
<title>loop closure test</title>
<script language="javascript" type="text/javascript">
window.onload = function() {
var div = document.getElementById("myDiv");
for( var i = 0; i <= 20; i++ ) {
var b = document.createElement("button");
b.setAttribute("type","button");
b.appendChild(document.createTextNode("Button" + i.toString()));
b.onclick = function(event) {
var date = new Date( 2012, 3, i );
alert( date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear() );
}
div.appendChild(document.createElement("br"));
div.appendChild(b);
}
}
</script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>
I thought about it some more, and the example answer below. Basically I needed to trap i inside another closure. I decided to go with this route:
<!DOCTYPE html>
<html>
<head>
<title>loop closure test</title>
<script language="javascript" type="text/javascript">
window.onload = function() {
var div = document.getElementById("myDiv");
for( var i = 0; i <= 20; i++ ) {
div.appendChild( (function() {
var day = i;
var b = document.createElement("button");
b.setAttribute("type","button");
b.appendChild(document.createTextNode("Button" + i.toString()));
b.onclick = function(event) {
var date = new Date( 2012, 3, day );
alert( date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear() );
}
return b;
}()));
div.appendChild(document.createElement("br"));
}
}
</script>
</head>
<body>
<div id="myDiv"></div>
</body>
</html>
-
1possible duplicate of Assign click handler in for loop in javascriptPointy– Pointy2012年03月22日 20:30:44 +00:00Commented Mar 22, 2012 at 20:30
-
Yes, it would work with a closure in each loop.Bergi– Bergi2012年03月22日 20:30:46 +00:00Commented Mar 22, 2012 at 20:30
-
The key thing to know is that JavaScript local variables are scoped at the function level. Thus, if you want to give each handler its own "i", you need to instantiate the handler functions in another function. There are many, many StackOverflow questions on exactly this issue.Pointy– Pointy2012年03月22日 20:32:02 +00:00Commented Mar 22, 2012 at 20:32
-
@Pointy This is not jQuery at all and the question you linked is completely foreign to me.user17753– user177532012年03月22日 20:32:37 +00:00Commented Mar 22, 2012 at 20:32
-
1It's exactly the same question whether you're using jQuery or not; jQuery is just JavaScript, after all.Pointy– Pointy2012年03月22日 20:33:15 +00:00Commented Mar 22, 2012 at 20:33
1 Answer 1
Try to use a closure like this:
var div = document.getElementById("myDiv");
for( var i = 0; i <= 20; i++ ) {
var b = document.createElement("button");
b.setAttribute("type","button");
b.appendChild(document.createTextNode("Button" + i.toString()));
b.onclick = function(pos) {
return function(event) {
var date = new Date( 2012, 3, pos );
alert( date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear() );
}
}(i);
div.appendChild(document.createElement("br"));
div.appendChild(b);
}
Comments
Explore related questions
See similar questions with these tags.