Collapsible Layer List

2346
13
Jump to solution
11-14-2018 08:08 AM
jaykapalczynski
Frequent Contributor

Looking for any examples of a collapsible layer list that Auto fills with my layers.

I have seen some really basic layer list examples on the api page but nothing that allows collapsible areas and auto filling of your layers.

I am trying to create 3 different areas as seen below.  Were the box next to the ------------- would collapse that section.

But I want it to auto fill the layers from my .js page.

Right now I am adding layers to the list and adding check boxes BUT THERE it is not collapsible 

legendLayers.push({ layer: FloodZonelayer, title: 'Flood Zones' });


 // ADD CHECK BOXES FOR LAYERS
 map.on('layers-add-result', function () {
 //add check boxes
 arrayUtils.forEach(legendLayers, function (layer) {
 var layerName = layer.title;
 var checkBox = new CheckBox({
 name: "checkBox" + layer.layer.id,
 value: layer.layer.id,
 checked: layer.layer.visible
 });
 checkBox.on("change", function () {
 var targetLayer = map.getLayer(this.value);
 targetLayer.setVisibility(!targetLayer.visible);
 this.checked = targetLayer.visible;
 });
 //add the check box and label to the toc
 domConstruct.place(checkBox.domNode, dom.byId("toggle"), "after");
 var checkLabel = domConstruct.create('label', {
 'for': checkBox.name,
 innerHTML: layerName
 }, checkBox.domNode, "after");
 domConstruct.place("<br />", checkLabel, "after");
 });
});

 //ADD THE LEGEND AND XY COORDINATES
 map.on("layers-add-result", function (evt) {

 // CYCLE through and grab all the layer names to add to the LEGEND PLUS
 // Remove layers not inteneted for the legend.
 var layerInfo = arrayUtils.map(evt.layers, function (layer, index) {
 if (layer.layer.id === "PastLocations" || layer.layer.id === "District" || layer.layer.id === "weatherlayer") { return { }; } //Hides Layers in the Legend
 else { return { layer: layer.layer, title: layer.layer.name }; } //Else return All others
 });
 // CYCLE through and grab all the layer names to add to the LEGEND
 if (layerInfo.length > 0) {
 var legendDijit = new Legend({
 map: map,
 layerInfos: layerInfo,
 }, "legend");
 legendDijit.startup();
 legendDijit.refresh();
 }

 });
0 Kudos
1 Solution

Accepted Solutions
jaykapalczynski
Frequent Contributor

I know this is not the way to do this although I don know of any other way to accomplish what I am looking for...

This is how I put on a large band-aid

  1. I still have to clean up the CSS to hide the clumsiness of this approach...especially with nesting the accordion panes..
  2. I still have to clean up my code so don't be too judgmental I repeated the code to build the legend layers in each of the accordion panes.
  3. I can put if then statements in this section to decrease the amount of code - map.on('layers-add-result', function () {

This gives you something like this in your panel... I have a container for Weather, Incidents, Other Layers.

If I do a little CSS work I can get ride of the frames and color backgrounds and make this look a little more appealing.

The example below does not have all the layers in the image.  In my below example it would simply put one feature layer in each of the 3 accordions

Follow the "legendLayers1.push" below from each FeatureLayer to the function below it.

legendLayers1.push({ layer: WeatherImpactWashout, title: 'WeatherImpact Washout' });

legendLayers2.push({ layer: WeatherImpactWashout, title: 'WeatherImpact Washout' });

legendLayers2.push({ layer: WeatherImpactWashout, title: 'WeatherImpact Washout' });

<div id="IDAccordionPaneLayers" data-dojo-type="dijit.layout.AccordionContainer" style="color:black; height:90%; width:90%;">                    
     <div id="idLayers2" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title:'Weather'" >
         <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="title:'Natural Disasters'">
          <div id="toggle2" style="padding: 2px 2px; color:Black;"></div>
         </div>
     </div>          
     <div id="idLayers3" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title:'Incidents & Traffic'" >
         <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="title:'Natural Disasters'">
          <div id="toggle3" style="padding: 2px 2px; color:Black;"></div>
         </div>
     </div>     
     <div id="idLayers1" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="title:'Layers1'" >
         <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="title:'Natural Disasters'">
          <div id="toggle1" style="padding: 2px 2px; color:Black;"></div>
         </div>
     </div>                    
</div>
var WeatherImpactPowerLines = new FeatureLayer("https://arcgis.vdem.virginia.gov/ArcGIS/rest/services/Traffic/VATraffic_WeatherImpactPoints/MapServe...", {
     mode: FeatureLayer.MODE_ONDEMAND,
     visible: false,
     outFields:["*"],
     infoTemplate: infoWeatherImpact
});
legendLayers1.push({ layer: WeatherImpactPowerLines, title: 'WeatherImpact Power Lines' });

var WeatherImpactOther = new FeatureLayer("https://arcgis.vdem.virginia.gov/ArcGIS/rest/services/Traffic/VATraffic_WeatherImpactPoints/MapServe...", {
     mode: FeatureLayer.MODE_ONDEMAND,
     visible: false,
     outFields:["*"],
     infoTemplate: infoWeatherImpact
});
legendLayers2.push({ layer: WeatherImpactOther, title: 'WeatherImpact Other' });
          
var WeatherImpactPassable = new FeatureLayer("https://arcgis.vdem.virginia.gov/ArcGIS/rest/services/Traffic/VATraffic_WeatherImpactPoints/MapServe...", {
     mode: FeatureLayer.MODE_ONDEMAND,
     visible: false,
     outFields:["*"],
     infoTemplate: infoWeatherImpact
});
legendLayers3.push({ layer: WeatherImpactPassable, title: 'WeatherImpact Passable' });




// ADD CHECK BOXES FOR LAYERS
map.on('layers-add-result', function () {
     //add check boxes
     arrayUtils.forEach(legendLayers1, function (layer) {
          var layerName = layer.title;
          var checkBox = new CheckBox({
               name: "checkBox" + layer.layer.id,
               value: layer.layer.id,
               checked: layer.layer.visible
          });
          checkBox.on("change", function () {
                var targetLayer = map.getLayer(this.value);
               targetLayer.setVisibility(!targetLayer.visible);
               this.checked = targetLayer.visible;
          });
          //add the check box and label to the toc
          //domConstruct.place(checkBox.domNode, dom.byId("toggle"), "after");
          domConstruct.place(checkBox.domNode, dom.byId("toggle1"), "after");
                  var checkLabel = domConstruct.create('label', {
                   'for': checkBox.name,
                   innerHTML: layerName
               }, checkBox.domNode, "after");
               domConstruct.place("<br />", checkLabel, "after");
     });
     arrayUtils.forEach(legendLayers2, function (layer) {
          var layerName = layer.title;
          var checkBox = new CheckBox({
               name: "checkBox" + layer.layer.id,
               value: layer.layer.id,
               checked: layer.layer.visible
          });
          checkBox.on("change", function () {
                var targetLayer = map.getLayer(this.value);
               targetLayer.setVisibility(!targetLayer.visible);
               this.checked = targetLayer.visible;
          });
          //add the check box and label to the toc
          //domConstruct.place(checkBox.domNode, dom.byId("toggle"), "after");
          domConstruct.place(checkBox.domNode, dom.byId("toggle1"), "after");
                  var checkLabel = domConstruct.create('label', {
                   'for': checkBox.name,
                   innerHTML: layerName
               }, checkBox.domNode, "after");
               domConstruct.place("<br />", checkLabel, "after");
     });               
     arrayUtils.forEach(legendLayers3, function (layer) {
          var layerName = layer.title;
          var checkBox = new CheckBox({
               name: "checkBox" + layer.layer.id,
               value: layer.layer.id,
               checked: layer.layer.visible
          });
          checkBox.on("change", function () {
                var targetLayer = map.getLayer(this.value);
               targetLayer.setVisibility(!targetLayer.visible);
               this.checked = targetLayer.visible;
          });
          //add the check box and label to the toc
          //domConstruct.place(checkBox.domNode, dom.byId("toggle"), "after");
          domConstruct.place(checkBox.domNode, dom.byId("toggle1"), "after");
                  var checkLabel = domConstruct.create('label', {
                   'for': checkBox.name,
                   innerHTML: layerName
               }, checkBox.domNode, "after");
               domConstruct.place("<br />", checkLabel, "after");
     });     
               
});     

          
//ADD THE LEGEND AND XY COORDINATES 
map.on("layers-add-result", function (evt) {

// CYCLE through and grab all the layer names to add to the LEGEND PLUS 
// Remove layers not inteneted for the legend.
     var layerInfo = arrayUtils.map(evt.layers, function (layer, index) {
          if (layer.layer.id === "PastLocations" || layer.layer.id === "District" || layer.layer.id === "weatherlayer") { return { }; } //Hides Layers in the Legend 
                else { return { layer: layer.layer, title: layer.layer.name }; } //Else return All others
     }); 
// CYCLE through and grab all the layer names to add to the LEGEND
     if (layerInfo.length > 0) {
          var legendDijit = new Legend({
          map: map,
          layerInfos: layerInfo,
          }, "legend");
          legendDijit.startup(); 
             legendDijit.refresh(); 
          }
});


map.addLayers([
WeatherImpactPassable,WeatherImpactOther,WeatherImpactPowerLines
]);‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

View solution in original post

13 Replies
jaykapalczynski
Frequent Contributor

I saw this example but its using a web map  I have my layers all defined individually in my js page

But this is the functionality I am after....but I am not using a web map

ArcGIS API for JavaScript Sandbox 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Here is that sample using coded layers like you are wanting:

<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
  <title>Layer List Dijit</title>
  <link rel="stylesheet" href="http://js.arcgis.com/3.25/dijit/themes/claro/claro.css">
  <link rel="stylesheet" href="http://js.arcgis.com/3.25/esri/css/esri.css">

  <style>
    html,
    body,
    .container,
    #map {
      height: 100%;
      width: 100%;
      margin: 0;
      padding: 0;
      margin: 0;
      font-family: "Open Sans";
    }

    #map {
      padding: 0;
    }

    #layerListPane {
      width: 25%;
    }

    .esriLayer {
      background-color: #fff;
    }

    .esriLayerList .esriList {
      border-top: none;
    }

    .esriLayerList .esriTitle {
      background-color: #fff;
      border-bottom: none;
    }

    .esriLayerList .esriList ul {
      background-color: #fff;
    }

  </style>
  <script>
    var dojoConfig = {
      parseOnLoad: true
    };
  </script>
  <script src="http://js.arcgis.com/3.25/"></script>
  <script>
    require([
    "esri/map",
    "esri/layers/ArcGISDynamicMapServiceLayer",
    "esri/dijit/LayerList",
    "dojo/query",
    "dojo/dom-construct",
    "dojo/dom-class",
    "dojo/dom-style",
    "dojo/on",
    "dojo/_base/array",
    "dijit/layout/BorderContainer",
    "dijit/layout/ContentPane",
    "dojo/domReady!"
], function (
      Map,
      ArcGISDynamicMapServiceLayer,
      LayerList,
      query,
      domConstruct,
      domClass,
      domStyle,
      on,
      array
    ) {
      var map = new Map("map", {
        basemap: "topo",
        center: [-123, 47],
        zoom: 8,
        sliderStyle: "small"
      });

      var atlasLayer = new ArcGISDynamicMapServiceLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer", {
        "id": "atlasLayer",
        "showAttribution": false
      });

      var recreationLayer = new ArcGISDynamicMapServiceLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Recreation/MapServer", {
        "id": "recreationLayer",
        "showAttribution": false
      });

      var waterNetLayer = new ArcGISDynamicMapServiceLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Water_Network/MapServer", {
        "id": "waterNetworkLayer",
        "showAttribution": false
      })

      map.addLayers([atlasLayer, recreationLayer, waterNetLayer]);

      var llWidget = new LayerList({
         map: map,
         layers: [{
           layer: atlasLayer,
            id: "Atlas layers",
            subLayers: true
         },{
           layer: recreationLayer,
            id: "Recreation Layer",
            subLayers: true
         },{
           layer: waterNetLayer,
            id: "Water Network Layer",
            subLayers: true
         }],
         showLegend: true,
         showOpacitySlider: true
      },"layerList");
      llWidget.startup();

    });
  </script>
</head>

<body class="claro">
  <div class="container" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline',gutters:false">
    <div id="layerListPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'right'">
      <div id="layerList"></div>
    </div>
    <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"></div>
  </div>
</body>

</html>
0 Kudos
jaykapalczynski
Frequent Contributor

So from what I am seeing there are 3 map services each with an array of layers in them. 

This reads through each service and creates the list allowing them to collapse?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Correct

0 Kudos
jaykapalczynski
Frequent Contributor

Thinking.....I have infotemplates as well to control what I see.  On a few of them I am doing more than simply reading from the Service for symbology etc.

Can I handle this with this code example?

          // ADDRESS POINTS
           var simpleJson = {
               "type": "simple",
               "label": "",
               "description": "",
               "symbol": {
                 "color": [255,255,51],
                 "size": 6,
                 "angle": 0,
                 "xoffset": 0,
                 "yoffset": 0,
                 "type": "esriSMS",
                 "style": "esriSMSCircle",
                 "outline": {
                    "color": [255,0,0],
                    "width": 1,
                    "type": "esriSLS",
                    "style": "esriSLSSolid"
                 }
               }
            }
          var infoTemplateAddressPoints = new InfoTemplate();
               infoTemplateAddressPoints.setTitle("Address Point Information");
               infoTemplateAddressPoints.setContent("<table>" +
               "<tr><td id='tblTitle'>Address Pts</td><td id='tblTitle2'></td></tr>" +
               "<tr><td id='tblTitleLine'></td><td id='tblTitleLine2'></td></tr>" +
               "<tr><td></td><td></td></tr>" +
               "<tr><td id='tblMainline1'>Address</td><td id='tblSubline2'>${FULLADDR}</td></tr>" +
               "<tr><td id='tblMainline1'>Municipality</td><td id='tblSubline2'>${MUNICIPALITY}</td></tr>" +
               "<tr><td id='tblMainline1'>PO Name</td><td id='tblSubline2'>${PO_NAME}</td></tr>" +
               "<tr><td id='tblMainline1'>Zip Code</td><td id='tblSubline2'>${ZIP_5}</td></tr>" +     
               "</table><hr>");       
          var AddressPointEndPoint = "https://xxxxxx/arcgis/rest/services/VA_Base_layers/VA_Address_Points/MapServer/0";
          var AddressPoints = new FeatureLayer(AddressPointEndPoint, {
            id: "AddressPoint",
            minScale: 50000,
            visible: true,
            opacity: .7,
            outFields: ["*"],
            infoTemplate: infoTemplateAddressPoints
          });
          // Push layer to the legend
          legendLayers.push({ layer: AddressPoints, title: 'Address Points' });
          var rend = new SimpleRenderer(simpleJson);
          AddressPoints.setRenderer(rend)
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Jay,

  Sure what I provided was just an example. All you really need of the code I provided is this portion:

      var llWidget = new LayerList({
         map: map,
         layers: [{
           layer: atlasLayer,
            id: "Atlas layers",
            subLayers: true
         },{
           layer: recreationLayer,
            id: "Recreation Layer",
            subLayers: true
         },{
           layer: waterNetLayer,
            id: "Water Network Layer",
            subLayers: true
         }],
         showLegend: true,
         showOpacitySlider: true
      },"layerList");
      llWidget.startup();

You just change the layer property for your actual layer vars.

0 Kudos
jaykapalczynski
Frequent Contributor

Say I wanted the Recreation in the atlasLayer  Can I do this?

var llWidget = new LayerList({
map: map,
layers: [{
layer: atlasLayer,recreationLayer,
id: "Atlas layers",
subLayers: true
},
{
layer: recreationLayer,
id: "Recreation Layer",
subLayers: true
},{
layer: waterNetLayer,
id: "Water Network Layer",
subLayers: true
}],
showLegend: true,
showOpacitySlider: true
},"layerList");
llWidget.startup();

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

No. One layer per layer property.

0 Kudos
jaykapalczynski
Frequent Contributor

So if I have 20 individual layers from multiple sources, with InfoTemplates.....

I want 3 categories...using your example...trying to figure out how I get like 10 in the first, 5 in the second and 5 in the third....  Each category will have layers from multiple sources....some external and some internal

Say I had this.  How do I get both of these in onto the atlasLayer

// WMA LINE 
var WMAFL = new FeatureLayer("https://xxxx/arcgis/rest/services/Projects/AVL/MapServer/4", {
     mode: FeatureLayer.MODE_SNAPSHOT,
     visible: true
});
          

// WMA FEATURES POINT
var WMAFPt = new FeatureLayer("https://xxxx/arcgis/rest/services/Projects/Locations/MapServer/2", {
     mode: FeatureLayer.MODE_SNAPSHOT,
     visible: true
});

var llWidget = new LayerList({
map: map,
layers: [{
layer: atlasLayer,  // I WANT BOTH LAYERS IN THIS CATEGORY
id: "Atlas layers",
subLayers: true
},
{
layer: recreationLayer,
id: "Recreation Layer",
subLayers: true
},{
layer: waterNetLayer,
id: "Water Network Layer",
subLayers: true
}],
showLegend: true,
showOpacitySlider: true
},"layerList");
llWidget.startup();‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos