To better describe the need for this here is a summary of our requirements:
- We wanted the ability to embed our live maps (and map related capabilities) as widgets in other HTML pages throughout our company website
- We wanted the ability to embed these live maps as a stand-alone snippets of HTML without having to modify the page <head>. This would allow content authors to embed maps without having access to modify anything but a container element on the page.
- We wanted the ability to wrap these up in a container (in our case this will probably be a DotNetNuke module)
- We didn’t want the loading of the embedded map to have direct impact on the loading of the parent page (asynchronous loading)
- We didn’t want to deal with iframes for embedded map widgets
What we wanted was the ability to include a snippet like the following in any page and get a fully dynamic map widget (Note: I have renamed the objects/namespaces to make this description generic. myMapApi is used as the base namespace for these examples):
Because Dojo is bootstrapped and modules can be loaded on demand, Dojo provides an addOnLoad method which allows you to ensure that everything has been loaded before proceeding with the execution of code that depends on Dojo components.
The addOnLoad method accepts a callback argument that is used to ‘call back’ when the following conditions are met:
- The DOM is loaded
- All Dojo modules are loaded (and their recursive dependencies)
- Run dojo.require for all necessary Dojo modules
- Create an init method to be called back when everything is loaded
- Pass this init method to dojo.addOnload to kick off the execution of the script when the page is loaded.
To get around the async loading that occurs when scripts are included dynamically we implemented a mechanism that is similar to the Dojo addOnLoad.
Here is a sample snippet that would appear in a web page to include our map widget:
Here is what we came up with:
Here is a quick breakdown of how this works:
Line 2: Set up the myMapApi namespace.
Line 5: This code is implemented entirely as an immediately executable anonymous function to avoid creating any variables within the scope of the page. You can see a description of this technique here.
Line 9-17: The djConfig object is the key to getting this technique to work. The default behavior of addOnLoad is to fire when all dependencies are loaded (including the page DOM). As a result, if the DOM is already loaded the addOnLoad event will not occur. In many cases with a widget (sometimes depending on the browser) the DOM may already be considered to be loaded and the addOnLoad will not fire. The afterAddOnLoad property allows this behavior to be ignored and addOnLoad will fire whenever Dojo dependencies are loaded.
Line 26-31: Dynamically load the tundra theme
Line 43-65: This class creates the div that will be used for the map, news up an esri.Map, and loads a map service into the div.
And that is basically it..
Here is the output from Firebug showing the loading sequence:
I have also posted a working example of this technique. This has been tested to work in IE 7, FireFox 3.x and Chrome 3.x. If you find that it works (or doesn’t work) please let me know. Suggestions or other ideas are also welcome!