JSAPI v4.3 - IdentifyTask returns feature even if layer is not visible

3452
15
03-30-2017 05:43 AM
MaximeDemers
Occasional Contributor III

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>‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
15 Replies
ThomasSolow
Occasional Contributor III

It's of course possible that someone else has encountered this bug.  For the time being, though, I think there is probably an acceptable workaround.

For example, if we only have to worry about one layer, or the sublayers of one layer, we could try something like this:

      function getVisibleLayerIds(map, layer){
        if (layer.sublayers){
          return layer.sublayers.filter(sublayer => sublayer.visible).map(sublayer => layer.sublayers.indexOf(sublayer));
        } else {
          return layer.visible ? [map.allLayers.indexOf(layer)] : [-1];
        }
      }

This could be calculated on click and the result could be passed into the layerId property of IdentifyParams.

0 Kudos
MaximeDemers
Occasional Contributor III

Thank you for your help Thomas. I have already tried this workaround. It could works only if you don't use definitionExpression on the subLayers, what I do.

The features in subLayers that are invisible by the action of the definitionExpression are queried anyway by the IdentifyTask().

I don't think there is a workaround that will cover every possibilities...

0 Kudos
hoogw
by
New Contributor III

your code, getVisibleLayerIds(), NOT work. 

it suppose return array [2, 4, 6],  

but it actually return empty array []

Please fix the bug

0 Kudos
hoogw
by
New Contributor III

Your code only works for single level sublayers, DOES NOT work when multiple level of sublayers, 

For example, a sublayers have children sublayers, etc.... 2 level deep sulayers.....

You have to use recursive to solve the multiple deep level sublayers.....

Here is my working code: 

               

   var _current_visible_layer_id_array = []

                 

   // you call this method

            recursive_nestedLayer(map,_map_image_layer.sublayers);

// then you set 

             params.layerIds = _current_visible_layer_id_array

// now it works. 

                      

// *********************** get current visible layer ***********************

/*
// https://community.esri.com/thread/192627-jsapi-v43-identifytask-returns-feature-even-if-layer-is-not-visible
// only works when layer NOT have nest sublayers. Only 1 level,
function getVisibleLayerIds(map, layer){
if (layer.sublayers){
return layer.sublayers.filter(sublayer => sublayer.visible).map(sublayer => layer.sublayers.indexOf(sublayer));
} else {
return layer.visible ? [map.allLayers.indexOf(layer)] : [-1];
}
}
*/


// for nested sublayer, use recursive
function recursive_nestedLayer(map, _nestedLayer){

_nestedLayer.forEach(function(item, i){

if (item.sublayers){

// recursive function deep 1 level
recursive_nestedLayer(map, item.sublayers);
}else {

console.log('-low-level-item',item )

if (item.visible){

console.log("visible !!!!")


// map.allLayers.indexOf(item), not work, maybe lost layer handle, instead use item.id works.
//_current_visible_layer_id_array.push(map.allLayers.indexOf(item));
_current_visible_layer_id_array.push(item.id);
} else {

_current_visible_layer_id_array.push(-1);

}




} // if

});

} //recursive_nestedLayer


// *********************** end ********************** get current visible layer ***********************

0 Kudos
hoogw
by
New Contributor III

now I found a better way:

                  you call:

                                     // .allSublayers is a flat collection of all children layer, including parent folder
_current_visible_layer_id_array = getVisibleLayerIds(_map_image_layer.allSublayers); 

             

function getVisibleLayerIds(flat_layer_collection){

// layer is collection of all kinds of layers. find the visible one

var ___array = [];
flat_layer_collection.forEach(function(item, i){


console.log("flat_collection_forEach - item: ====== >",item )




if (item.sublayers) {
// if item.sublayers is NOT null, means, item have children sulayer or layers.
// filter out

} else {
// sublayer is null
if (item.visible) {

___array.push(item.id);
} else {

___array.push(-1);

}

}
});


return ___array;
} // getVisibleLayerIds

0 Kudos
NilsBabel1
Occasional Contributor

Did you ever log a bug with Esri on this?  This seems to still be an issue at 4.17.  Although, I wonder if it is a bug or a flaw in the logic.  When creating a new IdentifyTask  you just specify a url.  It isn't really tied to the layer at all.  So how would it know if the layer is visible or not?  It seems like we are missing something.  

0 Kudos