开发者

Google Maps v3 opens the last infoWindow when a marker is clicked

开发者 https://www.devze.com 2023-01-08 13:34 出处:网络
I have a shared infoWindow for all my markers. It works good if I use jquery\'s $().each(function(){}), but if I change it to JavaScrips\'s native for or while loop, it\'s not working as expected.

I have a shared infoWindow for all my markers. It works good if I use jquery's $().each(function(){}), but if I change it to JavaScrips's native for or while loop, it's not working as expected.

Whenever I click a marker, it will open the last populated marker's infoWindow, instead of the clicked marker's infoWindow.

This works:

$(stores).each(function() {

   var storeId = $(this).attr('storeId');
   var address = $(this).attr('rawAddress');
   var city = $(this).attr('city');
   var state = $(this).attr('state');
   var zip = $(this).attr('zip');
   var lat = $(this).attr('lat');
   var lng = $(this).attr('lng');
   var distance = $(this).attr('distance');

   //create marker
   var point = new google.maps.LatLng(lat, lng);

   var marker = new google.maps.Marker({ position: point
     , map: InStorePickup.map
     , title: city + ' #' + storeId
   });

   //create infowindow c开发者_Go百科ontent
   var infoWindowContent = '<div style="font-size: 8pt;">'
     + '<strong>' + city + ' #' + storeId + '</strong> (' + parseFloat(distance).toFixed(2) + 'mi)<br />'
     + address + '<br />' + city + ', ' + state + ' ' + zip
     + '</div>';

   google.maps.event.addListener(marker, 'click', function() {
     InStorePickup.openInfoWindow(marker, infoWindowContent);
   });

   bounds.extend(point);
 });

But this does not work:

for (var i = 0; i < 3; i++) {
    var store = stores[i];

    var storeId = $(store).attr('storeId');
    var address = $(store).attr('rawAddress');
    var city = $(store).attr('city');
    var state = $(store).attr('state');
    var zip = $(store).attr('zip');
    var lat = $(store).attr('lat');
    var lng = $(store).attr('lng');
    var distance = $(this).attr('distance');

    //create marker
    var point = new google.maps.LatLng(lat, lng);

    var marker = new google.maps.Marker({ position: point
                  , map: InStorePickup.map
                  , title: city + ' #' + storeId
    });

    //create infowindow content
    var infoWindowContent = '<div style="font-size: 8pt;">'
                   + '<strong>' + city + ' #' + storeId + '</strong> (' + parseFloat(distance).toFixed(2) + 'mi)<br />'
                   + address + '<br />' + city + ', ' + state + ' ' + zip
                   + '</div>';

    google.maps.event.addListener(marker, 'click', function() {
        InStorePickup.openInfoWindow(marker, infoWindowContent);
    });

    bounds.extend(point);
}

Any thoughts?


You would be having a very common closure problem in the for loop. Incidentally I have answered a similar question on this topic just yesterday, which you may want to check out.

Variables enclosed in a closure share the same single environment, so by the time the click callback is called, the loop will have run its course and the infoWindowContent variable will be left pointing to the last value it was assigned to.

One way to solve this is with more closures, using a function factory:

function makeInfoWindowListener (pMarker, pContent) {  
  return function() {
    InStorePickup.openInfoWindow(pMarker, pContent);
  };  
}


// ...

for (var i = 0; i < 3; i++) {

  // ...

  var infoWindowContent = '<div style="font-size: 8pt;">' + city + '...</div>';

  google.maps.event.addListener(
    marker, 
    'click', 
    makeInfoWindowListener(marker, infoWindowContent)
  );
}

This can be quite a tricky topic, if you are not familiar with how closures work. You may be interested in checking out the following article for a brief introduction:

  • Mozilla Dev Center: Working with Closures

UPDATE:

The reason why the jQuery example works, is because the function you pass to the each() method encloses each iteration in its own scope. You could practically do the same thing in your plain JavaScript example:

for (var i = 0; i < 3; i++) {

  // each iteration will now have its own scope
  (function () {

     var infoWindowContent = '<div style="font-size: 8pt;">' + city + '...</div>';

     google.maps.event.addListener(marker, 'click', function() {
       InStorePickup.openInfoWindow(marker, infoWindowContent);
     });

  })();
}

2nd UPDATE:

Note that the first example can also be rewritten as follows, using an anonymous function:

for (var i = 0; i < 3; i++) {

  // ...

  var infoWindowContent = '<div style="font-size: 8pt;">' + city + '...</div>';

  google.maps.event.addListener(marker, 'click', (function (pMarker, pContent) {  
    return function() {
      InStorePickup.openInfoWindow(pMarker, pContent);
    };  
  })(marker, infoWindowContent));
}
0

精彩评论

暂无评论...
验证码 换一张
取 消