2

I have an array filled with strings that have the same name as Google Maps Polygon Objects I've created. I'd like to iterate through the array to set a specific option. Here's the code:

for (var i = 0; i < statesPoly.length; i++) {
    google.maps.event.addListener(statesPoly[i], 'mouseover', function() {
        statesPoly[i].setOptions({ strokeWeight: '2' });
    });
}

When executed I get "Cannot call method 'setOptions' of undefined" as the script seems to be using statesPoly[i] literally. When I replace statesPoly[i] with, for example, statesPoly[11], the script works as expected.

The loop also works as expected when I try something like this:

for (var i = 0; i < statesPoly.length; i++) {
    alert(statesPoly[i].strokeColor);
}

What am I doing wrong?

UPDATE:

Getting closer here. I believe the reason that using this works in some cases is because my function is expecting an object and I am giving it a string. Could this be the case?

alert(statesPoly[0]);
        google.maps.event.addListener(sarawakPoly, 'mouseover', function() {
            $("#"+statesPoly[0]).addClass("highlight");
            sarawakPoly.setOptions({ strokeWeight: '2' });
            //infowindow.open(map,marker);
        });

The code above will alert with SarawakPoly, and using statesPoly[0] as a string in the ID works as expected. This

 alert(statesPoly[0]);
        google.maps.event.addListener(statesPoly[0], 'mouseover', function() {
            $("#"+statesPoly[0]).addClass("highlight");
            statesPoly[0].setOptions({ strokeWeight: '2' });
            //infowindow.open(map,marker);
        });

Does not work because "Uncaught TypeError: Cannot read property 'mouseover' of undefined"

If I'm right, how to I get my JS to cast my array variable as an object?

chris_mac
  • 943
  • 3
  • 10
  • 21

3 Answers3

5

This is a very common mistake in JavaScript code:

for (var i = 0; i < n; i++) {
    registerSomeCallback(function () {
        console.log(i);
    });
}

On each loop iteration the variable i is incremented, and becasue of JavaScript's lexical scoping the functions defined on each iteration share the same i variable. This means that when the callback is invoked (in your case when a Google Maps event occurs), i will always be the last value the loop reached.

It's as if you're doing this:

var i, fn;

i = 0;
fn = function () { alert(i); };
fn(); // will alert "0"
i = 1;
fn(); // i has changed, will now alert "1"
i = 2;
fn(); // i has changed again, will now alert "2"

You need to make sure there's a new variable scope for each iteration of your loop, for example:

for (var i = 0; i < n; i++) {
    (function (n) {
        registerSomeCallback(function () {
            console.log(n);
        });
    }(i));
}

In this version of the code, each callback is defined in its own variable scope with its own counter variable (which you could still call i, but I've called n to make the example more clear).

Community
  • 1
  • 1
georgebrock
  • 28,393
  • 13
  • 77
  • 72
2

Can you try using this instead?

    for (var i = 0; i < statesPoly.length; i++) {
      (function(i) {
        google.maps.event.addListener(statesPoly[i], 'mouseover', function() {
            this.setOptions({ strokeWeight: '2' });
        });
       })(i);
    }
Heitor Chang
  • 6,038
  • 2
  • 45
  • 65
1

statesPoly[i] is undefined because your variable i is not defined inside the new function you attached to the event listener.

You can do several things here but the most simple way will be to pass this variable to the function. Something like that:

google.maps.event.addListener(statesPoly[i], 'mouseover', function(i) {
  statesPoly[i].setOptions({ strokeWeight: '2' });
});
Ido Green
  • 2,795
  • 1
  • 17
  • 26
  • You're on to something w/the variable not being defined in the new function, but your solution does not work. Any ideas on a better way to accomplish this? – chris_mac Jun 08 '12 at 18:12