views:

78

answers:

7
+2  Q: 

Variable in event

I got this code:

<script>window.onload = function () {
 var container, i;

 for (i = 0; i < 10; i ++) {
  container = document.createElement ("div");
   container.innerHTML = i;

   container.style.border = "1px solid black";
   container.style.padding = "10px";

   container.onclick = function () {
    alert (i);
   }

  document.body.appendChild (container);
 }
}</script>

Just would like to know why I get the wrong number when I click on element :(

Thanks

+2  A: 

You need to create for each iteration its own function. Try this instead:

container.onclick = (function(i) {
    return function() {
        alert(i);
    };
})(i);

Here the outer function (function(i) { … }) is used to return a new function with the value of i. When this function is called ((function(i) { … })(i)) the i is passed to that function and gets embedded into the function that gets returned.

Gumbo
+3  A: 

This is the classic scoping problem with anonymous functions.

The variable i in the function is the same for every event handler you add - so they'll all alert the same value.

You want to create a new scope for each variable: something like:

function createAlertFunction(i) {
    return function() {
        alert(i);
    }
}

//...

container.onclick = createAlertFunction(i);
Anon.
The scoping have nothing to do with function name though. Anonymous or named — scope of function has identical semantics.
kangax
+1  A: 

It's not displaying the wrong value, it's displaying the value of i when the inner anonymous function is called. I think you're expecting it to display the value of i when the function was bound to the respective divs' onclick events.

fsb
+1  A: 

Similar to Gumbo's and Anon's answers, although I personally find it slightly easier to read (just my opinion).

window.onload = function () {
        var container, i;

        for (i = 0; i < 10; i ++) {
            (function() {
                container = document.createElement ("div");
                container.innerHTML = i;

                container.style.border = "1px solid black";
                container.style.padding = "10px";

                container.onclick = function () {
                                        alert (i);
                                    };

                document.body.appendChild (container);
            })();
       }
}
Russ Cam
A: 

Here you're attempting to create something called "closure". It closes the last known context with the value of the variable "i". So to obtain a correct value inside of a closure, you have to create a new context by passing the variable value to new local scope of inner function. More about closures: http://www.jibbering.com/faq/faq%5Fnotes/closures.html

alemjerus
A: 

You can use with

var container, i;
for (i = 0; i < 10; i ++) {
    with ({ locali: i }) {
        container = document.createElement ("div");
        container.innerHTML = i;
        container.style.border = "1px solid black";
        container.style.padding = "10px";
        container.onclick = function () {
            alert(locali);
        }
    }
    document.body.appendChild(container);
}

Compared to the anonymous function solution mentioned before, it's a little less performant (which only matters if you call it 10s of 1000s of times), and works a lot better with the Visual Studio debugger (and probably others as well).

erikkallen
Why a -1 for this?
erikkallen
A: 

Rather than create a large number of virtually identical functions using closures, why not try something like this:

function containerOnClick () {
    alert(this.index);
}

window.onload = function() {
    var container, i;
    for (i = 0; i < 10; i++) {
        // -- snip --
        container.index = i;
        container.onclick = containerOnClick;
    }
};

Depending on the size of the onclick handler, as well as the number of containers you'll have in total, this could reduce the memory footprint quite a bit.

nickf