Search code examples
javascriptgoogle-maps-api-3xmlhttprequestgoogle-maps-markers

I need help making my googlemaps addlistener to work for a marker array


I'm using xmlhttp to query php for a list of markers and then putting the markers on a googlemap. That is working fine.

When a marker is clicked I've got an addlistener which for ease is just currently showing the iteration number but will be doing something else once I've finished.

No matter what marker is selected the code is acting as if the last marker generated was the one that was clicked on.

Can anyone recommend something that I might have missed?

for (i = 0; i < info.length; i++) {
    toilet = info[i];
    map_number = toilet.map_number;

    if (typeof marker_list[map_number][toilet.id] === "undefined") {
        unique_id = map_number + "_" + toilet.id;
        toilet_lat = parseFloat(toilet.lat);
        toilet_lng = parseFloat(toilet.lng);
        marker_x = parseFloat(toilet.marker_anchor_x);
        marker_y = parseFloat(toilet.marker_anchor_y);
        label_x = parseFloat(toilet.label_anchor_x);
        label_y = parseFloat(toilet.label_anchor_y);
        marker_anchor = new google.maps.Point(marker_x, marker_y);
        label_anchor = new google.maps.Point(label_x, label_y);

        marker[i] = new google.maps.Marker({
            position: {
                lat: toilet_lat,
                lng: toilet_lng
            },
            map: map,
            icon: {
                path: toilet.marker_path,
                anchor: marker_anchor,
                labelOrigin: label_anchor,
                fillColor: toilet.marker_colour,
                fillOpacity: 1,
                strokeWeight: 2,
                strokeColor: 'black'
            },
            opacity: toilet.marker_opacity,
            draggable: toilet.marker_draggable
        });

        marker[i].addListener('click', function() {
            alert(i);
        });
    }

    marker_list[map_number][toilet.id] = new Array();
    marker_list[map_number][toilet.id] = marker;
}

I've also tried adding the add listener to the end of the new marker. Also by looping through the marker array after finishing creating all of them. Also not having it as an array.

Always the same result.


Solution

  • This is a common problem with loops and InfoWindows, solved in the duplicate question: Google Maps JS API v3 - Simple Multiple Marker Example using function closure.

    change:

    marker[i].addListener('click', function() {
        alert(i);
    });
    

    To:

    /* fixed click listener using function closure */
      marker[i].addListener('click', (function(i) {
        return function() {
          alert(i);
        }
      })(i));
    

    proof of concept fiddle

    screenshot of resulting map after clicking marker 0

    // The following example creates complex markers to indicate beaches near
    // Sydney, NSW, Australia. 
    let marker_list = [];
    marker_list[0]= [];
    let marker = [];
    function initMap() {
      const map = new google.maps.Map(document.getElementById("map"), {
        zoom: 10,
        center: {
          lat: -33.9,
          lng: 151.2
        },
      });
    
      setMarkers(map);
    }
    
    // Data for the markers consisting of a name, a LatLng and a zIndex for the
    // order in which these markers should display on top of each other.
    const info = [
      {id: 0, name: "Bondi Beach", lat: -33.890542, lng: 151.274856, map_number: 0},
      {id: 1,name: "Coogee Beach", lat: -33.923036, lng: 151.259052, map_number: 0},
      {id: 2,name: "Cronulla Beach", lat: -34.028249, lng: 151.157507, map_number: 0},
      {id: 3, name: "Manly Beach", lat: -33.80010128657071, lng: 151.28747820854187, map_number: 0},
      {id: 4,name: "Maroubra Beach", lat: -33.950198, lng: 151.259302, map_number: 0},
    ];
    
    function setMarkers(map) {
      for (i = 0; i < info.length; i++) {
        toilet = info[i];
        map_number = toilet.map_number;
    
        if (typeof marker_list[map_number][toilet.id] === "undefined") {
          unique_id = map_number + "_" + toilet.id;
          toilet_lat = parseFloat(toilet.lat);
          toilet_lng = parseFloat(toilet.lng);
          // not relevant to issue
          // marker_x = parseFloat(toilet.marker_anchor_x);
          // marker_y = parseFloat(toilet.marker_anchor_y);
          // label_x = parseFloat(toilet.label_anchor_x);
          // label_y = parseFloat(toilet.label_anchor_y);
          // marker_anchor = new google.maps.Point(marker_x, marker_y);
          // label_anchor = new google.maps.Point(label_x, label_y);
    
          marker[i] = new google.maps.Marker({
            position: {
              lat: toilet_lat,
              lng: toilet_lng
            },
            map: map,
            // not relevant to issue
            /* icon: { 
              path: toilet.marker_path,
              anchor: marker_anchor,
              labelOrigin: label_anchor,
              fillColor: toilet.marker_colour,
              fillOpacity: 1,
              strokeWeight: 2,
              strokeColor: 'black'
            },
            opacity: toilet.marker_opacity,
            draggable: toilet.marker_draggable */
          });
    
    /* fixed click listener using function closure */
          marker[i].addListener('click', (function(i) {
            return function() {
              alert(i);
            }
          })(i));
        }
    
        marker_list[map_number][toilet.id] = new Array();
        marker_list[map_number][toilet.id] = marker;
      }
    }
    
    window.initMap = initMap;
    /* 
     * Always set the map height explicitly to define the size of the div element
     * that contains the map. 
     */
    #map {
      height: 100%;
    }
    
    /* 
     * Optional: Makes the sample page fill the window. 
     */
    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
    <!DOCTYPE html>
    <html>
      <head>
        <title>Complex Marker Icons</title>
        <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
        <!-- jsFiddle will insert css and js -->
      </head>
      <body>
        <div id="map"></div>
    
        <!-- 
         The `defer` attribute causes the callback to execute after the full HTML
         document has been parsed. For non-blocking uses, avoiding race conditions,
         and consistent behavior across browsers, consider loading using Promises
         with https://www.npmjs.com/package/@googlemaps/js-api-loader.
        -->
        <script
          src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&v=weekly"
          defer
        ></script>
      </body>
    </html>