Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

My application plots a bunch of markers on a map read from a MySQL database, and I want to display some content in each of the infowindows. My issue is the infowindows will only display the content of the last entry in my database. Below is my code, where I simply try to display the name of the location. I've tried alerting the variables to see if they are indeed displaying the correct content, which they are. I realize it is a javascript closure problem, but I don't know how to go about fixing this.

var startLat;
var startLng;
var locationName;

<?php foreach($workstations as $workstation):?>
    startLat = "<?php echo $workstation['lat']?>";
    startLng = "<?php echo $workstation['lng']?>";
    locationName = "<?php echo $workstation['name']?>";

    var marker = new google.maps.Marker({
        position: new google.maps.LatLng(startLat, startLng),
        map: map,
        icon: "images/purple.png"
    });

    //load all the infowindow content
    var contentString = [
                    '<div id="InfoText" style="margin: 0px; padding: 0px; overflow: hidden; border:0px">',
                    '<div class="tabs"><ul><li><a href="#tab1">General</a></li>',
                    '<li><a href="#tab2">General 2</a></li></ul>',
                    '<div id="tab1">',
                    '<b>' + locationName + '</b> - ' + locationName + '<BR>',
                    '<input id="save" type="submit" value="Reserve Today" onclick="saveStation(addMarker)" />',
                    '</div>',
                    '<div id="tab2">',
                    '</div>',
                    '</div>'
                           ].join('');

    //alert(contentString);
    var infowindow = new google.maps.InfoWindow({content: contentString});

    new google.maps.event.addListener(marker, 'click', (function(marker) {
        return function(){
            infowindow.open(map, marker);
            }
        })(marker));
<?php endforeach;?>
share|improve this question
add comment

2 Answers

up vote 3 down vote accepted

Yes. This is a js closure issue. You have one variable "marker" which all of the maps event listeners are pointing to. Try this instead:

Place this at the top (before the foreach loop):

function addMarkerListener( mark, mp, win )
{
    new google.maps.event.addListener(
          mark, 
          'click', 
          function(){win.open(mp,mark)}
}

Then, instead of the listener at the end of your code block add this:

addMarkerListener( marker, map, infowindow );

Basically, what is happening in your version is that js is saying, "Ok, I'm going to create a function and have the marker variable populate it. Got it." When the time comes to actually call the function, it says, "I'm looking for the variable 'marker', what's in that variable?" Unfortunately, this has been re-assigned in the meanwhile and now it represents the most recent assignment.

The version here, on the other hand, tells JavaScript, "I have these brand new variables, they only exist here, so don't look for them anywhere else. When one of them is clicked, then display the value related to it." When the item is clicked, JS says, "Hmm... this variable was only assigned to be used in this context so I guess I will use that."

I could go into variable binding, and there is some exciting Lambda Calculus stuff involved, but that is a bit much for this scope.

share|improve this answer
 
Thanks for your help! I gave this a try and it worked. And thanks for the explanation, really clear. –  Albert Jun 14 '11 at 6:56
add comment

You should not do the looping in PHP. Not only are you outputting massive, repetitive Javascript blocks this way, you're also producing this:

var infowindow = …
var infowindow = …
var infowindow = …
var infowindow = …

You're overwriting your own infowindow variable, so only the last one sticks, obviously.

Just prepare the data in PHP, then use a Javascript loop to process it. This should also make scope issues more obvious. In your case, the infowindow variable has one and can be fixed as below:

var workstations = <?php echo json_encode($workstations); ?>;

for (var i = 0; i < workstation.length; i++) {
    var lat = workstations[i].lat;
    var lng = workstations[i].lng;
    var name = workstations[i].name;

    var marker = …
    var content = …
    var infowindow = … 

    (function (marker, infowindow) {
        google.maps.event.addListener(marker, 'click', function () {
            infowindow.open(map, marker);
        });
    })(marker, infowindow);
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.