1

Possible Duplicate:
Javascript infamous Loop problem?

I have the following code:

function test() {

   var columns = options.columns;

for (var i =0; i < columns.length; i++) {
    if (columns[i].type === "number") {
        var field = columns[i].field;
        columns[i].footerTemplate = function(data) { return buildFooter(data, field);     };
      }
  }
}

function buildFooter(data, field) {
   alert(field);
 }

A library function calls the footerTemplate function (which in turn call buildFooter). The alert in buildFooter states that field is always the same value (the last value iterated in for loop of test.) How can buildFooter be called with the appropriate field value (i.e.

 columns[0].footerTemplate = function(data) { return buildFooter(data, columns[0].field);} 

and

 columns[1].footerTemplate = function(data) { return buildFooter(data, columns[1].field);}

and so on...

Community
  • 1
  • 1
James
  • 2,876
  • 18
  • 72
  • 116
  • Please come up with a better title. Something other than simply re-stating the question tags. – j08691 Dec 04 '12 at 21:03
  • Sorry. I edited to give a better title. I meant to better describe prior to initial posting. – James Dec 04 '12 at 21:36

3 Answers3

4

Javascript does not scope variables inside logical blocks (loops, ifs). That field variable is shared across all the footerTemplate properties.

You can solve this by creating an inline function to create some scope:

for (var i =0; i < columns.length; i++) {
    if (columns[i].type === "number") {
      (function () {
          var field = columns[i].field;
          columns[i].footerTemplate = function(data) { 
            return buildFooter(data, field);
          };
      })();
    }
  }
}
4lbertoC
  • 233
  • 1
  • 6
bhamlin
  • 5,177
  • 1
  • 22
  • 17
  • I'm not sure why but I'm getting an error when I try this. Firebug states SyntaxError: function statement requires a name when trying the above code. – James Dec 04 '12 at 21:23
  • I was missing the parenthesis around the function, thanks @4lbertoC for correcting it. – bhamlin Dec 04 '12 at 21:28
2

Try:

columns[i].footerTemplate = (function(field) {
    return function (data) {
        buildFooter(data, field);
    };
})(field);

It immediately executes a function that returns a new function that has the correctly bound field variable. It's definitely a scope issue that is a problem with loops, so using an immediately invoked function to create a new scope and making the correct variables available. This is definitely a duplicate of Javascript infamous Loop issue? though

Community
  • 1
  • 1
Ian
  • 50,146
  • 13
  • 101
  • 111
  • in his original code, `footerTemplate` is a function. You've now executed the function and set `footerTemplate` to be the result. This isn't the same thing. – bhamlin Dec 04 '12 at 21:07
  • @bhamlin Yeah, noticed that too and was in the middle of editing. It was hard to realize (when I originally intended to do what I have changed it to) when it was formatted that way (one line) – Ian Dec 04 '12 at 21:09
  • Thanks. Firebug reports data is not defined. Note: data is not defined the enclosing function. – James Dec 04 '12 at 21:11
  • @James Not sure if it would fix it, but I added `data` as a parameter to the inner function being returned (like you originally had it) – Ian Dec 04 '12 at 21:13
  • Thanks for the edit, but unfortunately this does not fix the issue. The problem is that data is not defined in the functions that encloses this code. so invoking the outer anonymous function with data is an error. bhamlin with 4lbertoC seems to do the trick though by creating additional scope. – James Dec 04 '12 at 21:33
  • @James One last edit, I think this one would work. I misread your original code and thought `data` was also defined somewhere in the function (only `field` is) so I was passing it incorrectly. I removed it as a parameter where it wasn't needed. Our examples are no different, bhamlin just creates a scope around more stuff which isn't necessary. If this last edit doesn't work, I take it all back and give up :) – Ian Dec 04 '12 at 21:39
  • @Ian - This works now and seems to be a more concise solution. Thanks. – James Dec 04 '12 at 22:12
  • @James Again, that was my fault. I just misread the code and didn't realize how `code` was being used. Sorry about that! Glad it works though – Ian Dec 04 '12 at 22:12
  • And by `code`, I meant `data` – Ian Dec 05 '12 at 01:01
0

Javascript is function-scoped language, so your decleration of

field 

variable inside of for loop is the same as you declared it outside of foor loop, you're just overwriting same variable over and over again, there's no memory allocated for field variable in every loop, it's one same memory space that's being written to.

toske
  • 1,744
  • 13
  • 24