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>
Solved! Go to Solution.
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);
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.
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?
You could try to use the direct findLayerById Method of the WebMap class. Link below.
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>
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.
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);