Select to view content in your preferred language

Multiple LayerLists in JS api 4.15

2350
5
Jump to solution
06-21-2020 04:49 PM
TamiaRudnicky
Occasional Contributor

I am developing a web app using JS api 4.15. The clients really want to have multiple layerlists where each contains a different category of data. I was excited to find the example in this thread Multiple LayerLists In Web App but while it works in 4.12, I can't figure out how to get it to work in 4.15.  Has anyone successfully adapted this code to work in 4.15 or can anyone help me with this?

0 Kudos
1 Solution

Accepted Solutions
TamiaRudnicky
Occasional Contributor

Thank you Christian for pointing me in the right direction! I have figured it out and am happy with the results. If anyone else is interested, swap the view.when function in the previous code sample with the function shown is this code snippet.

            var layerListUSA = new LayerList({
                view: view,
                container: "listDiv1"
            });

            var layerListCensus = new LayerList({
                view: view,
                container: "listDiv2"
            });
            
           view.when(function() {
                watchUtils.when(layerListUSA, 'operationalItems.length', function() {
                    var elementsUSA = document.getElementsByClassName('esri-layer-list__item esri-layer-list__item--has-children');
                    elementsUSA[0].style.display = "none";
                });

                watchUtils.when(layerListCensus, 'operationalItems.length', function() {
                    var elementsCensus = document.getElementsByClassName('esri-layer-list__item esri-layer-list__item--has-children');
                    elementsCensus[3].style.display = "none";
                });
            }); 

View solution in original post

5 Replies
ChristianBischof
Esri Contributor

The Layerlist has a Property called "operationalItems" which gives you access to the Layers displayed in the Layerlist. You can set the listMode property to "hide" and the Layer won't be shown in the Layerlist.

myfirstlayerList = new LayerList({
          view: view,
});

view.when(function () {
          /*  #################################################
                 OPTIONAL WIDGET SETTINGS
              var items includes all 4 layers which
                     could be visible on the Layer Widget.
                  Set the listMode property to:
              "show" - layer visible
                 "hide" - layer not visible
            ################################################# */
          var hiddenLayer = ["insert title of layer HERE", "optional second title"]; 
          var items = myfirstlayerList.operationalItems.items;
          for (var j = 0; j < items.length; j++) {
            if (hiddenLayer.indexOf(items[j].title) >= 0) {
              items[j].layer.listMode = "hide";
            }
          }

});

The idea is that the code iterates through the hiddenLayer List in which you can put any FeatureLayer you wish to hide and if the given Layer is inside of the operationalItems it will set the listMode of its layer to hide.

Layer | ArcGIS API for JavaScript 4.15 

TamiaRudnicky
Occasional Contributor

Hi Christian,

  Thank you for the suggestion. I have tried to play with the listMode before but it hides the layer in both LayerLists. Your method gave me a different approach but unfortunately it didn't work. In my test example below I want the USALayer to display in the layerlist on the left and the CensusLayer to show on the right.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
    <title>LayerList widgets testing - 4.15</title>

    <link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/themes/light/main.css" />

    <style>
        html,
        body,
        #viewDiv {
            padding: 0;
            margin: 0;
            height: 100%;
            width: 100%;
            overflow: hidden;
        }

        .divClass {
            width: 240px;
            border: 2px solid #00467F;
            background-color: white;
            border-radius: 10px;
        }

        #listDiv1 {
            position: absolute;
            top: 30px;
            left: 55px;
        }

        #listDiv2 {
            position: absolute;
            top: 30px;
            right: 40px;
        }
    </style>

    <script src="https://js.arcgis.com/4.15/"></script>

    <script>
        require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/GroupLayer",
        "esri/layers/MapImageLayer",
        "esri/widgets/LayerList"
        ], function(Map, MapView, GroupLayer, MapImageLayer, LayerList) {
        var USALayer = new MapImageLayer({
            url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer",
            title: "US Sample Data"
        });

        var censusLayer = new MapImageLayer({
            url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer",
            title: "US Sample Census",
            visible: false
        });

        var map = new Map({
            basemap: "dark-gray"
        });

        var view = new MapView({
            center: [-98.5795, 39.8282],
            zoom: 5,
            container: "viewDiv",
            map: map
        });
        
        map.addMany([USALayer, censusLayer]);

            var layerListUSA = new LayerList({
                view: view,
                container: "listDiv1"
            });

            var layerListCensus = new LayerList({
                view: view,
                container: "listDiv2"
            });

            view.when(function() {
                var hideInDiv1 = ["US Sample Census"];
                var hideInDiv2 = ["US Sample Data"];

                var itemsUSA = layerListUSA.operationalItems.items;
                for (var j = 0; j < itemsUSA.length; j++) {
                    if (hideInDiv1.indexOf(itemsUSA[j].title) >= 0) {
                        itemsUSA[j].layer.listMode = "hide";
                    }
                }

                var itemsCensus = layerListCensus.operationalItems.items;
                for (var j = 0; j < itemsCensus.length; j++) {
                    if (hideInDiv2.indexOf(itemsCensus[j].title) >= 0) {
                        itemsCensus[j].layer.listMode = "hide";
                    }
                    if (hideInDiv1.indexOf(itemsCensus[j].title) >= 0) {
                        itemsCensus[j].layer.listMode = "show";
                    }
                }
            });
        });
    </script>
</head>

<body>
    <div id="viewDiv"></div>
    <div id="listDiv1" class="divClass"></div>
    <div id="listDiv2" class="divClass"></div>
</body></html>
0 Kudos
ChristianBischof
Esri Contributor

Hi Tamia Rudnicky‌ I can't provide a ready to use solution right off the cuff right now, but another thing I'd suggest is to try it with "old school" DOM Manipulation - selecting the <li> elements of the layerlist by class and remove exactly those you don't wanna have to show up. Do this for every layerlist you have in your application.

var elements = document.getElementByClassName('classnameoflayerlistitem');
elements[indextoremove].parentNode.removeChild(elements[indextoremove]);
0 Kudos
TamiaRudnicky
Occasional Contributor

Thank you Christian for pointing me in the right direction! I have figured it out and am happy with the results. If anyone else is interested, swap the view.when function in the previous code sample with the function shown is this code snippet.

            var layerListUSA = new LayerList({
                view: view,
                container: "listDiv1"
            });

            var layerListCensus = new LayerList({
                view: view,
                container: "listDiv2"
            });
            
           view.when(function() {
                watchUtils.when(layerListUSA, 'operationalItems.length', function() {
                    var elementsUSA = document.getElementsByClassName('esri-layer-list__item esri-layer-list__item--has-children');
                    elementsUSA[0].style.display = "none";
                });

                watchUtils.when(layerListCensus, 'operationalItems.length', function() {
                    var elementsCensus = document.getElementsByClassName('esri-layer-list__item esri-layer-list__item--has-children');
                    elementsCensus[3].style.display = "none";
                });
            }); 
MasonBindl
Emerging Contributor

Hi Tamia Rudnicky‌,

I'm trying to adapt your code for my use case.

I'm having trouble hiding layers in my second layer list. It seems i'm only able to manipulate the first layer list. 


What am I doing wrong?

Here is my code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>Tahoe Imagery Swipe</title>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.14/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.14/"></script>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
        .overlay {
            opacity:0;
            position:fixed;
            top:-999em;
            left:-999em;
            width:100%;
            height:100%;
            display:table;
            background:rgba(0,0,0,0.8);
            -webkit-animation: splash 20s forwards; 
            animation: splash 20s forwards;
        }

        .overlay-inner {
            display:table-cell;
            vertical-align:middle;
            text-align:center;
        }
        .title{
            align-content: center;
        }
        .message {
/*            border:1px solid #6e6e6e;*/
            border-radius: 4px;
            background: rgba(102,128,168, 0.6);
            display:inline-block;
            vertical-align:middle;
            width:50%;
            text-align:center;
            font-family: "Avenir Next W00";
            color: #f9f9f9;
            padding:10px;
        }

        .active {
            background: #6680a8;
            color: #4c4c4c;

        }

        .overlay-wrap {
            position:fixed;
            top:0;
            left:0;
            right:0;
            z-index:99;
        }

        .overlay-wrap .hide {
            position:absolute;
            top:-999em;
            right:20px;
/*            border:1px solid #6e6e6e;*/
            border-radius: 2px;
            background: rgba(102,128,168, 0.6);
            display:inline-block;
            text-align:middle;
            font-family: "Avenir Next W00";
            opacity:0;
            color:#f9f9f9;
            padding:2px;
            font-size:100%;
            z-index:2;
            cursor:pointer;
            -webkit-animation:15s fadein 2s forwards;
            -moz-animation:15s fadein 2s forwards;
            -ms-animation:15s fadein 2s forwards;
            animation:15s fadein 2s forwards;
        }

        #hide {
            position:absolute;
            left:-999em;
            top:-999em;
        }

        .overlay2{
            position:absolute;
            opacity:1;
            -webkit-transition:all 2s;
            -moz-transition:all 2s;
            -ms-transition:all 2s;
            transition:all 2s ;
        }

        #hide:checked ~ div,#hide:checked ~ div *, #hide:checked + label {
            opacity:0;
            left:-999em;
            right:auto;
            top:-999em;
            pointer-events:none;
        }

        @-webkit-keyframes splash {
            0%  {opacity: 0;top:0;left:0}
            20% {opacity:1;top:0;left:0}
            60% {opacity:1;top:0;left:0}
            99% {top:0;left:0}
            100% {opacity:0;top:-999em;left:-999em}
        }

        @-moz-keyframes splash {
            0%  {opacity: 0;top:0;left:0}
            20% {opacity:1;top:0;left:0}
            60% {opacity:1;top:0;left:0}
            99% {top:0;left:0}
            100% {opacity:0;top:-999em;left:-999em}
        }

        @-ms-keyframes splash {
            0% {opacity: 0;top:0;left:0}
            20% {opacity:1;top:0;left:0}
            60% {opacity:1;top:0;left:0}
            99% {top:0;left:0}
            100% {opacity:0;top:-999em;left:-999em}
        }

        @keyframes splash {
            0%  {opacity: 0;top:0;left:0}
            20% {opacity:1;top:0;left:0}
            60% {opacity:1;top:0;left:0}
            99% {top:0;left:0}
            100% {opacity:0;top:-999em;left:-999em}
        }

        @-webkit-keyframes fadein {
            0% {opacity: 0;top:10px;}
            20% {opacity:1;top:10px;}
            60%{opacity:1;top:10px}
            99% {top:10px}
            100%{opacity:0;top:-999em}
        }

        @-moz-keyframes fadein {
            0% {opacity: 0;top:10px;}
            20% {opacity:1;top:10px;}
            60%{opacity:1;top:10px}
            99% {top:10px}
            100%{opacity:0;top:-999em
        }

        @-ms-keyframes fadein {
            0% {opacity: 0;top:10px;}
            20% {opacity:1;top:10px;}
            60%{opacity:1;top:10px}
            99% {top:10px}
            100%{opacity:0;top:-999em
        }

        @keyframes fadein {
            0% {opacity: 0;top:10px;}
            20% {opacity:1;top:10px;}
            60%{opacity:1;top:10px}
            99% {top:10px}
            100%{opacity:0;top:-999em}
        }

    </style>

    <script>
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/TileLayer",
          "esri/layers/MapImageLayer",
        "esri/widgets/LayerList",
        "esri/widgets/Swipe",
        "esri/widgets/Expand",
        "dojo/query",
        "esri/core/watchUtils",
        "dojo/dom-style"
      ], function(Map, MapView, TileLayer, MapImageLayer, LayerList, Swipe, Expand,query, watchUtils, domStyle) {
        const map = new Map({
          basemap: "satellite"
        });

        const fortyLayer = new MapImageLayer({
          url: "https://maps.trpa.org/server/rest/services/1940_Imagery/MapServer",
          maxScale: 3000
        });
        map.add(fortyLayer);

        const sixtynineLayer = new MapImageLayer({
          url: "https://maps.trpa.org/server/rest/services/1969_Imagery/MapServer",
          maxScale: 3000
        });
        map.add(sixtynineLayer);
          
        const fifteenLayer = new MapImageLayer({
          url: "https://maps.trpa.org/server/rest/services/2015_Imagery/MapServer",
          maxScale: 3000
        });
        map.add(fifteenLayer);

//        const eighteenLayer = new TileLayer({
//          url: "https://maps.trpa.org/server/rest/services/2015_Imagery/MapServer",
//          maxScale: 3000
//        });
//        map.add(eighteenLayer);
       
        const view = new MapView({
          container: "viewDiv",
          map: map,
          center: [-120.01,38.93],
          zoom: 15,
          constraints: {
            maxZoom: 17,
            minZoom: 8
          }
        });
        
        var lList = new LayerList({
                view: view
            });
            
        view.when(function() {
                watchUtils.when(lList, 'operationalItems.length', function() {
                    var elementsLeftList = document.getElementsByClassName('esri-layer-list__item esri-layer-list__item--has-children');
                    elementsLeftList[0].style.display = "none";
                    console.log(elementsLeftList);
                });
            }); 
          
          
        view.ui.add(lList, "bottom-left");   
          
          
        var rList = new LayerList({
                view: view
            });   
        
          view.when(function() {
                watchUtils.when(rList, 'operationalItems.length', function() {
                    var elementsRightList = document.getElementsByClassName('esri-layer-list__item esri-layer-list__item--has-children');
                    elementsRightList[1].style.display = "none";
                    elementsRightList[2].style.display = "none";
                    console.log(elementsRightList);
                });
            });
         view.ui.add(rList, "bottom-right");
       
          
        // create a new Swipe widget
        const swipe = new Swipe({
          leadingLayers: [fortyLayer, sixtynineLayer],
          trailingLayers: [fifteenLayer],
          position: 50, // set position of widget to 35%
          view: view
        });
        // add swipe to view
        view.ui.add(swipe);     
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
      <div class="overlay-wrap">
		<input type="checkbox" name="hide" id="hide">
		<label class="hide" for="hide">X</label>
		  <div class="overlay2">
              <div class="overlay">
                <div class="overlay-inner">
                  <div class="message">
                      <p><h2>Historic Image Swipe</h2></p> 
                      <p>Use this map to <b>SWIPE</b> between the hisotric image layers. Toggle them off to view the most recent imagery underneath.</p>
                  </div>
                </div>
            </div>
        </div>
    </div>
  </body>
</html>
0 Kudos