Reputation: 3161
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>
Upvotes: 0
Views: 260
Reputation: 4077
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);
}
Upvotes: 1