ArcGIS API for JS 4.15: queryTask within collapsable div

988
2
Jump to solution
10-30-2020 07:13 AM
KayceeFaunce
New Contributor III

Today in trying to learn JavaScript: I've created a div element inside of the expand widget. The div element holds a drop-down list and a search button. The search button activates a query task.

The query function works when the div is outside of the expand widget (ie, if I add the div and associated html straight to the view), but not inside of it. Currently, trying to query the featurelayer results in the error: "Cannot read property 'value' of null."

I'm not sure how to correctly point the queryTask to the div inside var node. I've tried a few different approaches involved with changing the "document" call in places like "document.getElementById", but nothing has worked so far.

Complete code below:

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"/>

    <title>Project viewer</title>

    <style>
      
      html,
      body,
      #mainViewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        overflow: hidden;
      }
      
      p {
        color: black;
        font-family: "Noto Sans", sans-serif;
        line-height: 2;
        margin: 0;
        padding: 0;
      }
      
      #results {
        padding-top: 5px;
      }
      
      #optionsDiv {
        background-color: white;
        color: white;
        padding: 10px;
        width: 100%;
        -webkit-box-shadow: 3px 2px 15px -2px rgba(0,0,0,0.67);
        -moz-box-shadow: 3px 2px 15px -2px rgba(0,0,0,0.67);
        box-shadow: 3px 2px 15px -2px rgba(0,0,0,0.67);
        opacity: 0.90;
      }
      
       .myPanel {
      }
      
      #drop-downs {
        padding-bottom: 15px;
      }
      
      #printResults {
        font-family: "Noto Sans", sans-serif;
        font-style: italic;
        font-size: 12px;
        color: black;
      }
      
      #doBtn {
        box-shadow: inset 0px 0px 0px 0px #9fb4f2;
        background-color: #1a1b1f;
        border: 0px solid #4e6096;
        display: inline-block;
        cursor: pointer;
        color: #ffffff;
        padding: 6px 12px;
        text-decoration: none;
        border: 0px;
        outline: none;
        transition: all 0.3s ease 0s;
      }
      #doBtn:hover {
        background-color: #494b51;
        outline: none;
      }
      #doBtn:active {
        position: relative;
        top: 1px;
        border: 0px;
        outline: none;
      }
      
     .widget {
       border-radius:4px;
       border:1px solid #AAAAAA;
     }

    </style>

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

    <script>
       require([
        "esri/Map",
        "esri/views/MapView",
        "dojo/dom-construct",
        "dojo/dom-class",
        "esri/core/watchUtils",
        "esri/Basemap",
        "esri/widgets/LayerList",
        "esri/layers/FeatureLayer",
        "esri/PopupTemplate",
        "esri/layers/GraphicsLayer",
        "esri/tasks/QueryTask",
        "esri/tasks/support/Query",
        "esri/widgets/Expand",
        "dojo/domReady!",
        "dojo/dom",
        "dojo/on"
        ], function(
          Map,
          MapView,
          domConstruct,
          domClass,
          watchUtils,
          Basemap,
          LayerList,
          FeatureLayer,
          PopupTemplate,
          GraphicsLayer,
          QueryTask,
          Query,
          Expand,
          dom,
          on
        ){
         
        var basinUrl =   "https://services.arcgis.com/v01gqwM5QqNysAAi/arcgis/rest/services/Chesapeake_Bay_major_watersheds_feature/FeatureServer/0";  
         
        //* Define the popup content for each result
        var popupTemplate = {
          title: "{MajBas}",
          content:
            "Test text"
        };
    
        // Layer - project footprints
       const basinLayer = new FeatureLayer({
        url: basinUrl,
        outFields: ["*"],
        visible: true,
        popupTemplate: popupTemplate,
        title: "Basins"
        });
         
        // Layer - dark nav basemap 
       const basemap = Basemap.fromId("streets-night-vector");
         
       //** Point querytask to project boundary URL
        var qTask = new QueryTask({
          url: basinUrl
        });
         
       //** Set the query parameters to always return geometry and all fields.
       //** Returning geometry allows us to display results on the map/view
        var params = new Query({
          returnGeometry: true,
          outFields: ["*"]
        });
         
       //* GraphicsLayer for displaying results
       var resultsLayer = new GraphicsLayer({
        listMode: "hide" 
       });
       
       var map = new Map({
           basemap : basemap,
          layers: [basinLayer, resultsLayer]
       });

        var mainView = new MapView({
          container: "mainViewDiv",
          map: map,
          popup: {
            highlightEnabled: true,
            dockEnabled: true,
            dockOptions: {
              breakpoint: false,
              position: "top-right"
            }
          },
          center: [-75.325395, 40.306275],
          zoom: 5
        });
         
        // * create query div
        var node = domConstruct.create("div", {
         idName: "myPanel",
         innerHTML: "<div id=\"optionsDiv\"><div id=\"drop-downs\"><p><b>Basin</b></p><select id=\"valSelect\" class=\"widget\"><option value=\"Susquehanna River Basin\">Susquehanna River Basin</option><option value=\"Potomac River Basin\">Potomac River Basin</option><option value=\"James River Basin\">James River Basin</option></select></div><div align=\"center\"><button id=\"doBtn\">Search</button></div><div align=\"center\"><p id=\"results\"><span id=\"printResults\"></span></p></div></div></div>"  
        });   
         
        // * create collapsable query panel
        var widgetPanel = new Expand({
          view: mainView,
          expanded: true,
          expandTooltip: "Search basins",
          content: node
         });
         
       //* add expand widget containing widgetPanel
        mainView.ui.add([widgetPanel], "bottom-left");

        // for drop down
        var basinTypeSelect = document.getElementById("valSelect");
         
        // call doQuery() each time the button is clicked
        mainView.when(function () {
          mainView.ui.add(widgetPanel, "bottom-left");
          document.getElementById("doBtn").addEventListener("click", doQuery);
        });

        // relate to drop-down menu select field ID
        var attributeName = document.getElementById("MajBas");
         
        // executes each time the button is clicked
        function doQuery() {
          // Clear the results from a previous query
          resultsLayer.removeAll();
          // Build new query
          params.where =
            "MajBas LIKE" + "'" + basinTypeSelect.value + "'";

          // executes query and calls getResults() once promise is resolved
          // promiseRejected() is called if the promise is rejected
          qTask.execute(params).then(getResults).catch(promiseRejected);
        }

        // called each time the promise is resolved
        function getResults(response) {
          // loop through each results and assign a symbol and PopupTemplate
          var basinResults = response.features.map(function (feature) {
            // Sets the symbol of each resulting feature
            feature.symbol = {
              type: "simple-fill", 
              color: [212, 161, 87, 0.25],
              outline: {  // autocasts as new SimpleLineSymbol()
                color: [128, 128, 128, 0.5],
                width: "0.5px"
               }
            };    
            
            feature.popupTemplate = popupTemplate;
            return feature;
          });

          resultsLayer.addMany(basinResults);
          
          // animate to the results after they are added to the map
          mainView
            .goTo(basinResults)
            .then(function () {
              mainView.popup.open({
                features: basinResults,
                featureMenuOpen: true,
                updateLocationEnabled: true
              });
            })
            .catch(function (error) {
              if (error.name != "AbortError") {
                console.error(error);
              }
            });

          // print the number of results returned to the user
          document.getElementById("printResults").innerHTML =
            basinResults.length + " result(s) found";
        }

        // Called each time the promise is rejected
        function promiseRejected(error) {
          console.error("Promise rejected: ", error.message);
          }
         
       });
       
    </script>
  </head>

  <body>
    <div id="mainViewDiv"></div>
    
  </body>
</html>
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Kaycee,

  The issue was that the basinTypeSelect was null inside the doQuery function. Here is the fix.

        // for drop down
        var basinTypeSelect;
         
        // call doQuery() each time the button is clicked
        mainView.when(function () {
          mainView.ui.add(widgetPanel, "bottom-left");
          document.getElementById("doBtn").addEventListener("click", doQuery);
//Wait for the view to be ready and then the valSelect will be ready too.
          basinTypeSelect = document.getElementById("valSelect")
        });

        // relate to drop-down menu select field ID
        var attributeName = document.getElementById("MajBas");
         
        // executes each time the button is clicked
        function doQuery() {
          // Clear the results from a previous query
          resultsLayer.removeAll();
          // Build new query
          params.where =
            "MajBas LIKE" + "'" + basinTypeSelect.value + "'";

          // executes query and calls getResults() once promise is resolved
          // promiseRejected() is called if the promise is rejected
          qTask.execute(params).then(getResults).catch(promiseRejected);
        }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

View solution in original post

2 Replies
RobertScheitlin__GISP
MVP Emeritus

Kaycee,

  The issue was that the basinTypeSelect was null inside the doQuery function. Here is the fix.

        // for drop down
        var basinTypeSelect;
         
        // call doQuery() each time the button is clicked
        mainView.when(function () {
          mainView.ui.add(widgetPanel, "bottom-left");
          document.getElementById("doBtn").addEventListener("click", doQuery);
//Wait for the view to be ready and then the valSelect will be ready too.
          basinTypeSelect = document.getElementById("valSelect")
        });

        // relate to drop-down menu select field ID
        var attributeName = document.getElementById("MajBas");
         
        // executes each time the button is clicked
        function doQuery() {
          // Clear the results from a previous query
          resultsLayer.removeAll();
          // Build new query
          params.where =
            "MajBas LIKE" + "'" + basinTypeSelect.value + "'";

          // executes query and calls getResults() once promise is resolved
          // promiseRejected() is called if the promise is rejected
          qTask.execute(params).then(getResults).catch(promiseRejected);
        }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
KayceeFaunce
New Contributor III

Thank you, Robert! You're awesome. I appreciate you taking the time to pinpoint the issue.

0 Kudos