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:
looked through the infobubble.js code and put console.logs either side of line 1231:
google.maps.event.trigger(this, 'domready');
The results show that domready is indeed being fired PRIOR to the start of the dynamic function.
disabling animation using the infobubble disableAnimation: true
option - thinking that could be slowing the infobubble load after domready is called - but it didn't work
added setTimeout()
of up to 3 seconds but that doesn't seem to help... and that would be a poor hack anyway.
How can I get the dynamic content to load on first click of the marker ?
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
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.