eschwartz / backbone.googlemaps

A Backbone JS extension for interacting with the Google Maps API (v3.10)
MIT License
139 stars 55 forks source link

Enforce closing infoWindow when another is open #29

Closed halcyonandon closed 10 years ago

halcyonandon commented 10 years ago

Opening this issue because the default behavior is to continually open infowindows without closing the open ones.

I need the behavior to be the latter. I'm not sure if this should/could be an option or if I should do so on my end using an onClose/Open event or something.

eschwartz commented 10 years ago

The current expected behavior is to only allow a single InfoWindow to be open per LocationCollection. InfoWindows are opened when the MarkerView's model is selected, and the LocationCollection ensures that only a single model is selected at a time:

GoogleMaps.LocationCollection = Backbone.Collection.extend({
    // ...
    constructor: function() {
      // ...

      // Deselect other models on model select
      // ie. Only a single model can be selected in a collection
      this.on("change:selected", function(selectedModel, isSelected) {
        if (isSelected) {
          this.each(function(model) {
            if (selectedModel.cid !== model.cid) {
              model.deselect();
            }
          });
        }
      }, this);
    }
  });

Can you give me more information about the issue you're experiencing? Is it possible that not all of your models are in the same collection?

halcyonandon commented 10 years ago

Ah, i see, okay, well I am doing something a little different with my infoWindows in that I'm passing in the full content and treating them like a Bootstrap popover in terms of markup/css used. I handled my issue in a somewhat hacky way, on initialize, i hide all elements with the info-window class. I also use requireJS, but no issues there. I'm definitely using only one collection with the same models since i share the same collection across multiple views, but I'll see if there's something going on there.

define('InfoWindow', [
  'jquery',
  'underscore',
  'backbone',
  'gmaps',
  'Text!main/js/modules/templates/map/infowindow.html',
  'Backbone.GoogleMaps'
], function($, _, Backbone, gmaps, infoWindowTemplate) {
  var InfoWindow = Backbone.GoogleMaps.InfoWindow.extend({
    template: infoWindowTemplate,
    overlayOptions: {
        disableAutoPan: false,
        maxWidth: 260,
        boxStyle: {'min-width': '180px'},
        pixelOffset: new gmaps.Size(25, -65),
        infoBoxClearance: new gmaps.Size(50, 20),
        zIndex: null,
        boxClass: 'info-window mapPopup popover fade in right',
        closeBoxMargin: "2px 2px 2px 2px",
        closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
        isHidden: false,
        pane: "floatPane",
        enableEventPropagation: true
    },
    initialize: function() {
      // Hide info-windows on initialize of a new one
      $('.info-window').hide();
    },
halcyonandon commented 10 years ago

Ah, figured it out... was using a standard collection, not Backbone.GoogleMaps.LocationCollection.extend

Switched it up, fixed the problem... thanks

eschwartz commented 10 years ago

Glad you figured it out.

Just remember what I said about assigning mutable properties to a View with Backbone.extend. Using your InfoWindow example. watch what could happen:

var infoWindow_A = new InfoWindow();
var infoWindow_B = new InfoWindow();

// InfoWindow instances inherit properties from the
// InfoWindow prototype
infoWindow_A.overlayOptions.maxwidth === 260;   // true
infoWindow_B.overlayOptions.maxWidth === 260;   // true

// Changing a mutable property (eg. an object property)
// of one instance will effect all other instances
infoWindow_A.overlayOptions.maxWidth = 999;

infoWindow_A.overlayOptions.maxwidth === 999;   // true
infoWindow_B.overlayOptions.maxWidth === 999;   // true.. .wait, what?!

What happens is that there is in fact only a single overlayOptions object created, which is located at InfoWindow.prototype.overlayOptions -- each instance 'borrows' the same object by reference. So when you change a property of that object, it changes for all instances. And thats a lot of fun to debug, when you run into it :)