0

I have a function which loops an array... whilst it works it seems to change the value of the information being sent from "begin" function to "process" function, but i don't know why... I'm sure i made a silly mistake but I cannot see the mistake =/

This is my function:

var array_data = data[9]; //global array to use
console.log(array_data); //debug

function process(i){
alert('Number is '+i); // shows the value "7" (should show value "1")
}

function begin(){
var count = 0;

for(i in array_data){

if(parseInt(array_data[i][9])){ //if true

    var result = create_layout(i); //function to make the layout
    alert('Number is '+i); //shows the value "1" (this is correct so far)

   document.getElementById('result'+count).innerHTML = result;  
   document.getElementById('result'+count).onclick = function() { process(i); };    

count++;

       }
}   

window.onload = function() {  
begin();  
};

Below is my array for (array_data) from the console log:

1: Array[10]
   0: "Car One"
   1: "1"
   2: "3"
   3: "d2.jpg"
   4: "1"
   5: "1"
   6: "200"
   7: "85"
   8: "5000"
   9: "1"
length: 10    

7: Array[10]
   0: "Car Two"
   1: "1"
   2: "1"
   3: "e2.jpg"
   4: "1"
   5: "0"
   6: "500"
   7: "50"
   8: "3000"
   9: "0"
length: 10

So I'm wondering why might it is changing the value of "i" when it reaches the process function ?

Sir
  • 8,135
  • 17
  • 83
  • 146

3 Answers3

4

By the time the onclick function actually gets called, the value of i will have changed because of the loop it's in. You should "anchor" its value. The easiest way to do it is like this:

for( some loop on `i`) {
    (function(i) {
        // your code that depends on `i`
    })(i);
}

This will ensure that the value of i will not change within that closure (unless you change it yourself)

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • Why would it change for that div though surely once its looped and assigned it to div ID result0 the next loop will assign it to div ID result1 ? – Sir Jul 25 '12 at 23:21
  • 1
    Yes, but the actual value of `i` changes. Functions aren't constants, they're closures and they inherit the variables of their containing scope. If those variable change in that scope, the function will reflect that change. – Niet the Dark Absol Jul 25 '12 at 23:22
  • So setting div id="result0" to i with a value of "1" isn't set in stone in the browser as the number one but rather the variable i? – Sir Jul 25 '12 at 23:25
  • Pretty much. But by using the code I gave you, it basically means that `i` is no longer affected by the loop inside there. – Niet the Dark Absol Jul 25 '12 at 23:27
  • ok yeh your method did fix the issue, though it looks a bit ugly with the (i); at the end =/ – Sir Jul 25 '12 at 23:28
  • Put it another way, the code you had before used `i` at the time the onclick was called, not when the event handler was created. – Lee Taylor Jul 25 '12 at 23:29
  • Ah i see :) i'll have to remember that! – Sir Jul 25 '12 at 23:30
2
  • Don't use for-in-loops on arrays (OK, doesn't apply here)
  • There's a missing closing brace for your begin function
  • Just use window.onload = begin; - no need for an extra function
  • Yet, there is need for a extra closure for your i variable. The time the event handler gets executed, it will use the variable i - whose current value is the one it got in the last loop cycle. It might be the same issue with your count variable.
for(var i=0; i<array_data.length; i++) (function(i){

    <...>.onclick = function() { ...i...; };    

})(i);
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • May i ask why the for in loop is not recommended also as i need to assign I to the key ID rather than the position. – Sir Jul 25 '12 at 23:26
  • Um, is `array_data` no array? – Bergi Jul 25 '12 at 23:31
  • It is an array from a json_encode i carry the id related to the data in the array as the key number rather than 0 1 2 3 etc if that makes sense? But its still only an array.length of 2 Thats why in the console.log it shows 1 then 7, those are the row id's in MYSQL table ! – Sir Jul 25 '12 at 23:33
  • Could you print the JSON representation in your question? There's a differencs between arrays (lists) and objects (dictionaries/maps/...) in javascript. An Array of length 2 can only have the keys/indizes 0 and 1. – Bergi Jul 25 '12 at 23:39
  • That's not JSON. Is it `{"1":...,"7":...}` or `[...,...]`? – Bergi Jul 26 '12 at 00:02
  • Good - the name was confusing. – Bergi Jul 26 '12 at 02:15
0

In ECMAScript 5, you can go ahead and use bind to bind the argument to your function:

document.getElementById('result' + count).onclick = process.bind(null, i);

This is great if you don't have to worry about Internet Explorer 8 and earlier versions.

Ry-
  • 218,210
  • 55
  • 464
  • 476