Working with the new Javascript API for ArcGIS Server 9.3, I am now writing quite a bit of javascript. If you try and write large amounts of javascript code (I would consider >200 lines as large enough) without using objects, soon enough you're going to have an unreadable nightmare in your hands.
In order for the code to be maintainable, I've realized I have to take advantage of dojo's object-orientation capabilities, and especially inheritance. This allows me to extend ESRI's default objects, compensate for missing behaviors, and add logic of my own. Luckily, in javascript the can't mark their objects sealed, or need to remember to mark methods as "virtual", so extending this API's objects is easier than doing so in the ADF.
For instance, suppose you want an ArcGISDynamicMapServiceLayer to tell you which layers are currently visible for it. Thing is, the API only exposes a setVisibleLayers method, but not a getVisibleLayers(). So let's try and add this, shall we?
1 //doron.common.js
2 dojo.require("esri.map");
3
4 dojo.declare("Doron.ExtendedDynamicMapServiceLayer", esri.layers.ArcGISDynamicMapServiceLayer, {
5 constructor: function () {
6 dojo.connect(this, "onLoad", function () {
7 this._currentVisibleLayers = this._getDefaultVisibleLayers();
8 });
9 },
10 setVisibleLayers: function(layers) {
11 this._currentVisibleLayers = layers;
12 //dojo's way of calling base method - so that default behavior is preserved
13 this.inherited(arguments);
14
15 },
16 getCurrentVisibleLayers: function() {
17 return this._currentVisibleLayers;
18 },
19 _getDefaultVisibleLayers: function () {
20 var defaultVisibleLayers = [];
21 for (var i=0; i < this.layerInfos.length; i++) {
22 if (this.layerInfos[i].defaultVisibility)
23 defaultVisibleLayers.push(this.layerInfos[i].id);
24 }
25 return defaultVisibleLayers;
26 }
27 });
I am using dojo.declare to declare my new class, which inherits from esri.layers.ArcGISDynamicMapServiceLayer. My constructor first saves the layers that are visible by default in a field (this can only be done once the layer is loaded, so I'm registering myself to that event). I also override setVisibleLayers(), so that when it is called, I remember to update that field as well. Now I can easily expose the getCurrentVisbleLayers() method.
This class is something you can put in a .js file and reference everywhere you want - it is a much better approach than putting all your scripts inside the .html/.aspx/.whatever file.
A page that would use it, might look like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Dynamically Create Map Service Layer List</title>
<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.1/js/dojo/dijit/themes/tundra/tundra.css">
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.1"></script>
<script type="text/javascript" src="doron.common.js"></script>
<script type="text/javascript">
dojo.require("esri.map");
function init() {
map = new esri.Map("map");
layer = new Doron.ExtendedDynamicMapServiceLayer("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer");
map.addLayer(layer);
}
function showVisibleLayers() {
alert( layer.getCurrentVisibleLayers().join(','));
}
dojo.addOnLoad(init);
</script>
</head>
<body>
<div id="map" class="tundra" style="width:600px; height:400px; border:1px solid #000;"></div>
<input type="button" onclick="showVisibleLayers()" value="Show Visible Layers" />
</body>
</html>
Here I just took one of ESRI's samples, and replaced their class with mine. I also added a button that shows the layers that are currently visible. The reference to "doron.common.js" allows me to use my own class that overrides the ESRI one.
Hope this was helpful. If you know of any more ways to make life with the Javascript API more comfortable, feel free to share.