Design Question - Feature Layer Queries on Client-Side?

2289
9
Jump to solution
03-16-2017 07:16 PM
DanielPascual
New Contributor II

I've been using a feature service URL off ArcGIS Online and have a Feature Layer based on that endpoint in my JSAPI 4.2 web application.

I see that anytime I update the definition expression or create a query object it makes a network call to the service.

I wanted to minimize server calls and work with the data on the client so I created a FeatureLayer based on graphics imported from a geojson file (based on one of the examples). Then I learned that query objects off a feature layer does not support where, out fields, etc. Per documentation, only the geometry, objectIDs, and spatialreference should be defined. Similar to using a FeatureLayerView.

I'd like to do things like filtering the features, running queries to produce popups, running statistic queries, etc. on the client, and prevent the server-side call. My question then is, does the API support client-side queries? Am I using the wrong layer, should I be using a GraphicsLayer or some other layer? Or do I need to write my own methods for doing the filtering/querying on client?

Much Thanks!

0 Kudos
1 Solution

Accepted Solutions
ThomasSolow
Occasional Contributor III

You're right, it looks like where is not supported for layerView.queryFeatures.

If you want to query for attributes, one option would be something like:

function queryByAttr(lv: layerView, key: string, value: any):Array<Graphic>{

   return layerView.featuresView.graphics.filter(graphic => graphic.attributes && graphic.attributes[key] === value).toArray();

}

There may be an easier way to do this, but that should work.  Use layerView.loadedGraphics (instead of featuresView.graphcis) for 3D.

View solution in original post

9 Replies
RobertScheitlin__GISP
MVP Emeritus

Daniel,


   Starting a 4.3 the onDemand mode was created. You should try 4.3

0 Kudos
DanielPascual
New Contributor II

What is onDemand? I tried searching the 4.3 JavaScript API reference and nothing comes up under "onDemand" or "demand". Also tried searching the FeatureLayer page for both terms, and nothing comes up.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Daniel,

  Sorry the onDemand is something that is happening under the hood of the JS API. In 3.x you could set the mode manually but in 4.x this is automatically decided for you based on the data. The more I think about it it has little to do with your question though, so disregard.

0 Kudos
ThomasSolow
Occasional Contributor III

The queryFeatures method might be what you're looking for: FeatureLayer | API Reference | ArcGIS API for JavaScript 4.3 

For client-side queries, you would call this on the layerView rather than on the layer itself.  To get ahold of the layerView, you can do something like: view.whenLayerView(layer).then(layerView => ...).  You could also search the view.layerViews collection for the item whose .layer property matches the layer you're looking for.

In general, you can think of the layerView as the visual representation of the layer in question.  Each layer, once added to the map, has a corresponding layerView on the view.

Last time I checked, layerView.queryFeatures is fairly limited in what kinds of spatial queries it supports.  I think it only supports extent geometries and the "intersects" spatial relationship.  You should be able to query by attributes though.

If you prefer to write your own spatial queries, you have some options.  To access a list of all graphics loaded inside a layerView on the client, you can look in: layerView.featuresView.graphics (2D) or layerView.loadedGraphics (3D).  These will be collections (Collection | API Reference | ArcGIS API for JavaScript 4.3) which are basically evented arrays (you can convert them to arrays with collection.toArray()).  To do the actual spatial queries, the geometryEngine has a lot of helpful methods: geometryEngine | API Reference | ArcGIS API for JavaScript 4.3.

As far as GraphicsLayer vs. FeatureLayer, I would consider using a GraphicsLayer if you want your layer to have features with different geometries and you're not concerned about persisting the layer on a back-end.

thejuskambi
Occasional Contributor III

Hello Thomas,

You have mentioned that "You should be able to query by attributes though", how can this be achieved when you cannot use the Query.where?

0 Kudos
ThomasSolow
Occasional Contributor III

You're right, it looks like where is not supported for layerView.queryFeatures.

If you want to query for attributes, one option would be something like:

function queryByAttr(lv: layerView, key: string, value: any):Array<Graphic>{

   return layerView.featuresView.graphics.filter(graphic => graphic.attributes && graphic.attributes[key] === value).toArray();

}

There may be an easier way to do this, but that should work.  Use layerView.loadedGraphics (instead of featuresView.graphcis) for 3D.

DanielPascual
New Contributor II

Thanks! This works! Got any insight on how to get this to filter symbols on the map? I tried setting the visible property of the graphic to false, but symbols still show on map. I suspect because the featureLayer is setup.

I need to jump on the Typescript wagon, but here's the JS version for the lazy who have to support IE 11 still. 

function queryByAttr(lyrView, key, value) {

   return lyrView.featuresView.graphics.filter(function (graphic) { return graphic.attributes && graphic.attributes[key] === value});

}

Thanks again!

0 Kudos
ThomasSolow
Occasional Contributor III

It looks like setting graphic.visible works in 3D but not in 2D (4.3).

For 2D, you should try deleting the graphic manually from the featuresView.graphics collection.  You can do this with  featuresView.graphics.remove(graphic) or  featuresView.graphics.removeMany([graphic1, graphic2,..]).

If you plan on re-adding these later, you'll have to store them somewhere and re-add them to the layerView graphics collection later (use collection.add and .addMany).

With this kind of functionality you're getting into GraphicsLayer-type stuff, so you might want to think about using a GraphicsLayer instead, as you initially mentioned.  I would say the main advantages of a FeatureLayer is that it has some built-in querying and has some nice methods to help you persist the layer on a back-end.  If you're not using these, then a GraphicsLayer may be better.

DanielPascual
New Contributor II

Thanks so much for being so helpful!

0 Kudos