Layer control (TOC): Hide or Show layers and/or group layers

15272
21
09-02-2010 06:40 AM
AxelSchaefer
New Contributor II
Hi.

I don't know how to handle my layer control with the right JS API statements to the REST API.

I've got a very simple mapservice (called grouped) with a group layer and two sublayers:

World (0) (Grouplayer)
`-> World Country (1) (Layer)
`-> World Timezone (2) (Layer)


The JS-API Samples with the layer control makes use of the  ArcGISDynamicMapServiceLayer.setVisibleLayers() method to define the visible layers. The parameters for that method are the IDs of the layer.

That doesn't work for group-layers, like this layer "World" with the ID 0. If I write this command in the JS API:

layer.setVisibleLayers([0]);


I see all layers, even the unchecked layers 1 and 2. What happens, is that the REST interface gets an ExportMap request like this, when I only check the group layer 0 to active:

http://machine/ArcGIS/rest/services/grouped/MapServer/export?layers=show:0&...


The result is that all layers are shown: World Country and World Timezone, although they are not in the list of the visible layers!

The logic of checking and unchecking grouplayers works, if I use the HIDE method in the REST API. Hiding layer 0 (the grouplayer) returns an empty map. All combinations work with the HIDE option.

Question: How can I use the HIDE logic with the JS API? Where is the ArcGISDynamicMapServiceLayer.setHiddenLayers() method? 😉 How can I make a layerlist control with grouplayers?

Can I set the esri.layers.ImageParameters() at runtime after initialization? The ImageParameters have the layerOptions LAYER_OPTION_HIDE. But they are read out and used at initialization.

How can I achive the logic with the grouplayers?

Thanks in advance,
Axel
0 Kudos
21 Replies
AxelSchaefer
New Contributor II
edit: my reply was not a solution. Topic still open.
0 Kudos
AxelSchaefer
New Contributor II
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/services/grouped/MapServer?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;
  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!

Axel
0 Kudos
SusanMcclendon
New Contributor III
Axel,

I'm trying to get group layers to work in a TOC and have tried to implement your suggestions.  I'm fairly new to dojo, but did manage to get the multistate checkboxes example to work from the jeckels and can create my layer list successfully.

What I can't seem to wrap my head around is how to hook the onCheckboxChange function to the fetchcomplete to update my layer visibility in the map.  Nor do I fully understand where to include your store.fetch method?

If you have a complete working example using the javascript API, could you share?

Thanks,

Susan
AxelSchaefer
New Contributor II
You can see an example here: http://mohadiax.de/gis/JS_TreeClient_ArcGIS/.

See the source-code of the page to know you to do it.
0 Kudos
AxelSchaefer
New Contributor II
I've provided a sample in the Resource Center.

http://www.arcgis.com/home/item.html?id=98d9e760d6d1496487ca583b0e8ce73c

Best regards,
Axel
0 Kudos
SusanMcclendon
New Contributor III
Thanks Axxl~!  I did finally get it working, but your example helps me greatly.  I'm now working on trying to integrate the legend into the functionality of the TOC using the JSON file for the swath.

Susan
0 Kudos
AndrewBrown1
Occasional Contributor II
Axel,

Thank you for your excellent TOC example!

But I have one question: How should I deal with the FeatureLayers? If I create a couple featurelayers to select/query against, how would I control their visibility?

Currently, the featurelayer is always turned on, yet the TOC control doesn't control it as it is separate. Even though that layer is turned off in the TOC, it is still visible because that layer is also a featurelayer.

Any advise regarding the handling of the featurelayers? Should I keep the visibility turned off?

I apologize for my ignorance; i'm still fairly new at this.

Thanks,
Andrew
0 Kudos
AxelSchaefer
New Contributor II
But I have one question: How should I deal with the FeatureLayers? If I create a couple featurelayers to select/query against, how would I control their visibility?


Thanks for your comment, Andrew. I guess you have to deal FeatureLayers in a special way. The feature layers don't has to show anything at startup, depending on your selection mode (MODE_ONDEMAND, MODE_SELECTION, MODE_SNAPSHOT). And since it's a 'subclass' of a layer you can 'switch it off' with "myfaeturelayer.hide();"

So in most cases it depends: if you select your features, how you select them (spatial or by attributes). You can show the results of your query in a table and use that for accessing your features. So you don't need it in a TOC as a layer.

My 2 cents. 😉


Best regards,
Axel
0 Kudos
AndrewBrown1
Occasional Contributor II
Hi Axel,

Thanks again for your input. You have really helped me thus far.

I understand why we wouldn't have to show the feature layer,  but I'm actually selecting features by using a freehand tool, so the layer needs to be turned on in order for the selection to work. I'm currently using MODE_ONDEMAND to perform the select.

So, my problem is when I turn off the layer in the TOC, the layer is still turned on the feature layer). How do I control the feature layer in the TOC? Is it possible? I know the layer in the TOC is part of the basemap, as I created it in the grouped.json file.

In total, I'll probably have around 6 or so feature layers, so this is an important part of my application. The user needs to have the ability to turn the feature layers on and off, and be able to select the feature layers if they are turned on.

Thanks again,
Andrew
0 Kudos