google maps infobubble dynamic content not loading

2019-08-30 11:20发布

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 ?

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

2条回答
虎瘦雄心在
2楼-- · 2019-08-30 11:33

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.

查看更多
走好不送
3楼-- · 2019-08-30 11:38

the issue seems to be the open_-method of the infobubble(which will be called in the open-method):

InfoBubble.prototype.open_ = function(opt_map, opt_anchor) {
  this.updateContent_();

  if (opt_map) {
    this.setMap(opt_map);
  }
  //............................
}

It first calls the method updateContent_ (where the domready-event will be triggered) and then sets the map. But the overlay will not be added to the map until the map-property has been set, the content is a DocumentFragment/Node that hasn't been attached to the document yet, so jQuery may not find it.

Possible solution:

Use the content_-property of the infobubble as context for the jQuery-selector, then it shouldn't matter if the content already has been attached to the document

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

  google.maps.event.addListenerOnce(infoBubble,'domready',function () {

    var that=this;            
    //when we load the additional content asynchronously, 
    //make sure that it's the correct content we are loading
    var token=new Date().getTime()*Math.random();
    that.set('token',token);

    $.get('https://lh4.googleusercontent.com/-_Cox6aEnSkU/UQ_B0LK4khI/AAAAAAAAAzw/4H4dsWGPgeE/s150/go-button.png', function (myImage) {
      if(that.get('token')===token){
        $(".dialog",that.content_).html('<img id="theImg" src="https://goo.gl/phmzis" />');
      }     
        })

  });
  infoBubble.open(map, marker);
});

http://jsfiddle.net/doktormolle/aLtz76ym/

查看更多
登录 后发表回答