Hi!
Is it normal that the IdentifyTask returns features even if the layer is not visible? I see in the documentation that the layerOption parameter in the IdentifyParameters should define if the IdentifyTask will return feature for visibile layer only. However, this parameter seem not working. The popup is displayed even if the layer is not visible as shown below. The image and code below are taken from the documentation sample codes
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/TileLayer",
"esri/tasks/IdentifyTask",
"esri/tasks/support/IdentifyParameters",
"dojo/_base/array",
"dojo/on",
"dojo/dom",
"dojo/domReady!"
], function(
Map, MapView, TileLayer,
IdentifyTask, IdentifyParameters,
arrayUtils, on, dom
) {
var identifyTask, params;
// URL to the map service where the identify will be performed
var soilURL =
"https://services.arcgisonline.com/arcgis/rest/services/Specialty/Soil_Survey_Map/MapServer";
// Add the map service as a TileLayer for fast rendering
// Tile layers are composed of non-interactive images. For that reason we'll
// use IdentifyTask to query the service to add interactivity to the app
var parcelsLyr = new TileLayer({
url: soilURL,
opacity: 0.85,
visible: false
});
var map = new Map({
basemap: "osm"
});
map.add(parcelsLyr);
var view = new MapView({
map: map,
container: "viewDiv",
center: [-120.174, 47.255],
zoom: 7
});
view.then(function() {
// executeIdentifyTask() is called each time the view is clicked
on(view, "click", executeIdentifyTask);
// Create identify task for the specified map service
identifyTask = new IdentifyTask(soilURL);
// Set the parameters for the Identify
params = new IdentifyParameters();
params.tolerance = 3;
params.layerIds = [0, 1, 2];
params.layerOption = "top";
params.width = view.width;
params.height = view.height;
});
// Executes each time the view is clicked
function executeIdentifyTask(event) {
// Set the geometry to the location of the view click
params.geometry = event.mapPoint;
params.mapExtent = view.extent;
dom.byId("viewDiv").style.cursor = "wait";
// This function returns a promise that resolves to an array of features
// A custom popupTemplate is set for each feature based on the layer it
// originates from
identifyTask.execute(params).then(function(response) {
var results = response.results;
return arrayUtils.map(results, function(result) {
var feature = result.feature;
var layerName = result.layerName;
feature.attributes.layerName = layerName;
if (layerName === 'Soil Survey Geographic') {
feature.popupTemplate = { // autocasts as new PopupTemplate()
title: "{Map Unit Name}",
content: "<b>Dominant order:</b> {Dominant Order} ({Dom. Cond. Order %}%)" +
"<br><b>Dominant sub-order:</b> {Dominant Sub-Order} ({Dom. Cond. Suborder %}%)" +
"<br><b>Dominant Drainage Class:</b> {Dom. Cond. Drainage Class} ({Dom. Cond. Drainage Class %}%)" +
"<br><b>Farmland Class:</b> {Farmland Class}"
};
}
else if (layerName === 'State Soil Geographic') {
feature.popupTemplate = { // autocasts as new PopupTemplate()
title: "{Map Unit Name}",
content: "<b>Dominant order:</b> {Dominant Order} ({Dominant %}%)" +
"<br><b>Dominant sub-order:</b> {Dominant Sub-Order} ({Dominant Sub-Order %}%)"
};
}
else if (layerName === 'Global Soil Regions') {
feature.popupTemplate = { // autocasts as new PopupTemplate()
title: layerName,
content: "<b>Dominant order:</b> {Dominant Order}" +
"<br><b>Dominant sub-order:</b> {Dominant Sub-Order}"
};
}
return feature;
});
}).then(showPopup); // Send the array of features to showPopup()
// Shows the results of the Identify in a popup once the promise is resolved
function showPopup(response) {
if (response.length > 0) {
view.popup.open({
features: response,
location: event.mapPoint
});
}
dom.byId("viewDiv").style.cursor = "auto";
}
}
});
</script>
By default it looks like identify is run on the top layer only, regardless of client layer visibility. You can change this using the identify params. For instance if you wanted to run identify only on visible layers, you could set the "layerOption" property on the params to "visible."
IdentifyParameters | API Reference | ArcGIS API for JavaScript 4.3
If you want to get specific about which layers to query, you can pass an array of layerIds in as the "layerIds" property.
Thats not what the doc says about the layerOption "top" paramerer: Only the top-most VISIBLE layer is identified.
Anyway setting the layerOption to "visible" does not make any difference. You can try directly in the sample code sandbox
What you'll have to do is set the layerIds property to -1 (setting it to "[]" doesn't work, like it did in 3.x)
params = new IdentifyParameters();
params.tolerance = 3;
params.layerIds = [-1];
params.layerOption = "top";
params.width = view.width;
params.height = view.height;
Doing that, it wont work when the layer is visible...
So what you'll have to do is put a little code in to determine whether the layer is visible
if (parcelsLyr.visible) {
params.layerIds = [0,1,2];
} else {
params.layerIds = [-1];
}
Imagine you have more than one layer that you want to use with the IdentifyTask, for instance subLayers in a MapImageLayer, you wont be able to use such workaround.
It seems to be a bug in the API right?
Yes, it does seem to be a bug. However, I'm not sure why you couldn't simply determine which layers are visible and use that in the layerIds property. For example, in the sandbox example, if I use
params.layerIds = [1];
then I get the result at the initial zoom level, but not when I zoom in or out far enough where the visible map changes from "State Soil Geographic" to "Soil Survey Geographic" or "Global Soil Regions"
I'd consider it a bug since "visible" doesn't appear to be working, and the documentation for "top" appears to be wrong.
It's not clear to me what a layer id is in this situation. You should be able to use Collection.flatten to get all layers + all sublayers and then map that to a list of ids. But what does [0,1,2] refer to here? Are those ids just "index of layer?"
According to me, the layerIds property refer to the subLayers ids (see for instance MapImageLayer.subLayers in the documentation.) When you instantiate an IdentifyTask(), you give the url of the layer that would be queried by the tool. So, layerIds is not related to every layers in the map, only the subLayers of the layer you have initiate the IdentifyTask with.
How is possible that no one have ever encountered this bug before? I can't believe it. I think it would be trivial to fix it, but how long shall we wait for the fix?