2

Im working on loading google map on-demand for my website utilizing this code:

  var googleMaps = document.createElement("script");
  googleMaps.type = "text/javascript";
  googleMaps.src = "https://maps.googleapis.com/maps/api/js?v=3.exp&" +
  "callback=googlemapready";

Problem is that no matter what i do, callback is executed as 'window.googlemapready', is there any way i can set it to be a method of a different object ? That is without polluting global namespace, i know i could just wrap above code in a function and set window.googlemapready = something...

  • Use the loader of the jsapi: http://stackoverflow.com/questions/5296115/can-you-load-google-maps-api-v3-via-google-ajax-api-loader – Dr.Molle Jul 19 '14 at 12:36
  • As far as i understand this wont do because i want to not only dynamically initialize map, but also dynamically insert the very googlemap script onto my page upon request (so that it isnt downloaded before request to use map is made). – user3561092 Jul 19 '14 at 12:49
  • the maps-API will be loaded when you load it( the jsapi must be loaded beforehand) – Dr.Molle Jul 19 '14 at 13:01
  • Thats the problem, since im using only this map on my site it would be just another redundant layer of scripts to download, i need to either pass something within src of script element to google to change default callback context, or use some js workaround to redirect callbacks associated with googlemap to other object without polluting global namespace. Ofc not that it will otherwise ruin my project but it would be nice to have feature if something like this could be done. – user3561092 Jul 19 '14 at 13:09
  • The context is window, the function must exists there when google tries to access the callback(there is no workaround). What you can do: remove the callback from the global namespace as soon as it has been called. – Dr.Molle Jul 19 '14 at 13:22

1 Answers1

1

Basically the callback must be a function that is accessible when you're in global scope(that's where google runs the callback).

The API uses eval to execute the callback, so the procedure is like this:

//the global callback
function bar(){ alert('callback executed');}

//string provided as callback
callbackname='bar' ;

//execute it
eval('window.'+callbackname+'()') ;

when you take a look at the eval-part it should be possible to run functions that are not defined global, e.g. as properties of objects:

//a global object with a method
foo={bar:function(){ alert('callback executed too');}};

//string provided as callback
othercallbackname='foo.bar';

//execute it
eval('window.'+othercallbackname+'()');

...and it works(also with the maps-API).

The problem: you still need a global thing(foo in this case).

But it's not a real problem, when you work with google-API's there will be at least 1 global object you can't get rid of: google

So: define the callback as property of the global google-object.

You may ask how you can set the property of google when you didn't load the API yet : define it on your own before you load the API:

window.google={bar:function(){/*do something*/}};

..then load the API using: callback=google.bar

sample-implementation(suitable for multiple calls):

//create maps of elements with className map
document.addEventListener('click',function(e){
  var node=e.target,callback,script,execCallbacks;

  //check the class
  if(node.className==='map'){
     //assign a new class to prevent from further clicks 
     node.className='mapped';

     //when window.google isn't available, create it
    if(!window.google){
      window.google={}; 
    }

    //we will store the callbacks in an array  
    if(!window.google.callbacks){
      window.google.callbacks=[];
    }
    //function that executes the callbacks
    if(!window.google.execCallbacks){
      window.google.execCallbacks=function(){
        while(this.callbacks.length){
          this.callbacks.shift()();
        }
      };
    }

    //define the callback(creates a simple map) 
    callback=function(){
        new google.maps.Map(node,
                           {zoom:1,
                            center:new google.maps.LatLng(0,0)
                           });
    };

    //google.maps isn't loaded yet
    if(!window.google.maps){
       //push the callback to the callbacks
       window.google.callbacks.push(callback);
       //load the API
       script=document.createElement('script');
       script.src="https://maps.googleapis.com/maps/api/js?v=3&" +
                  "callback=google.execCallbacks";
       document.getElementsByTagName('script')[0].parentNode.appendChild(script);
     }
     //API is already loaded, run the callback directly
     else{
      callback();
     }

  }
});

Demo: http://jsfiddle.net/doktormolle/gH8FR/

Dr.Molle
  • 116,463
  • 16
  • 195
  • 201