Hey Jeff,
This may or may not be of assistance to you in general; I assume you won't stretch out the seams in putting on the coat. Your post caught I attention, it's Friday, and I feel like sharing; so let me expand on Matt's concept a little bit and talk about loading content and functionality using on demand loading with content panes or any widget which extends dijit/_Container. You can load html, including widgets, and javascript placed in a html file by using the href property of a content pane. By default a content pane only loads the href on first show. So content loaded into a accordion pane via a href, which isn't initially visible, isn't loaded until the user clicks on it. As far as executing javascript on load there are a couple options available with dijit.layout.ContentPane and dojox.layout.ContentPane, which can be found in dojo docs.
This is especially handy in an app with a lot of little tasks and tools with varying levels of usage. Some might get used a few times daily or maybe once a week. Below is the html for my "poor developer's widget" for measuring, which is html/measure.html relative to the application. Measure is initiated from a toolbar button. The floating pane and button are created in the init of the application with the floating pane's href property set to the html file. It only loads when the user first shows the floating pane by clicking the button. Because I have one global variable/object app, which I create everything in, it's easy to extend as needed. You'll notice that I call a lot of functions and use objects which already exist as part of the application, e.g. functions for controlling map click events. This is one reason I started getting away from true widgets for this sort of thing; either I was using globals directly or passing them as variables to the widget. It always ended up being more code than doing it this way.
It's also a great way to load custom mods and widgets on demand too using the on load abilities of the content pane.
[HTML]<div class="dojoxFloatingPaneWrapper">
<div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Loacation', showLabel: false, title: 'Location', iconClass: 'iconMeasurePnt', onClick: app.measure.location"></div>
<div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Distance', showLabel: false, title: 'Distance', iconClass: 'iconMeasureDist', onClick: app.measure.distance"></div>
<div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Area', showLabel: false, title: 'Area', iconClass: 'iconMeasureArea', onClick: app.measure.area"></div>
<div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'Clear', showLabel: false, title: 'Clear', iconClass: 'iconCross', onClick: app.measure.clear"></div>
<div id="measure-results" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="style: 'padding:6px 0 0'"></div>
</div>
<script>
app.measure = {
loaded: false,
load: function () {
app.measure.results = dijit.byId('measure-results');
app.map.addLayer(app.measure.layer = new esri.layers.GraphicsLayer(), 0);
app.measure.loaded = true;
},
location: function () {
if (!app.measure.loaded) {
app.measure.load();
};
app.measure.layer.clear();
app.utility.reset.start();
app.map.setMapCursor('crosshair');
app.map.toaster.setContent('Click on the map to return location.');
app.measure.results.destroyDescendants();
app.measure.results.set('content', 'Click on the map to return location.');
app.map.drawToolbar.activate('point');
var on = app.map.drawToolbar.on('draw-end', function (result) {
on.remove();
app.utility.reset.end();
app.map.drawToolbar.deactivate();
app.measure.layer.add(new esri.Graphic(result.geometry, new esri.symbol.SimpleMarkerSymbol('cross', 20, new esri.symbol.SimpleLineSymbol('solid', new dojo.Color([255, 0, 255]), 2), new dojo.Color([255, 0, 255, 1])), null, null));
var lat = result.geometry.getLatitude();
var lng = result.geometry.getLongitude();
var pp = new esri.tasks.ProjectParameters();
pp.geometries = [result.geometry];
pp.outSR = new esri.SpatialReference({
wkid: 26910
});
esri.config.defaults.geometryService.project(pp, function (results) {
app.measure.results.set('content', '<b>Latitude-Longitude</b><br />' + lat + '<br />' + lng + '<br />' + app.utility.dms.lat(lat) + '<br />' + app.utility.dms.lng(lng) + '<br /><b>UTM Zone 10N</b><br />N: ' + (Math.round(results[0].y * 1000) / 1000) + '<br />E: ' + (Math.round(results[0].x * 1000) / 1000));
}, function (error) {
console.log(error);
app.error('A geometry service projection error has occurred.');
app.measure.clear();
});
});
app.utility.reset.on.push(on);
},
distance: function () {
if (!app.measure.loaded) {
app.measure.load();
};
app.measure.layer.clear();
app.utility.reset.start();
app.map.setMapCursor('crosshair');
app.map.toaster.setContent('Click to add vertex; double-click to end and return distance.');
app.measure.results.destroyDescendants();
app.measure.results.set('content', 'Click to add vertex; double-click to end and return distance.');
app.map.drawToolbar.activate('polyline');
var on = app.map.drawToolbar.on('draw-end', function (result) {
on.remove();
app.utility.reset.end();
app.map.drawToolbar.deactivate();
app.measure.layer.add(new esri.Graphic(result.geometry, new esri.symbol.SimpleLineSymbol('solid', new dojo.Color([255, 0, 255]), 2), null, null));
var length = esri.geometry.geodesicLengths([esri.geometry.webMercatorToGeographic(result.geometry)], esri.Units.FEET);
app.measure.results.set('content', '<b>Length</b><br />' + (Math.round(length[0] * 100) / 100) + ' feet<br />' + (Math.round((length[0] / 5280) * 100) / 100) + ' miles');
});
app.utility.reset.on.push(on);
},
area: function () {
if (!app.measure.loaded) {
app.measure.load();
};
app.measure.layer.clear();
app.utility.reset.start();
app.map.setMapCursor('crosshair');
app.map.toaster.setContent('Click to add vertex; double-click to end and return area.');
app.measure.results.destroyDescendants();
app.measure.results.set('content', 'Click to add vertex; double-click to end and return area.');
app.map.drawToolbar.activate('polygon');
var on = app.map.drawToolbar.on('draw-end', function (result) {
on.remove();
app.utility.reset.end();
app.map.drawToolbar.deactivate();
app.measure.layer.add(new esri.Graphic(result.geometry, new esri.symbol.SimpleLineSymbol('solid', new dojo.Color([255, 0, 255]), 2), null, null));
var area = esri.geometry.geodesicAreas([esri.geometry.webMercatorToGeographic(result.geometry)], esri.Units.SQUARE_FEET);
app.measure.results.set('content', '<b>Area</b><br />' + (Math.round(area[0] * 100) / 100) + ' sq. feet<br />' + (Math.round((area[0] / 43560) * 100) / 100) + ' acres');
});
app.utility.reset.on.push(on);
},
clear: function () {
app.utility.reset.all();
if (app.measure.layer) {
app.measure.layer.clear()
}
if (app.measure.loaded) {
app.measure.results.destroyDescendants();
}
}
};
</script>[/HTML]
I checked out your app. You might be able to improve load time and performance by loading some of your functionalities on demand.
I'm not sure how all this will play out with AMD. I'm preparing for full conversion, which with 6k lines of code just to load the app, it's a bit nerve racking. No reason to keep putting off the inevitable. 🙂
Have a great weekend!
Ben