1

I am using the Google Maps API to display a series of markers on a map. If there are no markers visible I want to display a little message advising the user to zoom out.

This is the code I am currently using:

google.maps.event.addListener(map, 'bounds_changed', function() {
    bounds =  map.getBounds();
    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();
    n = ne.lat();
    e = ne.lng();
    s = sw.lat();
    w = sw.lng();
    var counter = 0; // Define "counter" and set it to zero each time the bounds are changed
    var xmlfile = 'php-to-xml-dev.php?n=' + n + "&e=" + e + "&s=" + s + "&w=" + w;
    downloadUrl(xmlfile, function(doc) {
        var xmlDoc = xmlParse(doc);
        var markers = xmlDoc.documentElement.getElementsByTagName("marker");
        for (var i = 0; i < markers.length; i++) {
            var lat = parseFloat(markers[i].getAttribute("lat"));
            var lng = parseFloat(markers[i].getAttribute("lng"));
            var point = new google.maps.LatLng(lat,lng);
            var content=markers[i].getAttribute("content");
            var icn=markers[i].getAttribute("icon");
            createMarker(point, content, icn);
            counter++; // Increment "counter" by 1
        }
    });
    if (counter > 0) {
        locationButton.classList.add("custom-map-control-hidden"); // Hide the message button
    }else{
        //locationButton.textContent = 'No defibs visible. Try zooming out.';
        locationButton.textContent = counter; // Temporary line in place of the one above for debugging
    }
});

Regardless of how many markers are visible, the value of "counter" is always zero.

I've read numerous similar questions on here and it appears to be something to do with global and local scope and/or "hoisting". Whatever I try I cannot get "counter" to give me the actual count of the markers. If I understand correctly, the "counter" inside the "for" loop is being treated as a different variable to the one defined in the "bounds changed" function. But I can't find any way of it all being treated as one variable.

geocodezip
  • 158,664
  • 13
  • 220
  • 245
TrapezeArtist
  • 777
  • 1
  • 13
  • 38
  • Do you stepped through it in debug, or have any other evidence that it is actually executing the contents of your `markers` loop? Because offhand it looks like that loop may be failing. – RBarryYoung Jul 29 '23 at 11:07
  • 3
    I know nothing about Google Maps API, but `downloadUrl` seems to be asynchronous. That said, `.textContent = counter` is always evaluated earlier than `counter++`. – InSync Jul 29 '23 at 11:07
  • It's basically this https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call?answertab=scoredesc#tab-top. If you understand that then you can understand why you're getting unexpected results in your example. – Sergiu Paraschiv Jul 29 '23 at 11:15
  • 1
    I was so hung up on the scope and hoisting that I didn't consider asynchronous. By moving the if-else statement inside the for loop I have almost solved it. The only issue now is that as the map is panned around (and therefore the bounds are changed) the value of counter never falls below 1. Consequently panning the map to a blank area never reinstates the message. I'll answer the question with my final code when (if!) I can iron out that little problem. Thanks, guys. – TrapezeArtist Jul 29 '23 at 11:51

1 Answers1

1

The problem was the synchronous behaviour of downLoadUrl as suggested by InSync. So I moved the if-else statement and the problem is almost solved. Here is the modified code:

google.maps.event.addListener(map, 'bounds_changed', function() {
    bounds =  map.getBounds();
    var ne = bounds.getNorthEast();
    var sw = bounds.getSouthWest();
    n = ne.lat();
    e = ne.lng();
    s = sw.lat();
    w = sw.lng();
    var counter = 0;
    var xmlfile = 'php-to-xml.php?n=' + n + "&e=" + e + "&s=" + s + "&w=" + w;
    downloadUrl(xmlfile, function(doc) {
        var xmlDoc = xmlParse(doc);
        var markers = xmlDoc.documentElement.getElementsByTagName("marker");
        for (var i = 0; i < markers.length; i++) {
            var lat = parseFloat(markers[i].getAttribute("lat"));
            var lng = parseFloat(markers[i].getAttribute("lng"));
            var point = new google.maps.LatLng(lat,lng);
            var content=markers[i].getAttribute("content");
            var icn=markers[i].getAttribute("icon");
            createMarker(point, content, icn);
            counter++;
            if (counter > 1) {
                locationButton.classList.add("custom-map-control-hidden");
            }else{
                locationButton.classList.remove("custom-map-control-hidden");
                locationButton.textContent = 'No defibs visible? Try zooming out.';
            }
        }
    });

});

One small problem remains, because if there are markers on the screen but then the user pans until there are none, the "No defibs visible?" message doesn't re-appear. This seems to be because the value of counter never goes below 1. It's a minor point though so I'm happy to use the code as it is until I can find the solution.

TrapezeArtist
  • 777
  • 1
  • 13
  • 38