query features on a layer inside a webmap returns null

2500
6
Jump to solution
01-22-2021 01:09 AM
litch
by
New Contributor III

I am trying to make a query-related-features sample on a webmap with a point layer.
after getting the layer I try to queryObjectIds, the webmap returns a popup on the point I click so I know the screenpoint should intersect but the query returns "null".

When I console the layer for type it returns "feature".
And just to check that it doesn't have any restrictions for querying I queried the service on its REST page and got results.
I also turned on the objectId field inside the webmap on the layer.

 

 

        //find layer in webmap
        var layer
        webmap.when(function () {
          ///console.log(webmap.layers)
          layer = webmap.allLayers.find(function (layer) {
            return layer.id === "mifalim_related_3837";
          });
          console.log(layer)
        });

 

 


I am getting the Layer straight from the webmap and not creating a new feature layer by url like in the sample. Am I wrong treating it as a feature layer without creating it in code?

I even tried changing my query to a 5 mile radius on the off chance that the query looks for an exact xy when intersecting with a point.

My code:

 

 

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>CodePen - testShip</title>


</head>

<body>
  <!-- partial:index.partial.html -->
  <html>

  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
    <!--
  ArcGIS API for JavaScript, https://js.arcgis.com
  For more information about the query-related-features sample, read the original sample description at developers.arcgis.com.
  https://developers.arcgis.com/javascript/latest/sample-code/query-related-features/index.html
  -->
    <title>
      Query Related Features | Sample | ArcGIS API for JavaScript 4.18
    </title>

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

      #gridDiv {
        padding: 10px;
        max-width: 300px;
      }

      #viewDiv {
        height: 100%;
        width: 100%;
      }

      #clearButton {
        margin-top: 5px;
        display: none;
      }

      .dgrid {
        height: auto !important;
      }

      .dgrid .dgrid-scroller {
        position: relative;
        max-height: 200px;
        overflow: auto;
      }
    </style>

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

    <script>
      require([
        "esri/WebMap",
        "esri/config",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
        "dgrid/Grid"
      ], function (WebMap, esriConfig, MapView, FeatureLayer, Legend, Expand, Grid) {
        // Create the webmap
        var webmap = new WebMap({
          portalItem: {
            // autocasts as new PortalItem()
            id: "8e9f4e8d2e644d989067843e794c86c5"
          },

        });
        //find layer in webmap
        var layer
        webmap.when(function () {
          ///console.log(webmap.layers)
          layer = webmap.allLayers.find(function (layer) {
            return layer.id === "mifalim_related_3837";
          });
          console.log(layer)
        });
        /********************
        * Set the WebMap instance to the map property in a MapView.
        ********************/
        var view = new MapView({
          map: webmap,
          container: "viewDiv"
        });

        const legend = new Legend({ view: view });
        // Expand widget to expand and contract the legend widget
        const legendExpand = new Expand({
          expandTooltip: "Show Legend",
          expanded: false,
          view: view,
          content: legend
        });

        // Add widgets to the view
        view.ui.add(document.getElementById("gridDiv"), "bottom-left");
        view.ui.add(legendExpand, "top-right");

        // Initialize variables
        let grid;

        // call clearMap method when clear is clicked
        const clearbutton = document.getElementById("clearButton");
        clearbutton.addEventListener("click", clearMap);


        webmap.load().then(function () {
          return (g = new Grid());
        });

        view.on("click", function (event) {
          clearMap();
          queryFeatures(event);
        });

        function queryFeatures(screenPoint) {
          const point = view.toMap(screenPoint);

          // Query the for the feature ids where the user clicked
          layer
            .queryObjectIds({
              geometry: point,
              spatialRelationship: "intersects",
              returnGeometry: false,
              outFields: ["*"]
            })

            .then(function (objectIds) {
              console.log(objectIds)
              if (!objectIds.length) {
                console.log('noIDs')
                return;
              }

              // Query the for the related features for the features ids found
              return layer.queryRelatedFeatures({
                outFields: ["site"],
                relationshipId: layer.relationships[0].id,
                objectIds: objectIds
              });
            })

            .then(function (relatedFeatureSetByObjectId) {
              if (!relatedFeatureSetByObjectId) {
                console.log("!relatedFeatureSetByObjectId")
                return;
              }
              // Create a grid with the data
              Object.keys(relatedFeatureSetByObjectId).forEach(function (
                objectId
              ) {
                // get the attributes of the FeatureSet
                const relatedFeatureSet = relatedFeatureSetByObjectId[objectId];
                const rows = relatedFeatureSet.features.map(function (feature) {
                  return feature.attributes;
                });

                if (!rows.length) {
                  console.log("!rows.length")
                  return;
                }

                // create a new div for the grid of related features
                // append to queryResults div inside of the gridDiv
                const gridDiv = document.createElement("div");
                const results = document.getElementById("queryResults");
                results.appendChild(gridDiv);

                // destroy current grid if exists
                if (grid) {
                  grid.destroy();
                }
                // create new grid to hold the results of the query
                grid = new Grid(
                  {
                    columns: Object.keys(rows[0]).map(function (fieldName) {
                      return {
                        label: fieldName,
                        field: fieldName,
                        sortable: true
                      };
                    })
                  },
                  gridDiv
                );

                // add the data to the grid
                grid.renderArray(rows);
              });
              clearbutton.style.display = "inline";
            })
            .catch(function (error) {
              console.error(error);
            });
        }

        function clearMap() {
          if (grid) {
            grid.destroy();
          }
          clearbutton.style.display = "none";
          console.log("clear")
        }
      });
    </script>
  </head>

  <body>
    <div id="gridDiv" class="esri-widget">
      <h2>US Cities</h2>
      <p>
        Click to view related table.
      </p>
      <div id="queryResults"></div>
      <button id="clearButton" class="esri-widget">Clear Query</button>
    </div>
    <div id="viewDiv"></div>
  </body>

  </html>
  <!-- partial -->

</body>

</html>

 

 

 

0 Kudos
1 Solution

Accepted Solutions
litch
by
New Contributor III

Yes, but the problem wasn't what I query but how,
The popup responds by graphic click so this is how I now get the OID without querying at all.

      view.on("click", function(evt) {
        // Search for graphics on click's position
        view.hitTest(evt.screenPoint)
          .then(function(response) {
            console.log(response.results)
        // isolate the correcet layer from graphics
            response.results.forEach(r => (console.log(r.graphic.layer.id)))
            var graphic = response.results.find(r => {
              return r.graphic.layer.id === "mifalim_related_3837";
            });
        console.log(graphic.attributes.OBJECTID);

 

View solution in original post

0 Kudos
6 Replies
ChristianBischof
Esri Contributor

I copied your code and tried to recreate the problem and seems like the layer is not even loading that's why your find Method returns null. I can only provide you with a development hint to put the variable view into the global scope of your JS code, which makes it available in the browser console for easier debugging.

What's important is that you should not forget to put the view variable out of the global scope again, once you ship your application in production mode.

0 Kudos
litch
by
New Contributor III

The layer is inside a closed network, but it does load.
The  webmap I load is a test webmap containing  the layer and the relationship table just like the sample.
Is there anything I should check inside of it?
5bb217ed-0104-4a74-8eb5-e363ef56113b.jpg

0 Kudos
ChristianBischof
Esri Contributor

You could try to use the direct findLayerById Method of the WebMap class. Link below.

WebMap | ArcGIS API for JavaScript 4.18

litch
by
New Contributor III

I redid the code with an online webmap that will work on codepen for you.

and I think i found the problem !

The intersect query doesn't care about the clicking on the point that opens the popup , adding 15km to this map returned an object-id and only if I was zoomed in enough.


Am i using the query function incorrectly?


Is there a way to get the id of the popup opened or symbology highlighted?
Can i listen to that event?


Also by global scope, do you  mean declare "var view" outside the require function? 

 

 

 

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1, maximum-scale=1,user-scalable=no"
    />
    <!--
  ArcGIS API for JavaScript, https://js.arcgis.com
  For more information about the query-related-features sample, read the original sample description at developers.arcgis.com.
  https://developers.arcgis.com/javascript/latest/sample-code/query-related-features/index.html
  -->
<title>
      Query Related Features | Sample | ArcGIS API for JavaScript 4.18
    </title>

    <style>
      html,
      body {
        height: 100%;
        width: 100%;
        margin: 0;
        padding: 0;
      }
      #gridDiv {
        padding: 10px;
        max-width: 300px;
      }
      #viewDiv {
        height: 100%;
        width: 100%;
      }
      #clearButton {
        margin-top: 5px;
        display: none;
      }
      .dgrid {
        height: auto !important;
      }
      .dgrid .dgrid-scroller {
        position: relative;
        max-height: 200px;
        overflow: auto;
      }
    </style>

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

    <script>
      require([
        "esri/WebMap",
        "esri/config",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend",
        "esri/widgets/Expand",
        "dgrid/Grid"
      ], function (WebMap,esriConfig, MapView, FeatureLayer, Legend, Expand, Grid) {
        // Create the layer

        var webmap = new WebMap({
          portalItem: {
            // autocasts as new PortalItem()
            id: "f2e9b762544945f390ca4ac3671cfa72"
          },
          
        });
        
var layer = "test"
 webmap.when(function() {
///console.log(webmap.layers)
 console.log("webmap ready")
 layer = webmap.findLayerById("Accidental_Deaths_8938")
 console.log(layer)       
})  
         /************************************************************
         * Set the WebMap instance to the map property in a MapView.
         ************************************************************/
        var view = new MapView({
          map: webmap,
          container: "viewDiv"
        });

        const legend = new Legend({ view: view });
        // Expand widget to expand and contract the legend widget
        const legendExpand = new Expand({
          expandTooltip: "Show Legend",
          expanded: false,
          view: view,
          content: legend
        });

        // Add widgets to the view
        view.ui.add(document.getElementById("gridDiv"), "bottom-left");
        view.ui.add(legendExpand, "top-right");

        // Initialize variables
        let highlight, grid;

        // call clearMap method when clear is clicked
        const clearbutton = document.getElementById("clearButton");
        clearbutton.addEventListener("click", clearMap);

        
        webmap.load().then(function () {
          return (g = new Grid());
        });

        view.on("click", function (event) {
          clearMap();
          queryFeatures(event);
        });

        function queryFeatures(screenPoint) {
          const point = view.toMap(screenPoint);
            console.log("queryFeatures")
                    
          layer
            .queryObjectIds({
              geometry: point,
              spatialRelationship: "intersects",
              distance : 15000,
              units : "meters",
              returnGeometry: false,
              outFields: ["*"]
            })
            .then(function (objectIds) {
            console.log(objectIds)            
              if (!objectIds.length) {
                return;
              }
           
              // Highlight the area returned from the first query
              view.whenLayerView(layer).then(function (layerView) {
                if (highlight) {
                  highlight.remove();
                }
                highlight = layerView.highlight(objectIds);
              });

              // Query the for the related features for the features ids found
              return layer.queryRelatedFeatures({
                outFields: ["site"],
                relationshipId: layer.relationships[0].id,
                objectIds: objectIds
              });
            })

            .then(function (relatedFeatureSetByObjectId) {
              if (!relatedFeatureSetByObjectId) {
                return;
              }
              // Create a grid with the data
              Object.keys(relatedFeatureSetByObjectId).forEach(function (
                objectId
              ) {
                // get the attributes of the FeatureSet
                const relatedFeatureSet = relatedFeatureSetByObjectId[objectId];
                const rows = relatedFeatureSet.features.map(function (feature) {
                  return feature.attributes;
                });

                if (!rows.length) {
                  return;
                }

                // create a new div for the grid of related features
                // append to queryResults div inside of the gridDiv
                const gridDiv = document.createElement("div");
                const results = document.getElementById("queryResults");
                results.appendChild(gridDiv);

                // destroy current grid if exists
                if (grid) {
                  grid.destroy();
                }
                // create new grid to hold the results of the query
                grid = new Grid(
                  {
                    columns: Object.keys(rows[0]).map(function (fieldName) {
                      return {
                        label: fieldName,
                        field: fieldName,
                        sortable: true
                      };
                    })
                  },
                  gridDiv
                );

                // add the data to the grid
                grid.renderArray(rows);
              });
              clearbutton.style.display = "inline";
            })
            .catch(function (error) {
              console.error(error);
            });
        }

        function clearMap() {
          if (highlight) {
            highlight.remove();
          }
          if (grid) {
            grid.destroy();
          }
          clearbutton.style.display = "none";
          console.log("clear")
        }
      });
    </script>
  </head>

  <body>
    <div id="gridDiv" class="esri-widget">
      <h2>US Cities</h2>
      <p>
        Click on a hexagon in the map to view the US cities located in that
        area.
      </p>
      <div id="queryResults"></div>
      <button id="clearButton" class="esri-widget">Clear Query</button>
    </div>
    <div id="viewDiv"></div>
  </body>
</html>

 

 

0 Kudos
ChristianBischof
Esri Contributor

Just a short answer to global scope, yes I mean outside of the require statement. Have you tried to use the queryFeatures Method instead of queryObjectIds? I assume at the end of the day you want the features to be displayed in the bottom left corner.

FeatureLayer | ArcGIS API for JavaScript 4.18

litch
by
New Contributor III

Yes, but the problem wasn't what I query but how,
The popup responds by graphic click so this is how I now get the OID without querying at all.

      view.on("click", function(evt) {
        // Search for graphics on click's position
        view.hitTest(evt.screenPoint)
          .then(function(response) {
            console.log(response.results)
        // isolate the correcet layer from graphics
            response.results.forEach(r => (console.log(r.graphic.layer.id)))
            var graphic = response.results.find(r => {
              return r.graphic.layer.id === "mifalim_related_3837";
            });
        console.log(graphic.attributes.OBJECTID);

 

0 Kudos