Adding Feature Layers to a Group Layer in a Layer List widget using javascript api.

2540
3
Jump to solution
05-25-2020 07:02 AM
by Anonymous User
Not applicable

Hi,  I wanted to know if there is a way of creating a group layer hierarchy for individual feature layers in a webmap and display them in a layer list widget for a web app created using ArcGIS Javascript API 4.15 .i.e. grouping individual feature layers into group layer.  Converting :-

-Layer1

-Layer 2

-Layer3

-Layer4

into

-GroupLayer1

  -Layer 1

  -Layer 2

-GroupLayer2

  -Layer3

  -Layer4

I did try using one of the code samples provided for creating group layers in the Javascript API reference, GroupLayer | ArcGIS API for JavaScript 4.15, Sample-GroupLayer with LayerList widget. https://codepen.io/pen?&editable=true&editors=100. Replaced the mapserver url with feature service urls and used a FeatureLayer constructor. However this fails with the following error in the browser console.  

Uncaught (in promise) TypeError: b.load is not a function
at Object.d._createLayerView (dojo.js:2027)
at Array.forEach (<anonymous>)
at Object.c.forEach (dojo.js:595)
at a.d._doWork [as callback] (dojo.js:2023)
at g (dojo.js:418)
at dojo.js:422

I have attached a .html file showing the code that I am using for this task. The same code works for MapImage Layers but fails when using Feature Service layers. 

1 Solution

Accepted Solutions
Egge-JanPollé1
MVP Regular Contributor

Hi Puthran Joshua‌,

Please see the sample below.

I did take a basic tutorial from Esri - Add layers to a map | ArcGIS API for JavaScript 4.15  - and extend this with a LayerList widget and a GroupLayer, just to prove that it is possible to add FeatureLayers to a GroupLayer.

From here you could extend the application further, with your own data of course.

Hope this helps.

BR,

Egge-Jan

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
  <title>ArcGIS JavaScript Tutorials: Add a GroupLayer to a LayerList widget</title>
  <link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/css/main.css">
  <script src="https://js.arcgis.com/4.15/"></script>
  <style>
    html, body, #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
  </style>
  <script>
    require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/FeatureLayer",
      "esri/layers/GroupLayer",
      "esri/widgets/LayerList"
    ], function(Map, MapView, FeatureLayer, GroupLayer, LayerList) {
      
      var map = new Map({
        basemap: "topo-vector"
      });

      var view = new MapView({
        container: "viewDiv",  
        map: map,
        center: [-118.80543,34.02700],
        zoom: 13            
      });

        // Trailheads feature layer (points)
      var trailheadsLayer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0"
      });

      // Trails feature layer (lines)
      var trailsLayer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0"
      });

      // Parks and open spaces (polygons)
      var parksLayer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0"
      });

      var layerList = new LayerList({
        view: view
      });
      // Adds widget below other elements in the top left corner of the view
      view.ui.add(layerList, {
        position: "top-left"
      });

      var myGroupLayer = new GroupLayer({
        title: "My GroupLayer",
        layers: [parksLayer, trailsLayer, trailheadsLayer]
      });

      map.add(myGroupLayer);


    });
  </script>
</head>
<body>
  <div id="viewDiv"></div>
</body>
</html> 

View solution in original post

3 Replies
Egge-JanPollé1
MVP Regular Contributor

Hi Puthran Joshua‌,

Please see the sample below.

I did take a basic tutorial from Esri - Add layers to a map | ArcGIS API for JavaScript 4.15  - and extend this with a LayerList widget and a GroupLayer, just to prove that it is possible to add FeatureLayers to a GroupLayer.

From here you could extend the application further, with your own data of course.

Hope this helps.

BR,

Egge-Jan

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
  <title>ArcGIS JavaScript Tutorials: Add a GroupLayer to a LayerList widget</title>
  <link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/css/main.css">
  <script src="https://js.arcgis.com/4.15/"></script>
  <style>
    html, body, #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
  </style>
  <script>
    require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/FeatureLayer",
      "esri/layers/GroupLayer",
      "esri/widgets/LayerList"
    ], function(Map, MapView, FeatureLayer, GroupLayer, LayerList) {
      
      var map = new Map({
        basemap: "topo-vector"
      });

      var view = new MapView({
        container: "viewDiv",  
        map: map,
        center: [-118.80543,34.02700],
        zoom: 13            
      });

        // Trailheads feature layer (points)
      var trailheadsLayer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads/FeatureServer/0"
      });

      // Trails feature layer (lines)
      var trailsLayer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails/FeatureServer/0"
      });

      // Parks and open spaces (polygons)
      var parksLayer = new FeatureLayer({
        url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space/FeatureServer/0"
      });

      var layerList = new LayerList({
        view: view
      });
      // Adds widget below other elements in the top left corner of the view
      view.ui.add(layerList, {
        position: "top-left"
      });

      var myGroupLayer = new GroupLayer({
        title: "My GroupLayer",
        layers: [parksLayer, trailsLayer, trailheadsLayer]
      });

      map.add(myGroupLayer);


    });
  </script>
</head>
<body>
  <div id="viewDiv"></div>
</body>
</html> 
by Anonymous User
Not applicable

Thanks Egge for taking the time to work on this. This worked perfectly. 

LoranHayden1
New Contributor II

I did this by hitting the mapserver's json endpoint then iterating through it's layers collection and using each layer's type (group or feature) determine how to process it. Using that you can build a couple functions to build an array of sublayers which you can then pass off to the layerlist. Note that you need to reverse the order of the elements in the hierarchy hence the use of unshift instead of push

e.g.

        $(function () {
            $.getJSON('ServiceDefinition.json', function (results) {
                const layers = results.layers;
                let sublayers = [];
                ///// need to keep track of removed layers
                let layerIndices = [];
                for (let i = 0; i < layers.length; i++) {
                    layerIndices.push(i);
                }
                /////
                for (let lyrIdx = 0; lyrIdx < layers.length; lyrIdx++) {
                    if (layerIndices.indexOf(lyrIdx) === -1) continue;
                    layerIndices = removeIndex(layerIndices, lyrIdx);
                    let layer = layers[lyrIdx];

                    if (layer.type === "Feature Layer") {
                        sublayers.unshift(getFeatureLayer(layer, layerIndices));
                    }
                    else {
                        let glyr = getGroupLayer(layer, layers, layerIndices);
                        if(glyr.sublayers.length > 0)
                            sublayers.unshift(glyr);
                    }
                    //layerIndices = removeIndex(layerIndices, lyrIdx);
                }
                $('#sublayers').html(JSON.stringify(sublayers));
            });
            function getGroupLayer(layer, layers, layerIndices) {
                let sublayer = {};
                sublayer.id = layer.id;
                sublayer.title = layer.name;
                sublayer.sublayers = [];
                for (let idx = 0; idx < layer.subLayerIds.length; idx++) {
                    let lyrId = layer.subLayerIds[idx];
                    if (layerIndices.indexOf(lyrId) === -1) continue;
                    layerIndices = removeIndex(layerIndices, idx);
                    let sublyr = layers[lyrId];
                    if (sublyr.type === "Feature Layer") {
                        sublayer.sublayers.unshift(getFeatureLayer(sublyr, layerIndices));
                    }
                    else {
                        let glyr = getGroupLayer(sublyr, layers, layerIndices);
                        if(glyr.sublayers.length > 0)
                            sublayer.sublayers.unshift(glyr);
                    }
                }
                return sublayer;
            }
            function getFeatureLayer(layer, layerIndices) {
                let sublayer = {};
                sublayer.id = layer.id;
                sublayer.title = layer.name;
                sublayer.definitionExpression = null;
                layerIndices = removeIndex(layerIndices, layer.id);
                return sublayer;
            }
            function removeIndex(indices, value) {
                
                let index = indices.indexOf(value);
                if (index > -1) {
                    indices.splice(index, 1);
                }
                return indices;
            }
        });

 

0 Kudos