user17753
user17753

Reputation: 3161

Looping and closure

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

Answers (1)

Just_Mad
Just_Mad

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

Related Questions