Layer control (TOC): Hide or Show layers and/or group layers (ESRI ArcGIS JavaScript API)

Hacking some JavaScript TOC: Forum entry at forums.arcgis.com

The solution is: Ignore the group-layers in the updateLayerVisibility() method. Put only the array of the layers (the ones with data) in it.

The whole design of a TOC needs to reflect that. I've used now the "Dijit Tree with Multi State Checkboxes" from http://www.thejekels.com/. The Multi State Checkboxes are important because it brings this updateLayerVisibility() logic up to the interface. Something similar is done by Mansour Raad at http://thunderheadxpler.blogspot.com/2010/07/merging-table-of-content-and-legend.html but with additional legend information pictures. He also uses Multi-state Checkboxes.

However, if you use the Multi State Checkboxes, the whole group-layer logic behaves different than in ArcMap and that's mandatory. The group-layer doesn't have any information about what happens at the sublevel. It show only that something at the sublevel is checked but in fact you don't need the group-layer anymore for the request. If you click it, either all sublevels are checked or none. Otherwise if only some sublevels are checked, the grouplayer gets the "intermediate" state. So the group-layer is only for "design" not for real "functionality".

To fill my Multi-State Checkbox Tree I have to use an external configuration file, that translates the MapService REST-JSON to a hierachical JSON. With that hierachy it is easy to fill the DOJO-store, define the DOJO-model and to fill the Tree. A sample configuration file looks like this:

grouped.json:

{
identifier : 'name',
  label : 'name',
  items : [
      {
          name : 'World',
          type : 'grouplayer',
          id: 0,
          visible: true,
          children : [
              {name : 'World Country', type : 'layer', id: 1, visible: true},
              {name : 'World Timezone', type : 'layer', id: 2, visible: true}
          ]
      }
  ]
}

It contains the layer information from the REST-endpoint of the mapservice (http://localhost/ArcGIS/rest/service…Server?f=pjson) but moves the sublayers in the hierachy of the appropriate grouplayer. I have to put the following attributes to a layer: name, type (grouplayer or layer), id (for the ExportMap request) and visible (initially checked or not). The children list the sublayers, which recursively can be grouplayers.

Unfortunetaly this configuration file has to be written by hand, right now. But it should be possible to write a translator later. The current REST endpoint of a MapService cannot be used right now, because it lists the layers plain and the hierachy is only placed in the "parentLayerId" and "subLayerIds" attributes of a layer. (Assumed that the IDs of the layers are one after another (they are) it should be possible to parse the REST endpoint dynamically and to build the TOC directly with this plain structure and to get rid of the configuration file. But maybe you have to parse it two times to get the TOC. Remember the compilation of the table-of-contents in LaTeX? You had to do it two times. ).

Anyway. Here's the code for the store, model, tree, the fetch (query) after a click on a tree-branch, the fetchCompleted method and the HTML page.

Store:

store = new dojo.data.ItemFileWriteStore({
	url: "./datastore/grouped.json"
});

Model:

model = new tmpdir.CheckBoxStoreModel({
	store: store,
	query: {
		type: 'grouplayer'
	},
	rootLabel: 'Service',
	checkboxAll: true,
	checkboxRoot: false,
	checkboxState: true,
	checkboxStrict: true,
	checkboxIdent: "visible"
});

Tree:

var tree = new tmpdir.CheckBoxTree({
	model: model,
	id: "MenuTree"
},
"CheckboxTree");

Fetch:

store.fetch({
	query: {
		visible: true,
		type: "layer"
	},
	queryOptions: {
		deep: true
	},
	onBegin: fetchPrepare,
	onComplete: fetchCompleted,
	onError: fetchFailed
});

FetchCompleted:

function fetchCompleted(items, request) {
	visibleLayers = [];
	var i;
	for (i = 0; i < items.length; i++) {
		var item = items[i];
		visibleLayers.push(store.getValue(item, "id"));
	}
	mapServiceLayer.setVisibleLayers(visibleLayers);
}

HTML:

<div id="map" style="width: 600px; height: 400px; border: 1px solid #000;">
</div>
<div id="CheckboxTree">
</div>

Hope that helps for similar questions. Discussion and additional information is welcome! Please go to the forum link above.

Advertisements