-1

I have a JSON with some locations to show on a Google map with markers and info window.

With a simple loop I can create the markers on the map (there are a lot of examples for putting many markers on a single map), but I have an extra level of difficulty: since I have physical addresses in the JSON, I have to geocode them first, translating into coordinates.

Anyway, I got working this too: for each loop, every JSON item is translated in its coordinates and a marker is added

But here comes the problem: in the geocode callback I can't access my current JSON item (I need it to build my info window)... It always returns the last JSON item, so it's unuseful

Here is a working snippet:

var locations = [{"name":"Le Ginestre","address":"Via G. Marconi, Tremestieri Etneo"},{"name":"Le Zagare","address":"Via Manzoni, San Giovanni La Punta"},{"name":"Katan\u00e8","address":"Via Quasimodo 1, Gravina di Catania"}];

function initMap(){

    if (locations.length > 0){

        var i;
        var map;
        var location;
        var geocoder;
        var position;
        var marker;
        var bounds = new google.maps.LatLngBounds();
        var mapOptions = {
            mapTypeId: 'roadmap'
        };

        map = new google.maps.Map(document.getElementById("map"), mapOptions);
        var infoWindow = new google.maps.InfoWindow();

        for(i = 0; i < locations.length; i++){
            location = locations[i];
            geocoder = new google.maps.Geocoder();
            geocoder.geocode({ 'address': location.address }, function(results, status){
                console.log(location); // THIS RETURNS ALWAYS THE LAST JSON ITEM
                if (status === 'OK') {
                    position = results[0].geometry.location;
                    bounds.extend(position);
                    map.fitBounds(bounds);
                    marker = new google.maps.Marker({
                        position: position,
                        map: map
                    });

                    google.maps.event.addListener(marker, 'click', (function(marker) {
                        return function() {
                             // AND OF COURSE THIS SHOWS THE WRONG ADDRESS
                            infoWindow.setContent(location.address);
                            infoWindow.open(map, marker);
                        }
                    })(marker));
                }
            });
        }

        google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
            this.setCenter(bounds.getCenter());
        });
    }
}
#map {
  width:100%;
  height:300px;
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA222wozVyNudm3i0A2Tr_Vlmh_RipQ284&callback=initMap" async defer></script>

<div id="map"></div>

As you see, the console.log(location); // THIS RETURNS ALWAYS THE LAST JSON ITEM line is self explained, and the info window that opens on markers' click has always the same address

I read some StackOverflow post (i.e. JavaScript closure inside loops – simple practical example) but though the problem is similar I did not understood a lot...

Please any help? Thanks

Ivan
  • 2,463
  • 6
  • 39
  • 51

1 Answers1

2

Ok, I searched better and I found the answer, thanks to the following articles:

https://decembersoft.com/posts/understanding-javascript-closures-in-for-loops/ http://www.teknically-speaking.com/2013/01/closures-in-loops-javascript-gotchas.html

Here is a working example:

var locations = [{"name":"Le Ginestre","address":"Via G. Marconi, Tremestieri Etneo"},{"name":"Le Zagare","address":"Via Manzoni, San Giovanni La Punta"},{"name":"Katan\u00e8","address":"Via Quasimodo 1, Gravina di Catania"}];

function initMap(){

    if (locations.length > 0){

        var i, map, position, marker, location, geocoder;
        var bounds = new google.maps.LatLngBounds();
        var mapOptions = {
            mapTypeId: 'roadmap'
        };

        map = new google.maps.Map(document.getElementById("map"), mapOptions);
        var infoWindow = new google.maps.InfoWindow();

        for(i = 0; i < locations.length; i++){
            location = locations[i];
            
            // put geocoder stuff in a closure
            (function(item){
                var name = '<b>' + item.name + '</b>';
                var address = item.address;
                
                geocoder = new google.maps.Geocoder();
                return geocoder.geocode({ 'address': address }, function(results, status){
                    if (status === 'OK') {
                        position = results[0].geometry.location;
                        bounds.extend(position);
                        map.fitBounds(bounds);
                        marker = new google.maps.Marker({
                            position: position,
                            map: map
                        });

                        google.maps.event.addListener(marker, 'click', (function(marker) {
                            return function() {
                                infoWindow.setContent(name + '<br>' + address);
                                infoWindow.open(map, marker);
                            }
                        })(marker));
                    }
                });
            })(location);
        }

        google.maps.event.addListenerOnce(map, 'bounds_changed', function() {
            this.setCenter(bounds.getCenter());
        });
    }
}
#map {
  width:100%;
  height:300px;
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyA222wozVyNudm3i0A2Tr_Vlmh_RipQ284&callback=initMap" async defer></script>

<div id="map"></div>

Hope this can be useful for people trying to work on Google Maps

Ivan
  • 2,463
  • 6
  • 39
  • 51