Automatically close a widget when opening another one

4526
11
Jump to solution
11-30-2017 05:51 AM
HlynurIngólfsson
New Contributor III

Hello.

Making an app with widgets like search and basemapToggle in API 4x.

All my widgets are being minimized by using the "Exapand" widget, my problem is that i need to close a widget before I open another one, otherwise both widgets stay open and overlap each other (as seen on attached png):

So instead of this happening I would actually want one widget to close automatically when I open another one, in this case the search widget to automatically close when I open the basemapToggle one (and wise versa)

Does anyone have some good solutions for me regarding this?

1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

And here is a sample for what Rene is talking about:

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
  <title>Expand widget [beta] - 4.5</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
  <script src="https://js.arcgis.com/4.5/"></script>

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

  <script>
  var bgExpand, bgExpand2, expandHandle1, expandHandle2;
    require([
      "esri/Map",
      "esri/views/SceneView",
      "esri/widgets/Expand",
      "esri/widgets/BasemapGallery",
      "esri/widgets/Search",
      "esri/core/watchUtils",
      "dojo/domReady!"
    ], function(
      Map, SceneView, Expand, BasemapGallery, Search, watchUtils
    ) {

      var map = new Map({
        basemap: "satellite"
      });

      var view = new SceneView({
        container: "viewDiv",
        map: map
      });

      // Create a BasemapGallery widget instance and set
      // its container to a div element

      var basemapGallery = new BasemapGallery({
        view: view,
        container: document.createElement("div")
      });

      var searchWidget = new Search({
        view: view,
        container: document.createElement("div")
      });

      // Create an Expand instance and set the content
      // property to the DOM node of the basemap gallery widget
      // Use an Esri icon font to represent the content inside
      // of the Expand widget

      bgExpand = new Expand({
        view: view,
        content: basemapGallery.container,
        expandIconClass: "esri-icon-basemap"
      });

      bgExpand2 = new Expand({
        view: view,
        content: searchWidget.container,
        expandIconClass: "esri-icon-search"
      });

      expandHandle1 = watchUtils.pausable(bgExpand, "expanded", function(newValue, oldValue){
        if(newValue === true){
          expandHandle1.pause();
          setTimeout(function(){
            expandHandle2.resume();
          }, 100);
        }else{
          expandHandle1.resume();
        }
        if(bgExpand2.expanded){
          bgExpand2.collapse();
        }
      });

      expandHandle2 = watchUtils.pausable(bgExpand2, "expanded", function(newValue, oldValue){
        if(newValue === true){
          expandHandle2.pause();
          setTimeout(function(){
            expandHandle1.resume();
          }, 100);
        }else{
          expandHandle2.resume();
        }
        if(bgExpand.expanded){
          bgExpand.collapse();
        }
      });

      // Add the expand instance to the ui
      view.ui.add(bgExpand, "top-right");
      view.ui.add(bgExpand2, "top-right");


    });
  </script>
</head>

<body>
  <div id="viewDiv"></div>
</body>
</html>

View solution in original post

11 Replies
ReneRubalcava
Frequent Contributor

You could watch for the "expanded" property of each one, when one changes, change all the others.

This functionality is going to be coming to 4.6, which is coming soon!

RobertScheitlin__GISP
MVP Emeritus

And here is a sample for what Rene is talking about:

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
  <title>Expand widget [beta] - 4.5</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
  <script src="https://js.arcgis.com/4.5/"></script>

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

  <script>
  var bgExpand, bgExpand2, expandHandle1, expandHandle2;
    require([
      "esri/Map",
      "esri/views/SceneView",
      "esri/widgets/Expand",
      "esri/widgets/BasemapGallery",
      "esri/widgets/Search",
      "esri/core/watchUtils",
      "dojo/domReady!"
    ], function(
      Map, SceneView, Expand, BasemapGallery, Search, watchUtils
    ) {

      var map = new Map({
        basemap: "satellite"
      });

      var view = new SceneView({
        container: "viewDiv",
        map: map
      });

      // Create a BasemapGallery widget instance and set
      // its container to a div element

      var basemapGallery = new BasemapGallery({
        view: view,
        container: document.createElement("div")
      });

      var searchWidget = new Search({
        view: view,
        container: document.createElement("div")
      });

      // Create an Expand instance and set the content
      // property to the DOM node of the basemap gallery widget
      // Use an Esri icon font to represent the content inside
      // of the Expand widget

      bgExpand = new Expand({
        view: view,
        content: basemapGallery.container,
        expandIconClass: "esri-icon-basemap"
      });

      bgExpand2 = new Expand({
        view: view,
        content: searchWidget.container,
        expandIconClass: "esri-icon-search"
      });

      expandHandle1 = watchUtils.pausable(bgExpand, "expanded", function(newValue, oldValue){
        if(newValue === true){
          expandHandle1.pause();
          setTimeout(function(){
            expandHandle2.resume();
          }, 100);
        }else{
          expandHandle1.resume();
        }
        if(bgExpand2.expanded){
          bgExpand2.collapse();
        }
      });

      expandHandle2 = watchUtils.pausable(bgExpand2, "expanded", function(newValue, oldValue){
        if(newValue === true){
          expandHandle2.pause();
          setTimeout(function(){
            expandHandle1.resume();
          }, 100);
        }else{
          expandHandle2.resume();
        }
        if(bgExpand.expanded){
          bgExpand.collapse();
        }
      });

      // Add the expand instance to the ui
      view.ui.add(bgExpand, "top-right");
      view.ui.add(bgExpand2, "top-right");


    });
  </script>
</head>

<body>
  <div id="viewDiv"></div>
</body>
</html>
HlynurIngólfsson
New Contributor III

Hey and thanks for the answers, have made the altercations but the problem still persists, could you take a look at my setup?

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>Hlynur experiments</title>
    
  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
      
      #layerToggle1 {
        top: 13px;
        right: 13px;
        width: 165px;
        position: absolute;
        float: right;
        color: #86888A;
        text-align: left;
        font-family: "arial";
        font-size: 14px;
        padding: 5px 2px;
        background-color: white;
        outline-color: white;
        box-shadow: 1px 1px #bdbdbd;
      }
      
      #layerToggle2 {
        top: 37px;
        right: 13px;
        width: 165px;
        position: absolute;
        float: right;
        color: #86888A;
        text-align: left;
        font-family: "arial";
        font-size: 14px;
        padding: 5px 2px;
        background-color: white;
        outline-color: white;
        box-shadow: 1px 1px #bdbdbd;
      }
      
  </style>

  <link rel="stylesheet" href="https://js.arcgis.com/4.5/esri/css/main.css">
  <script src="https://js.arcgis.com/4.5/"></script>

  <script>
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/widgets/Home",
        "esri/widgets/Zoom",
        "esri/widgets/BasemapToggle",
        "esri/tasks/Locator",
        "esri/widgets/Search",
        "esri/widgets/Expand",
        "esri/layers/FeatureLayer",
        "esri/core/watchUtils",
        "dojo/dom",
        "dojo/on",
        "dojo/domReady!"
        
    ], function(
            Map, 
            MapView, 
            Home,
            Zoom,
            BasemapToggle,
            Locator,
            Search,
            Expand,
            FeatureLayer,
            watchUtils,
            dom,
            on,
        ) {

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

      var view = new MapView({
        container: "viewDiv",
        map: map,
        zoom: 9,
          
        extent: {
            xmin: -3730050,
            ymin: 6277314,
            xmax: 4468890,
            ymax: 12147678,
            spatialReference: 102100
        }
      });
      
      var homeWidget = new Home({
        view: view
      });
        
      var basemapToggle = new BasemapToggle({
          view: view,
          nextBasemap: "satellite",
          container: document.createElement("div")
      });
        
      var basemapToggleExpand = new Expand({
          view: view,
          content: basemapToggle.container,
          expandIconClass: "esri-icon-basemap",
      });
        
      var searchWidget = new Search({
          view:view,
            allPlaceholder: "Incident or address",
            container: document.createElement("div"),
            sources: [
              {
              locator: new Locator({ url: "//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer" }),
              singleLineFieldName: "SingleLine",
              name: "Adress search",
              localSearchOptions: {
              minScale: 300000,
              distance: 50000
              },
            maxResults: 3,
            maxSuggestions: 6,
            suggestionsEnabled: false,
            minSuggestCharacters: 0,
            resultGraphicEnabled: false
      },{
                featureLayer: new FeatureLayer({
                    url: "https://services1.arcgis.com/LpQVI6wAjYbHDKAK/arcgis/rest/services/Report_Service/FeatureServer/0",
                    popupTemplate: {
                        title: "{Incident_Type} </br> {Incident_Description}",
                        overwriteActions: true
                    }
                }),
                searchFields: ["Incident_Type"],
                displayField: "Incident_Description",
                exactMatch: false,
                outFields: ["Incident_Type", "Report_Date"],
                name: "Incident",
                placeholder: "huh?",
                zoomScale: 10000,
                resultGraphicEnabled: false
            }, {
              featureLayer: new FeatureLayer({
                url: "https://services1.arcgis.com/LpQVI6wAjYbHDKAK/arcgis/rest/services/Iceland_Test/FeatureServer/0",
                popupTemplate: {
                  title: "{Name}",
                  overwriteActions: true
                }
              }),
              searchFields: ["Name"],
              suggestionTemplate: "{Name}",
              exactMatch: false,
              outFields: ["Name"],
              name: "Basecamps",
              zoomScale: 5000,
              resultGraphicEnabled: false
            }],
            
            popupEnabled: false
        });
        
        var searchWidgetExpand = new Expand({
          view: view,
          content: searchWidget.container,
          expandIconClass: "esri-icon-search",
        });
        
        var reportLyr = new FeatureLayer({
          url: "https://services1.arcgis.com/LpQVI6wAjYbHDKAK/arcgis/rest/services/Report_Service/FeatureServer/0",
          id: "report",
          visible: false,
          
        popupTemplate: {
          title: "{Incident_Type}",
          content: [{
            type: "text",
            text: "Here something seriously interresting has taken place, stay tuned for more AMAZING adventures!!!"
          }]
        },  
          outFields: ["*"]
        });
        
        var reportLyrToggle = dom.byId("reportLyr");
        on(reportLyrToggle, "change", function() {
          reportLyr.visible = reportLyrToggle.checked;
        });
        
         var icelandLyr = new FeatureLayer({
          url: "https://services1.arcgis.com/LpQVI6wAjYbHDKAK/arcgis/rest/services/Iceland_Test/FeatureServer/0",
          id: "iceland",
          visible: false,
          
        popupTemplate: {
          title: "Basecamp",
          content: [{
            type: "text",
            Text: "Place: {Name} <br/> Region: {Region}"
          }, {
            type: "media",
            mediaInfos: [{
              title: "{Name}",
              type: "image",
              value: {
                sourceURL: "{PICTURE}"
              }
            }]
          }, {
            type: "attachments"
          }],
          actions: [{
            id: "see-more",
            className: "esri-icon-home",
            title: "Visit homepage"
          }]
        },  
          outFields: ["*"]
        });
        
        var icelandLyrToggle = dom.byId("icelandLyr");
        on(icelandLyrToggle, "change", function() {
          icelandLyr.visible = icelandLyrToggle.checked;
        });
        
        expandhandle1 = watchUtils.pausable(basemapToggleExpand, "expanded", function(newValue, oldValue){
          if(newValue === true){
            expandHandle1.pause();
            setTimeout(function(){
              expandHandle2.resume();
            }, 100);
          }else{
            expandHandle1.resume();
          }
          if(searchWidgetExpand.expanded){
            searchWidgetExpand.collapse();
          }
        });
        
        expandhandle2 = watchUtils.pausable(searchWidgetExpand, "expanded", function(newValue, oldValue){
          if(newValue === true){
            expandHandle2.pause();
            setTimeout(function(){
              expandHandle1.resume();
            }, 100);
          }else{
            expandHandle2.resume();
          }
          if(basemapToggleExpand.expanded){
            basemapToggleExpand.collapse();
          }
        });
    
    view.on("layerview-create", function(event) {if (event.layer.id === "report") {console.log("LayerView for reports created!", event.layerView)};
    });
    
    view.on("layerview-create", function(event) {if (event.layer.id === "iceland") {console.log("Layerview for Iceland created!", event.layerView)}
        });
  
    map.add(reportLyr);    
    map.add(icelandLyr);
    
    view.ui.add(homeWidget, {position: "top-left", index: 1});
    view.ui.add(searchWidgetExpand, {position: "top-left", index: 3});
    view.ui.add(basemapToggleExpand, {position: "top-left", index: 2});
    
    view.then(function () {
      var popup = view.popup;
      popup.viewModel.on("trigger-action", function(event) {
        if (event.action.id === "see-more") {
          var attributes = popup.viewModel.selectedFeature.attributes;
          var info = attributes.Link;
          if (info !== null) {
            window.open(info.trim());
          } else {
            window.open ("https://www.google.com/search?q=" +
                attributes.Name);
          }
        }
      });
    });
  
    });
      
  </script>
</head>

<body>
  <div id="viewDiv"></div>
    <span id="layerToggle1">
    <input type="checkbox" id="reportLyr">Hlynur has issues
  </span>
    <span id="layerToggle2">
      <input type="checkbox" id="icelandLyr">Hlynur has basecamps
    </span>
</body>
    
</html>
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Hlynur,

   JS is a case sensitive language and you had expandhandle1 instead of expandHandle1:

      expandHandle1 = watchUtils.pausable(basemapToggleExpand, "expanded", function(newValue, oldValue) {
        if (newValue === true) {
          expandHandle1.pause();
          setTimeout(function() {
            expandHandle2.resume();
          }, 100);
        } else {
          expandHandle1.resume();
        }
        if (searchWidgetExpand.expanded) {
          searchWidgetExpand.collapse();
        }
      });

      expandHandle2 = watchUtils.pausable(searchWidgetExpand, "expanded", function(newValue, oldValue) {
        if (newValue === true) {
          expandHandle2.pause();
          setTimeout(function() {
            expandHandle1.resume();
          }, 100);
        } else {
          expandHandle2.resume();
        }
        if (basemapToggleExpand.expanded) {
          basemapToggleExpand.collapse();
        }
      });
0 Kudos
HlynurIngólfsson
New Contributor III

Excellent, works like a dream! Thanks so much for the quick assistance.

One more thing as I have you on the line, in my searchWidget, do I have to reference the featureLayers being search as new FeatureLayer or can I somehow just reference their "id's" as they are also being added to the map itself?

0 Kudos
GregoryBologna
Occasional Contributor II

What is the purpose of the timer in your solution? Why not just check the newValue and expanded property?

        if (newValue === true) {
          if (layerListExpand.expanded) {
            layerListExpand.collapse();
          }
        }
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

To handle a race issue.

0 Kudos
ThomasColson
MVP Frequent Contributor
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Thomas,

   This thread is not about WAB it is a JS API 4.x question.

0 Kudos