jquerygoogle-mapsinfowindowdomreadyinfobubble

google maps infobubble dynamic content not loading on first marker click


I'm trying to add dynamic content inside a google maps infobubble:
- one first marker click an empty infobubble appears
- on SECOND click of the marker the correct content is loaded

As per this answer I'm using the domready event on the previously defined infobubble object to launch the function that loads the dynamic content.
...although the JS fiddle in that answer is misleading since the 'dynamic' content is actually loaded prior to domready using the content option of the new InfoBubble() call

I'm getting all the right signals in console that the domready function is being completed and the content is being correctly found on 1st marker click.

Tried:

How can I get the dynamic content to load on first click of the marker ?

JS Fiddle here

Notes:
- for the js fiddle example I'm using a $.get() call - since in my application I'm using moustache to load a template into the infobubble
- the example content being loaded has nothing to do with the $.get() call (and yes I could achieve the same without the $.get() call) but I'm just trying to use similar code layout + timing to my own application


Solution

  • Thanks to the observations in the answer by Dr.Molle I've figured out the solution - which is indeed related to the placement of the domready event trigger in the infobubble.js code.

    Unfortunately it's currently located in the updateContent_() function, which is called by open_(), before setMap() is called - which means that domready is fired BEFORE the infoBubble is added to the DOM.

    It's not possible to simply add the domready trigger after the setMap() call in the open_() function because setMap() is asynchronous... and the setMap() function doesn't have a specific callback.

    However, according to the documentation for OverlayView (which is what is being used by this plugin) the setMap() function calls the onAdd() function once AFTER setMap() is called with a valid map object:

    onAdd(): Implement this method to initialize the overlay DOM elements. This method is called once after setMap() is called with a valid map. At this point, panes and projection will have been initialized.

    and more simply:

    In the onAdd() method, you should create DOM objects and append them as children of the panes.

    Therefore we should fire the domready event within the onAdd() function, after the infoBubble is appended to the map panes:

    /**
     * On Adding the InfoBubble to a map
     * Implementing the OverlayView interface
     */
    InfoBubble.prototype.onAdd = function() {
      if (!this.bubble_) {
        this.buildDom_();
      }
    
      this.addEvents_();
    
      var panes = this.getPanes();
      if (panes) {
        panes.floatPane.appendChild(this.bubble_);
        panes.floatShadow.appendChild(this.bubbleShadow_);
      }
      google.maps.event.trigger(this, 'domready');    // infobubble has now been added to DOM so we can fire `domready`
    };
    

    I've created a pull-request for google to update the infobubble.js code and fix this issue.

    JS Fiddle here with updated code (see line 910 in the javascript window for new domready placement)
    http://jsfiddle.net/goredwards/7r96we66/

    Notes:
    - I've added timestamps in the jsfiddle at the old domready call and the correct (updated) domready call - you'll see them in the console.log - it comes to about 20ms on my system (it will vary with system speed)
    - it shows that the old domready was indeed firing prior to the infoBubble being appended to the panes
    - this gives an idea of the minimum setTimeout you'd need to put around any functions within a domready call

    If you want to use the original code without the fix - and a setTimeout hack: http://jsfiddle.net/goredwards/xeL7dxye/
    ...you can play around with the setTimeout duration and see what the minimum is - I got down to around 5ms on a fast machine. Obviously you'd have to go the other way in production code with this hack to cope with the slowest machines (ie you'd put the setTimeout duration at the maximum level you can stand - without annoyance ~150-250ms - to cover even your slowest systems).
    ... or you could just copy and update the infobubble.js code and be done with it.