IdentifyParameters.LAYER_OPTION_VISIBLE still gives identify results on all layers

7992
26
Jump to solution
02-03-2012 09:36 AM
SwenWaschk
New Contributor III
I've used both the create layer list and the identify pop-up samples to create the following code (see first reply)


But if I turn of a layer in the layerlist it still is identified. How do i stop this from happening?
0 Kudos
26 Replies
KevinMacLeod1
Occasional Contributor III
nicholas if I understand you correctly, I want the same thing.  I suspect most developers and end users do.  We want an "Identify" like in ArcMap. 

What I need is to Identify on multiple dynamic layers, and identifies on only visible layers, and display all results with page-through, with those little arrows at the top of the infowindow, or another way if that is not supported.  And work with scale-dependent layers as well.  It should know visibility based on Nianwei's AGS JS TOC toggling control.

Does anyone have a working example of this, such as a Fiddle, etc?

Something perhaps that combines the efforts of these two Fiddles:

http://jsfiddle.net/kenbuja/nvNQw/   (works with AGS JS TOC but only one layer)

http://jsfiddle.net/blordcastillo/mULcz/    (multiple dynamic layers)

It looks like perhaps Tracy created something like this in this thread  http://forums.arcgis.com/threads/93896-conversion-of-mutiple-IdentifyTasks-from-DeferredList-to-Prom...

A solution for scale dependency was apparently proposed in this thread: http://forums.arcgis.com/threads/68811-IdentifyTask-Returning-Scale-Dependent-Layers-When-Outside-of...

This would probably be a good widget for ESRI to provide as an official Sample as well.  It would be popular.
0 Kudos
TracySchloss
Frequent Contributor
Yes, you can't tell from my thread, by I was able to get my identify to work the way I wanted.  One of the gotchas I learned from another thread was that I needed to dynamically create my identifyParameters based on the current visibility.  It's not enough to have them defined at the beginning.  Once you introduce a TOC into the mix, the visibility isn't fixed. 

I have this set on a map click event
app.map.on("click", runIdentifies);


These are my identify functions. 
// FUNCTION FOR IDENTIFYING MULTIPLE LAYERS AT ONCE
//manually define which layers to do the identify on based on visible Layers
function createIdentifyParams(layers,evt){
    identifyParamsList.length = 0;
    arrayUtils.forEach(layers, function (layer) {
    var idParams = new IdentifyParameters();
    idParams.width = app.map.width;
    idParams.height = app.map.height;
    idParams.geometry = evt.mapPoint;
    idParams.mapExtent = app.map.extent;
    idParams.layerOption = IdentifyParameters.LAYER_OPTION_VISIBLE;
    var visLayers = layer.visibleLayers;
    if (visLayers !== -1) { //TOC lets the user change visibility, layerIDs must be explicitly defined
    idParams.layerIds = layer.visibleLayers;
    }else {
    idParams.layerIds = [];
    }
    idParams.tolerance = 3;
    idParams.returnGeometry = true;
    idParams.spatialReference = spatialReference;
    identifyParamsList.push(idParams);
    });
    return identifyParamsList;
}
function runIdentifies(evt) {
idPoint = evt.mapPoint;
app.map.infoWindow.clearFeatures();
    var layers = arrayUtils.map(app.map.layerIds, function(layerId) {
        return app.map.getLayer(layerId);
    }); 
    layers = arrayUtils.filter(layers, function(layer) {
        if (layer.visibleLayers[0] !== -1){
        return layer.getImageUrl && layer.visible
        }
    });
    var params = createIdentifyParams(layers,evt);
    var tasks = arrayUtils.map(layers, function(layer) {
        return new IdentifyTask(layer.url);
    }); 
var IdentifyTaskList = arrayUtils.map(layers, function(layer, index) {
        task = new IdentifyTask(layer.url);
        return task.execute(params[index])     //assume you have a list of identifyParameters
    }); 
all(IdentifyTaskList).then(showIdentifyResults);
}

function showIdentifyResults(idResults){
  var results = [];
   idResults = arrayUtils.filter(idResults, function (result) {//filter out any failed tasks
      return idResults[0];
   }); 
    for (i=0;i<idResults.length;i++) { //combines identifyResults 
        var lyrResultLen = idResults.length;
        var lyrResult = idResults;
        for (j = 0; j < lyrResultLen; j++) {
          var featRes = lyrResult;
          results.push(featRes);
        }
    }
    formatResults = arrayUtils.map(results, function(result){        
        var feature = result.feature;
        var layerName = result.layerName;           
        feature.attributes.layerName = result.layerName;
        feature.setInfoTemplate(generateInfoTemplate);
        generateInfoTemplate.setTitle("Layer Information");
        return feature;            
     });
        if (formatResults.length > 0) { 
         app.map.infoWindow.setFeatures(formatResults);
         app.map.infoWindow.show(idPoint);
        }      
}   


I have this other set of functions that allows me to pick and choose which output fields I want to display in the infoTemplate.  It's the only 'project specific' bit of code that I have to edit.

First you need to define an array of attributes per each layer. 
        var legisDistAtt = ['OBJECTID','District'];
        var prevDistAtt = ['OBJECTID','ID'];
        var countyAtt = ['OBJECTID', 'COUNTYNAME'];


Then you want to create a infoTemplate and use a function to set its content:

generateInfoTemplate = new InfoTemplate();
generateInfoTemplate.setTitle("Layer Information");
generateInfoTemplate.setContent(generateWindowContent);

function generateWindowContent(graphic) {
   var layerName = graphic.attributes.layerName;//case sensitive field names
   var fieldNamesArr = [];
for (fieldName in graphic.attributes) {
    if (graphic.attributes.hasOwnProperty(fieldName) && fieldName !=='Shape' && fieldName !== 'Shape.area' && fieldName !== 'Shape.len') {
        fieldNamesArr.push(fieldName);
    }
}
   var attString = "";
   switch (layerName) {
       case "House District":
       attString = createAttRows(graphic, legisDistAtt);
       break;
       case "Senate District":
       attString = createAttRows(graphic, legisDistAtt);
       break;
       case "Congressional District":
       attString = createAttRows(graphic, legisDistAtt);
       break;
       case "County":
       attString = createAttRows(graphic, countyAtt);
       break;
       default:
       attString = createAttRows(graphic, fieldNamesArr);      
   }   
   return "<h4>"+ layerName +"</h4>" +"<table id='infoWindowTable' data-dojo-type='dojox/grid/DataGrid' data-dojo-props='class:'infoTable'' ><tr><th></th><th></th></tr>" +attString+ "</table>";
}

function createAttRows(graphic, attArray) {
    var returnString = "";
     arrayUtils.forEach(attArray, function (attName){
         if (attName !== 'OBJECTID' && attName !== 'layerName') {
         returnString = returnString + "<tr><td><b>"+attName+"</b></td><td>" + graphic.attributes[attName]+ "</td></tr>";
         }
     });
     return returnString;
} 


I throw these last functions in because they're called in the identify results handler to set up the feature's infoTemplate.
0 Kudos
NicholasGross
Occasional Contributor II
Tracy, do you know whether the code you posted will work for multiple dynamic map services?

The problem I'm having (or that I think I'm having) is that with multiple dynamic services, I have multiple sublayers with the same id. So, let's say I have two dynamic services, parentA and parentB. And both parentA and parentB have three sublayers each. The API automatically assigns ids to these sublayers; each set gets id 0-2. So now I have two sublayers at id 0, two at 1, and two at 2.

When I assign ids to the layerId property on the IdentifyParameter object, it seems to completely ignore the parent ids and only pay attention to the sublayers. So if I assign layerId to parentA, it ignores that and assigns to sublayer 0. The bigger problem is that, because I'm not giving it the actual layer object, but rather a simple integer (or array of integers), it can't distinguish between sublayer 0 on parentA and sublayer 0 on parentB. It identifies both even though I only want one to be visible.

When trying to identify only visible layers from multiple dynamic map services, due to the grouping of sublayers beneath a parent, I can't find any way around the bugged layerOption property or the limitations of the layerId property.
0 Kudos
TracySchloss
Frequent Contributor
Nearly all my services have multiple layers within them.  You aren't referring to group layers are you?  It gets hard to have a discussion when we're using such generic terms as layer.  It doesn't matter what the layers are called within the service, or if you have the same layer name in two different services.  You aren't using these names when you set up your identify.  

What you are using in Identify is the unique ID you should be assigning to each layer as you load it into your map.  When you add a layer,you should always give it an id.  I give the same id as the variable, just to keep it straight in my head.
    educationLayer = new ArcGISDynamicMapServiceLayer(pathName+"/ArcGIS/rest/services/BaseMap/Education/MapServer", {id:'educationLayer', visible:false})


When you start up the runIdentifies function, the first thing it does is look at the current layers you have loaded.  It's going to create an array of all the layers.  This isn't a list of the names as they are called in the service directory.  
 var layers = arrayUtils.map(app.map.layerIds, function(layerId) {
        return app.map.getLayer(layerId);
    }); 


When you define your identifyParameters, you don't care about the names of the layers here either.  I have this set up to generate a new  identifyTask and corresponding identifyParameters each time you click.  Since the identifyParameters are created on-the-fly, you have the chance to specify which layers you want to identify.  You need this extra parameter of layerIds, setting IdentifyParameters.LAYER_OPTION_VISIBLE isn't going to be enough.

        var visLayers = layer.visibleLayers;
        if (visLayers !== -1) { //TOC lets the user change visibility, layerIDs must be explicitly defined
        idParams.layerIds = layer.visibleLayers;
        }else {
        idParams.layerIds = [];
        }


When defining visLayers, it's  returning the array of numbers, something like [0,2] or whatever you have currently turned on.  Again, it doesn't matter what something is called in the service.
0 Kudos
MichaelVolz
Esteemed Contributor

Does ESRI or any Javascript developer know if this NIM has been fixed at any version of AGS v10.2.x or possibly at v10.3.0?  It would be nice for the code to work as advertised in the documentation instead of resorting to workarounds.

0 Kudos
KevinMacLeod1
Occasional Contributor III

Michael it does not seem likely ESRI will change it.  Ultimately it would be good to see ESRI provide an Identify widget in the API that tracked visible layers and had capability to identify all visible layers. But for now you must build your own widget.  I built an Identify that does this (with much help from Tracy, Adrian and everyone else here..thank you all). It works with the AGS JS TOC Widget mentioned here:  MapViewer - Savannah Area GIS

Feel free to use all the code.  Just let me know if you find any bugs.

0 Kudos
MohammedAbdulMateen
New Contributor II

Simple way to get visiblelayerids and assign to identify parameters.

var FilteredLayerIds = app.ElectricGrid_Service.visibleLayers.slice(0);

        identifyParams.layerIds = FilteredLayerIds;

0 Kudos