Google Maps v3 открывает последнее информационное окно при нажатии на маркер - PullRequest
2 голосов
/ 22 июля 2010

У меня есть общий доступ infoWindow для всех моих маркеров.Это хорошо работает, если я использую jquery $().each(function(){}), но если я изменю его на нативный цикл JavaScrips для цикла while или while, он не будет работать должным образом.

Всякий раз, когда я нажимаю на маркер, он открывает infoWindow последнего заполненного маркера вместо infoWindow.

. Это работает:

$(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 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);
 });

Но это не работает:

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);
}

Есть мысли?

1 Ответ

4 голосов
/ 22 июля 2010

У вас будет очень распространенная проблема закрытия в цикле for. Кстати, Я только вчера ответил на похожий вопрос по этой теме, который вы, возможно, захотите проверить.

Переменные, заключенные в замыкание, совместно используют одну и ту же среду, поэтому к тому времени, когда будет вызван обратный вызов click, цикл завершит свою работу, а переменная infoWindowContent останется указывающей на последнее значение, которое было ей присвоено к.

Одним из способов решения этой проблемы является использование большего числа замыканий с использованием фабрики функций:

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)
  );
}

Это может быть довольно сложной темой, если вы не знакомы с тем, как работают замыкания. Возможно, вам будет интересно ознакомиться со следующей статьей для краткого введения:


UPDATE:

Причина, по которой работает пример jQuery, заключается в том, что функция, которую вы передаете методу each(), заключает каждую итерацию в свою область видимости. Вы можете практически сделать то же самое в своем простом примере JavaScript:

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);
     });

  })();
}

2-е ОБНОВЛЕНИЕ:

Обратите внимание, что первый пример также можно переписать, используя анонимную функцию:

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));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...