I'm using JS API 4.6 and I'm trying to show in a table all graphics been displayed in the current extent directly querying the client/view.
You can find a live sample of the skeleton I'm using here or directly in here:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Query graphics on webmap</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.6/esri/css/main.css">
<script>
var dojoConfig = {
has: {
"esri-featurelayer-webgl": 1
}
};
</script>
<script src="https://js.arcgis.com/4.6/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 400px;
width: 100%;
}
</style>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/widgets/LayerList",
"esri/widgets/Legend",
"esri/geometry/geometryEngine",
"esri/core/watchUtils",
"esri/tasks/support/Query",
"dojo/domReady!"
],
function(
WebMap,
MapView,
LayerList,
Legend,
geometryEngine,
watchUtils,
Query
) {
webmap = new WebMap({
portalItem: {
id: "19d21df5e87f4f5a9aa5b8d678b174d6"
}
});
view = new MapView({
container: "viewDiv",
map: webmap,
popup: {
dockEnabled: true,
dockOptions: {
buttonEnabled: false,
breakpoint: {
width: 1000
},
position: "bottom-left"
}
},
});
view.when(function() {
var featureLayer = webmap.layers.getItemAt(0);
featureLayer.labelingInfo = [{
labelExpression: "[title]",
labelExpressionInfo: {
"expression": "$feature[\"title\"]"
},
labelPlacement: "always-horizontal",
symbol: {
type: "text",
color: [ 255,255,255,0.85 ],
font: {
size: 16,
weight: "bold",
family: "Arial Unicode MS"
},
haloColor: [255, 255, 255, 255],
haloSize: 0.75,
}
}];
var legend = new Legend({
view: view,
layerInfos: [{
layer: featureLayer,
title: "Actor type"
}]
});
view.ui.add(legend, "bottom-right");
});
view.when(function() {
var layerList = new LayerList({
view: view
});
view.ui.add(layerList, "top-right");
});
watchUtils.whenTrue(view, "stationary", function() {
if (view.extent) {
var info = `the view extent changed: \n
xmin = ${view.extent.xmin.toFixed(2)} xmax = ${view.extent.xmax.toFixed(2)} \n
ymin = ${view.extent.ymin.toFixed(2)} ymax = ${view.extent.ymax.toFixed(2)}`;
console.log(info);
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div>
<p>Visible graphics:</p>
<!-- TODO: Display visible graphics-->
</div>
</body>
</html>
I have been trying different things:
1) Using queryGraphics as I found at the GraphicsLayerView | API Reference | ArcGIS API for JavaScript 4.6
l = view.allLayerViews.getItemAt(1);
l.queryGraphics().then(function(results){
console.log("results=",results);
});
But the "then" promise was not resolved, maybe because I didn't added in the right place.
2) So I tried using queryFeatures, similar al Robert Scheitlin, GISP suggested in Capture attribute values from a WebMap without click event directly on the console:
view.allLayerViews.getItemAt(1).queryFeatures(query).always(function(results){
console.info(results);
});
But this time I used "always" and I got an:
{
name: "FeatureLayerView2D",
message: "Not ready to execute query",
details: undefined
}
3) I didn't know what "Not ready to execute query" means so I keep trying this time using the view event layerview-create as Ken Buja mentioned atCannot access items array property of MapView.allLayerViews (ArcJS API 4.4) :
view.on("layerview-create", function(event) {
var query = new Query();
query.where = '1=1';
query.outSpatialReference = view.spatialReference;
query.outFields = ["*"];
console.log("event.layer.title=",event.layer.title)
event.layerView.queryFeatures(query).always(function(results){
console.info(results);
});
});
But I got the same error.
4) Next time I tried a different way, using layerView.featuresView.graphics as Thomas Solow mentioned at Design Question - Feature Layer Queries on Client-Side?
l = view.allLayerViews.getItemAt(1);
l.layer.title // return "Startups"
l.featuresView.numFeatures // return 374
l.featuresView.graphics // return undefined
And I don't understand why graphics are undefined this time... ^_^. I also tried using queryFeatures on l.featuresView but the method didn't exist.
5) Desperately I also tried using the Accessor:
l = view.allLayerViews.getItemAt(1)
l.watch("updating", function (newValue, oldValue, propertyName, target) {
target.queryFeatures().then(function (results) {
console.log("results", results);
})
console.log("graphics=", target.featuresView.graphics")
});
But nothing ;(
I have spent several hours reading, trying different things and searching in the answered questions, but I'm running out of ideas. Please, could you help me solve this problem? I guess it should be quite easy to do but I'm not able to make it work.
Thanks in advance.
Solved! Go to Solution.
Raul,
Here is your code updated to work best:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Query graphics on webmap</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.7/esri/css/main.css">
<script>
var dojoConfig = {
has: {
"esri-featurelayer-webgl": 1
}
};
</script>
<script src="https://js.arcgis.com/4.7/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 400px;
width: 100%;
}
</style>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/widgets/LayerList",
"esri/widgets/Legend",
"esri/geometry/geometryEngine",
"esri/core/watchUtils",
"esri/tasks/support/Query",
"dojo/domReady!"
],
function(
WebMap,
MapView,
LayerList,
Legend,
geometryEngine,
watchUtils,
Query
) {
webmap = new WebMap({
portalItem: {
id: "19d21df5e87f4f5a9aa5b8d678b174d6"
}
});
view = new MapView({
container: "viewDiv",
map: webmap,
popup: {
dockEnabled: true,
dockOptions: {
buttonEnabled: false,
breakpoint: {
width: 1000
},
position: "bottom-left"
}
}
});
function graphicsInView(lyrView) {
var query = new Query();
query.geometry = view.extent;
query.spatialRelationship = "intersects";
lyrView.queryFeatures(query).then(function(results){
console.log(`Graphics found: ${results.length}`);
});
}
view.when(function() {
var featureLayer = webmap.layers.getItemAt(0);
view.whenLayerView(featureLayer).then(function(lyrView){
watchUtils.whenFalseOnce(lyrView, "updating", function() {
graphicsInView(lyrView);
});
watchUtils.whenTrue(view, "stationary", function() {
graphicsInView(lyrView);
});
});
featureLayer.labelingInfo = [{
labelExpression: "[title]",
labelExpressionInfo: {
"expression": "$feature[\"title\"]"
},
labelPlacement: "always-horizontal",
symbol: {
type: "text",
color: [ 255,255,255,0.85 ],
font: {
size: 16,
weight: "bold",
family: "Arial Unicode MS"
},
haloColor: [255, 255, 255, 255],
haloSize: 0.75,
}
}];
var legend = new Legend({
view: view,
layerInfos: [{
layer: featureLayer,
title: "Actor type"
}]
});
//view.ui.add(legend, "bottom-right");
var layerList = new LayerList({
view: view
});
//view.ui.add(layerList, "top-right");
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div>
<p>Visible graphics:</p>
<!-- TODO: Display visible graphics-->
</div>
</body>
You need to wait for LayerView updating to be false, I think even in the case of the GraphicsLayerView.
Check this sample.
Raul,
EDIT: this seems to be an issue in 4.6 when using the webGL script portion. If you remove that the this sample and your code will working in 4.6. It has been fix in 4.7 though.
It looks like 4.6 is real buggy when doing the client-side query. I agree with Rene you need to wait for the featureLayerView to not be updating but even then in 4.6 there are errors. Here is a sample using 4.7 that works fine but if you switch it to 4.6 you see you get the not ready to execute error.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Query graphics on webmap</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.7/esri/css/main.css">
<script>
var dojoConfig = {
has: {
"esri-featurelayer-webgl": 1
}
};
</script>
<script src="https://js.arcgis.com/4.7/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 500px;
width: 100%;
}
</style>
<script>
var featLyrView;
require([
"esri/WebMap",
"esri/views/MapView",
"esri/widgets/LayerList",
"esri/widgets/Legend",
"esri/geometry/geometryEngine",
"esri/core/watchUtils",
"esri/tasks/support/Query",
"dojo/domReady!"
],
function(
WebMap,
MapView,
LayerList,
Legend,
geometryEngine,
watchUtils,
Query
) {
webmap = new WebMap({
portalItem: {
id: "19d21df5e87f4f5a9aa5b8d678b174d6"
}
});
view = new MapView({
container: "viewDiv",
map: webmap,
popup: {
dockEnabled: true,
dockOptions: {
buttonEnabled: false,
breakpoint: {
width: 1000
},
position: "bottom-left"
}
},
});
view.when(function() {
var featureLayer = webmap.layers.getItemAt(0);
var query = new Query();
query.geometry = view.extent;
query.spatialRelationship = "intersects";
view.whenLayerView(featureLayer).then(function(lyrView){
featLyrView = lyrView
lyrView.watch("updating", function (val) {
if (!val){
lyrView.queryFeatures(query).then(function(results){
console.log(results); // prints the array of client-side graphics to the console
});
}
});
});
featureLayer.labelingInfo = [{
labelExpression: "[title]",
labelExpressionInfo: {
"expression": "$feature[\"title\"]"
},
labelPlacement: "always-horizontal",
symbol: {
type: "text",
color: [255, 255, 255, 0.85],
font: {
size: 16,
weight: "bold",
family: "Arial Unicode MS"
},
haloColor: [255, 255, 255, 255],
haloSize: 0.75,
}
}];
var legend = new Legend({
view: view,
layerInfos: [{
layer: featureLayer,
title: "Actor type"
}]
});
view.ui.add(legend, "bottom-right");
});
view.when(function() {
var layerList = new LayerList({
view: view
});
view.ui.add(layerList, "top-right");
});
watchUtils.whenTrue(view, "stationary", function() {
if(featLyrView){
featLyrView.queryFeatureCount().then(function (results) {
console.log("results", results);
}).otherwise(function(error){
console.info(error);
});
}
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div>
<p>Visible graphics:</p>
<!-- TODO: Display visible graphics-->
</div>
</body>
</html>
Thanks Robert Scheitlin, GISP & Rene Rubalcava!! Now it works , I'll share the app as soon as I have something to show ;-***
I have found an strange behaviour, as you can see here:
The layerView is not updating when new features are showing up and the query doesn't seem to be displaying the number of features in the screen, right?
This is the source code: https://jsbin.com/fuworis/11/edit?html,output
Any ideas?:Rene Rubalcava / Robert Scheitlin, GISP
Raul,
You have to update the query geometry each time:
view.whenLayerView(featureLayer).then(function(lyrView){
featLyrView = lyrView
lyrView.watch("updating", function (val) {
console.log("Updating layer view")
if (!val){
query.geometry = view.extent;
query.spatialRelationship = "intersects";
lyrView.queryFeatures(query).then(function(results){
console.log(`Graphics found: ${results.length}`);
});
}
});
});
hehe... ^_^'', you are right, (sorry, for the dummy question) -> https://jsbin.com/fuworis/13/edit?html,output
What about the ViewLayer, it should be updated when a new feature shows up on the screen, right?
Raul,
Here is your code updated to work best:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Query graphics on webmap</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.7/esri/css/main.css">
<script>
var dojoConfig = {
has: {
"esri-featurelayer-webgl": 1
}
};
</script>
<script src="https://js.arcgis.com/4.7/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 400px;
width: 100%;
}
</style>
<script>
require([
"esri/WebMap",
"esri/views/MapView",
"esri/widgets/LayerList",
"esri/widgets/Legend",
"esri/geometry/geometryEngine",
"esri/core/watchUtils",
"esri/tasks/support/Query",
"dojo/domReady!"
],
function(
WebMap,
MapView,
LayerList,
Legend,
geometryEngine,
watchUtils,
Query
) {
webmap = new WebMap({
portalItem: {
id: "19d21df5e87f4f5a9aa5b8d678b174d6"
}
});
view = new MapView({
container: "viewDiv",
map: webmap,
popup: {
dockEnabled: true,
dockOptions: {
buttonEnabled: false,
breakpoint: {
width: 1000
},
position: "bottom-left"
}
}
});
function graphicsInView(lyrView) {
var query = new Query();
query.geometry = view.extent;
query.spatialRelationship = "intersects";
lyrView.queryFeatures(query).then(function(results){
console.log(`Graphics found: ${results.length}`);
});
}
view.when(function() {
var featureLayer = webmap.layers.getItemAt(0);
view.whenLayerView(featureLayer).then(function(lyrView){
watchUtils.whenFalseOnce(lyrView, "updating", function() {
graphicsInView(lyrView);
});
watchUtils.whenTrue(view, "stationary", function() {
graphicsInView(lyrView);
});
});
featureLayer.labelingInfo = [{
labelExpression: "[title]",
labelExpressionInfo: {
"expression": "$feature[\"title\"]"
},
labelPlacement: "always-horizontal",
symbol: {
type: "text",
color: [ 255,255,255,0.85 ],
font: {
size: 16,
weight: "bold",
family: "Arial Unicode MS"
},
haloColor: [255, 255, 255, 255],
haloSize: 0.75,
}
}];
var legend = new Legend({
view: view,
layerInfos: [{
layer: featureLayer,
title: "Actor type"
}]
});
//view.ui.add(legend, "bottom-right");
var layerList = new LayerList({
view: view
});
//view.ui.add(layerList, "top-right");
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
<div>
<p>Visible graphics:</p>
<!-- TODO: Display visible graphics-->
</div>
</body>
This is exactly the behaviour I was expecting, great! Robert Scheitlin, GISP, thank you very very much.
This is the code working -> https://jsbin.com/fuworis/edit?html,output