1

I am creating a map for users on my website. The way it works is I use PHP and AJAX to get all the sites users addresses, I then pass these values to my JS as JSON where I generate a google map centered around the current users address with a marker for each user on the map. This part works at the moment but what I'm struggling with is generating a unique infowindow for each user. As it is right now I get the same info window for all markers, how can I fix this?

JS

jQuery(document).ready(function($){
    $.ajax({
        url: ajax_url,
        type: 'post',
        dataType: 'json',
        data: { 
            action: 'map' 
        },
        error : function(response){
            console.log(response);
        },
        success : function(response){
            var mapOptions = {
                zoom: 16,
            }

            var geocoder = new google.maps.Geocoder();
            var infowindow = new google.maps.InfoWindow();

            // current user position
            geocoder.geocode({'address': response.current[0].postcode}, function(results, status){
                map.setCenter( results[0].geometry.location );

                var marker = new google.maps.Marker({
                    map: map,
                    position: results[0].geometry.location
                });
            });

            // other users loop
            for( var i = 0; i < response.other.length; i++ ){
                var postcode = response.other[i].postcode;

                geocoder.geocode( {'address': postcode}, function(results, status){
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });

                    google.maps.event.addListener(marker, 'click', function(){
                        infowindow.close(); // Close previously opened infowindow
                        infowindow.setContent( "<div id='infowindow'>"+ postcode +"</div>");
                        infowindow.open(map, this);
                    });
                });
            }

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

            return false;
        }
    });
});

PHP

add_action('wp_ajax_nopriv_map', 'addresses');
add_action('wp_ajax_map', 'addresses');


function addresses(){
    global $current_user;

    $address_street = get_user_meta( $current_user->ID, 'shipping_address_1', true );
    $address_city = get_user_meta( $current_user->ID, 'shipping_city', true );
    $address_postcode = get_user_meta( $current_user->ID, 'shipping_postcode', true );
    $address = $address_street . ', ' . $address_city . ', ' . $address_postcode;

    $cur_user[] = array(
        "postcode" => $address
    );

    $other_users[] = array(
        "postcode" => "LS11 6NA"
    );

    $other_users[] = array(
        "postcode" => "LS11 6LY"
    );

    echo json_encode( array( "current" => $cur_user, "other" => $other_users) );

    die();
}

I know my PHP file needs some work its just a rough draft to get this working first.

MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
Reece
  • 2,581
  • 10
  • 42
  • 90
  • 1) You are indeed creating only 1 instance of the Infowindow 2) Why do you need separate Infowindows for each marker? 3) If you really need that, you should remove the `new google.maps.InfoWindow();` from where it is and move it to your `for` loop. – MrUpsidown Jul 03 '19 at 12:13
  • you didn't pass any unique value to ajax call, so the same response you are getting – ManiMuthuPandi Jul 03 '19 at 12:13
  • @MrUpsidown It might not be separate markers exactly I just need to generate unique content for each window. Its so the users can be contacted as I will probably put their email in the window or something like that. – Reece Jul 03 '19 at 12:17
  • @ManiMuthuPandi Thanks for the reply, but could you go into further detail and explain what you mean? – Reece Jul 03 '19 at 12:19
  • What exactly are you not able to achieve with the current implementation? which btw. is better than creating a separate Infowindow object for each marker... – MrUpsidown Jul 03 '19 at 12:19
  • @MrUpsidown What I'm after might be achievable with the current implementation but I haven't found any good documentation on it. I just want each marker to have its own window content containing the users postcode. This will later be changed to an email – Reece Jul 03 '19 at 12:23
  • Yes, sorry, I didn't see you mentioned *I get the same info window for all markers*. See my answer. – MrUpsidown Jul 03 '19 at 12:27

1 Answers1

2

You need to use a closure in your for loop.

You can read Google documentation on Using closures in event listeners.

See the basic example below and note the use of the closure in the marker click event listener.

function initialize() {

    var mapOptions = {
        zoom: 5,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        center: new google.maps.LatLng(1, 1)
    };

    var locations = [
        [new google.maps.LatLng(0, 0), 'Marker 1', 'Infowindow content for Marker 1'],
        [new google.maps.LatLng(0, 1), 'Marker 2', 'Infowindow content for Marker 2'],
        [new google.maps.LatLng(0, 2), 'Marker 3', 'Infowindow content for Marker 3'],
        [new google.maps.LatLng(1, 0), 'Marker 4', 'Infowindow content for Marker 4'],
        [new google.maps.LatLng(1, 1), 'Marker 5', 'Infowindow content for Marker 5'],
        [new google.maps.LatLng(1, 2), 'Marker 6', 'Infowindow content for Marker 6']
    ];

    var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

    var infowindow = new google.maps.InfoWindow();

    for (var i = 0; i < locations.length; i++) {

        var marker = new google.maps.Marker({
            position: locations[i][0],
            map: map,
            title: locations[i][1]
        });

        google.maps.event.addListener(marker, 'click', (function (marker, i) {

            return function () {
                infowindow.setContent(locations[i][2]);
                infowindow.open(map, marker);
            }

        })(marker, i));
    }
}
#map-canvas {
  height: 160px;
}
<div id="map-canvas"></div>

<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize">
</script>

To illustrate with the use of the Geocoder, please see the below snippet. As I said in a comment, the Geocoder service has a QPS limit of 50 requests per second. If your locations list has more than 50 items, it is very likely that it will fail as the loop will be executed in less than 1 second.

function initialize() {

  var geocoder = new google.maps.Geocoder();
  var mapOptions = {
    zoom: 12,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    center: new google.maps.LatLng(40.718193, -74.001339)
  };

  var locations = [
    ['Marker 1', 'Infowindow content for Marker 1', '10001, USA'],
    ['Marker 2', 'Infowindow content for Marker 2', '10002, USA'],
    ['Marker 3', 'Infowindow content for Marker 3', '10003, USA'],
    ['Marker 4', 'Infowindow content for Marker 4', '10004, USA'],
    ['Marker 5', 'Infowindow content for Marker 5', '10005, USA'],
    ['Marker 6', 'Infowindow content for Marker 6', '10006, USA']
  ];

  var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
  var infowindow = new google.maps.InfoWindow();

  for (var i = 0; i < locations.length; i++) {

    geocoder.geocode({
      'address': locations[i][2]
    }, (function(locations, i) {

      return function(results, status) {

        var marker = new google.maps.Marker({
          map: map,
          position: results[0].geometry.location,
          title: locations[i][0]
        });

        google.maps.event.addListener(marker, 'click', (function(marker) {

          return function() {

            infowindow.setContent("<div id='infowindow-content'><h3>" + locations[i][1] + "</h3>" + results[0]['formatted_address'] + "</div>");
            infowindow.open(map, marker);
          }

        })(marker));
      }
    })(locations, i));
  }
}
#map-canvas {
  height: 160px;
}
<div id="map-canvas"></div>

<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize">
</script>
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
  • Thanks, just trying to get my head around how this works. If I can implement it into my code I'll accept your answer – Reece Jul 03 '19 at 12:41
  • You probably should have coordinates for your markers before you plot them on the map. The issue is that the Geocoder is limited to 50 requests per second... depending on the amount of locations you are trying to geocode (in your `for` loop), the requests **will** fail as you will hit the API limits. – MrUpsidown Jul 03 '19 at 13:29
  • 2
    This doesn't include the geocoding – geocodezip Jul 03 '19 at 13:33
  • I have addressed this in the second snippet. – MrUpsidown Jul 03 '19 at 14:17