2

I'm trying to loop over a simple array, find elements based on the array values, and then add a click event for each element. For some reason (maybe related to the scope?) all the events think they're at the end of the array.

Example HTML:

<!-- "Sectors" -->
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>

Corresponding javascript:

var sectorArray = ["a", "b", "c"];
// Loop over sector letters
for (var s in sectorArray) {
    var sector = sectorArray[s];
    console.log("Adding click event for sector: " + sector);
    $('div.' + sector).on("click", function(e){
        console.log("Clicked sector: " + sector);
    });
}

When I click on any div, I get the message that I'm on sector "c". Here is a jsfiddle: http://jsfiddle.net/luken/Pd66m/

I was able to fix the problem by making everything inside the for-loop into it's own, separate function... and there are other solutions... But I'd like to figure out why this, above, won't work. Thanks.

Luke
  • 18,811
  • 16
  • 99
  • 115

4 Answers4

3

closure issue, try this. I added an anonymous function to "enclose" loop values.

var sectorArray = ["a", "b", "c"];
// Loop over sector letters
  for (var s in sectorArray) {
    var sector = sectorArray[s];
    (function(sec){
      $('div.' + sec).on("click", function(e){
        console.log("Clicked sector: " + sec);
      });
    }(sector))
 }
james emanon
  • 11,185
  • 11
  • 56
  • 97
  • Although many of these solutions work, I went with this solution. It worked well ...although I'm not a fan of the anonymous function notation. – Luke Jan 12 '14 at 04:57
3

Another way with pure js, by adding a closure:

for (var s in sectorArray) {
    (function(s){  //This line creates a 'per loop cycle' s var
       var sector = sectorArray[s];
       console.log("Adding click event for sector: " + sector);
       $('div.' + sector).on("click", function(e){
           console.log("Clicked sector: " + sector);
       });
    })(s);   //Calls the function
}

This way the inner s is not 'shared' and each loop cycle will have its own copy, so it does not get overwritten.

Hope this helps. Cheers

Edgar Villegas Alvarado
  • 18,204
  • 2
  • 42
  • 61
2

It is a known issue with using closure in a loop

$.each(sectorArray, function (i, sector) {
    console.log("Adding click event for sector: " + sector);
    $('div.' + sector).on("click", function (e) {
        $selection.html(sector);
        console.log("Clicked sector: " + sector);
    });
})
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
2

You can also make a function which returns the the event handler function, pass in the sector and execute it immediately like this:

$('div.' + sector).on("click", 
  function(sec){
    return function(e) {
      console.log("Clicked sector: " + sec);
    };
  }(sector)
);
scf1001
  • 251
  • 1
  • 5