'Google Maps API v3 binding events to multiple maps

I've got a page with two Google maps on, using the v3 API. Currently they have one pin each, with the same lat & long set for each pin, although one of the maps will have other pins added at a later date (when I can get this to work!) The maps are generated by looping through an object, so further maps can be added simply if needed.

What I am trying to do is bind the bounds_changed event once to both maps, to run map.setZoom() after map.fitBounds() has been run. The event, however, only binds to the last map to be set up, so does not reset the zoom on the first map.

Link to JSFiddle replicating the issue: http://jsfiddle.net/pkhb8mvz/7/

(For a more clear example of what the event is being bound to, change the event to listen on click rather than bounds_changed then try clicking on the first map and watch the zoom level change on the second map)

Any help greatly appreciated!



Solution 1:[1]

The problem is that the map variable is being redefined on each iteration of your loop, so by the time your event listener callback runs it will operate on the second google.maps.Map object. The simplest solution is to capture the value of the map variable on each iteration using a closure, like so:

(function (map) {
    var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function () {
        if (!opts.center) {
            map.setZoom(opts.zoom);
        };
    });
}) (map);

I forked your JSFiddle to demonstrate the idea: https://jsfiddle.net/e8qbr8qL/

Solution 2:[2]

Created this fiddle that works based on this answer https://stackoverflow.com/a/5839041/2321666.

Apart from the function you need to add, your map variable should be an array so that there is one instance of each map.

map[i] = new google.maps.Map($(maps[i].mapElement)[0], opts);

If you need any explanation of the code please ask, but i think there is enough info about javascript closures in the post added.

Solution 3:[3]

You can't add a listener to multiple maps unless you keep references to all of them, currently you are only keeping a reference to the last map created.

    // use function closure to associate the map with its bounds listener
    addBoundsListener(map, opts, bounds);
    map.fitBounds(bounds);
}

function addBoundsListener(map, opts, bounds) {
    // If no center option has been specified, center the map to
    // contain all pins and reset the zoom
    var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function () {
        if (!opts.center) {
            map.setZoom(opts.zoom);
        }
    });
}

updated fiddle

code snippet:

var maps = {
  "propertyLocation": {
    "mapElement": "#map1",
    "options": {
      "zoom": 10,
      "streetViewControl": false
    },
    "pins": [{
      "title": "Test 1",
      "lat": "52.1975331616",
      "long": "0.9771180153"
    }]
  },
  "localArea": {
    "mapElement": "#map2",
    "options": {
      "zoom": 14,
      "streetViewControl": false
    },
    "pins": [{
      "title": "Test 2",
      "lat": "52.1975331616",
      "long": "0.9771180153"
    }]
  }
};

// Sensible defaults
var defaults = {
  zoom: 9,
  mapTypeId: google.maps.MapTypeId.ROADMAP,
  draggable: true
};

for (var i in maps) {
  // Extend the options
  var opts = $.extend(true, defaults, maps[i].options),
    marker,
    map,
    bounds = new google.maps.LatLngBounds();

  // Create the map
  map = new google.maps.Map($(maps[i].mapElement)[0], opts);

  // Create all pins
  for (var p = 0; p < maps[i].pins.length; p++) {
    var pin = maps[i].pins[p];
    marker = new google.maps.Marker({
      position: new google.maps.LatLng(pin.lat, pin.long),
      map: map,
      title: pin.title,
      icon: pin.icon
    });

    // Extend the bounds of the map to contain the marker
    bounds.extend(marker.position);
  }
  // use function closure to associate the map with its bounds listener
  addBoundsListener(map, opts, bounds);
  map.fitBounds(bounds);
}

function addBoundsListener(map, opts, bounds) {
  // If no center option has been specified, center the map to
  // contain all pins and reset the zoom
  var listener = new google.maps.event.addListenerOnce(map, "bounds_changed", function() {
    if (!opts.center) {
      map.setZoom(opts.zoom);
    }
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div style="width: 500px; height: 500px;" id="map1"></div>
<div style="width: 500px; height: 500px;" id="map2"></div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tomcant
Solution 2 Community
Solution 3