queryFeatures() method return 0 features on initial call

1033
6
03-30-2022 09:24 AM
craragon77
New Contributor III

Hello all,

I'm encountering odd behavior from the queryFeatures method and I can't identify the cause. I'm using the queryFeatures method to highlight features in the featurelayer based on a user's input. However, the response is null only when the user calls the function after the page initializes. E.g. the page loads => user clicks to highlight something => queryFeature response is an empty feature array, but when they try again then the queryFeature method returns the feature in question in the response. There are no features during the first call, but features are successfully returned after each subsequent function call, and I can't figure out why this is happening. The query and the layer which are used in the function are identical each time the method is called. Removing the query argument that is getting passed in also doesn't change the behavior, and I can't identify anything in the react lifecycle which explains this behavior. I'm using react 17.0.1 and I'm using the @arcgis/core package version 4.18.1 for the arcGIS components. I have attached the method + promise handling below.

 

 

 

 

riverLayer.queryFeatures(riverQuery).then((res) => {
//if res + res.features has length, continue execution
          if(res && res.features.length){
            //name of highlight variable = highlightTest
            if(highlightTest){
              highlightTest.remove()
            }
//equate the highlightTest variable to the response feature's first index's object id
            highlightTest = riverLayer.highlight(res.features[0].attributes.objectid);
          }
        })

 

 

 

 

 Is there anything that can explain why this only fails to work on the first method call but not any method call after that? 

0 Kudos
6 Replies
ReneRubalcava
Frequent Contributor

Is the layer visible on the map? Sounds like the layer isn't loaded, but tough to tell by the snippet. You can do a check or preload when the app starts using layer.load() or check if it's loaded before that query

https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-FeatureLayer.html#loaded

0 Kudos
craragon77
New Contributor III

@ReneRubalcava  i'm getting a type error when I try to call riverLayer.load() in a console statement. Is that the right way to use this method? I'm still pretty new to arcGIS for Javascript 

0 Kudos
ReneRubalcava
Frequent Contributor

Sorry, I just realized, I think you're using the layerview for clientside queries. You need to wait for the layerview to finish updating. Check out this blog post

https://odoe.net/blog/when-are-layers-done

Since you're using a CSVLayer, you can query the layer directly as the data is already in memory, so there is no request to the service in this case.

 

 

0 Kudos
ReneRubalcava
Frequent Contributor

Sorry, not sure. If you can provide a simple repo, could take a look. Not enough info to really tell.

0 Kudos
craragon77
New Contributor III

@ReneRubalcava here is a larger snippet of the code that I'm working with 

function handleRivers(){
//projectsSvc.selectedProjects is from a service file; track's primary key
    let riverString = "ffi_id = '" + projectsSvc.selectedProjects + "'";
    let riverFilter = new FeatureFilter({
      where: riverString
    });
    let finalExtent = null;
    let riverExtent = null;
    let riverLayer = null;
    let riverQuery = null;
//theMapView = the state hook for the MapView.map
    if (!theMapView){
      return null;
    }
    let allLayersAndSublayers = theMapView.layerViews.flatten(function(item){
      return item.layerViews || item.sublayers;
    });

    if (riverString != "") {
      try {
        riverLayer = allLayersAndSublayers.find((layerView) => {
          return layerView.layer.title === config.riverName
        });
        riverLayer.filter = riverFilter;
        riverQuery = riverFilter.createQuery();
        riverQuery.returnGeometry = true;
        riverQuery.outSpatialReference = theMapView.spatialReference;
//function for the highlighting
        riverLayer.queryFeatures(riverQuery).then((res) => {
          if(res && res.features.length){
            if(highlightTest){
              highlightTest.remove()
            }
            console.log('res.features[0].attributes.objectid', res.features[0].attributes.objectid);
            highlightTest = riverLayer.highlight(res.features[0].attributes.objectid);
            console.log('highlightTest', highlightTest);
          }
        })

        riverLayer.layer.queryExtent(riverQuery).then((results) => {
          riverExtent = results.extent;
          if (riverExtent) {
            finalExtent = riverExtent.clone();
            finalExtent.union(riverExtent);
          }
          else {
            finalExtent = riverExtent;
          };

          if (theMapView){
            theMapView.goTo(finalExtent.expand(8));
          }
        });
        
      }
      catch (ex) {
        console.log("Error filtering rivers");
      }
    }
    else {
      try {
        riverLayer = allLayersAndSublayers.find((layerView) => {
          return layerView.layer.title === config.riverName
        });
        riverLayer.filter = null;
      }
      catch (ex) {
        console.log("Error filtering rivers");
      }
    }
  }

 

0 Kudos
ReneRubalcava
Frequent Contributor

Yeah, looks like you're using the LayerView. Here is a sample that does something similar.

https://developers.arcgis.com/javascript/latest/sample-code/sandbox/?sample=featurelayerview-query-d...

view.whenLayerView(layer).then(function (layerView) {
    watchUtils.whenFalseOnce(layerView, "updating", function (val) {
        // Query layer view statistics as the user clicks
        // or drags the pointer across the view.
        view.on(["click", "drag"], function (event) {
        // disables navigation by pointer drag
        event.stopPropagation();
        queryStatsOnDrag(layerView, event)
            .then(updateCharts)
            .catch(function (error) {
            if (error.name !== "AbortError") {
                console.error(error);
            }
            });
        });
    });
});

Notice how it uses the whenFalseOnce watchUtils helper to make sure the LayerView is done updating before it queries it.

That should help! 

0 Kudos