Feature Layer and a Graphics Layer?!?

4753
5
Jump to solution
10-17-2012 06:23 AM
AaronWeier
Occasional Contributor
Hi All,

I am running into a very confusing issue. I have a map service with about 45 layers and 5 tables. I am creating feature layers based on a drop down chosen by the user. Then, after the feature layer is displayed on screen, the user can select a feature on the map and see attribute data in a dashboard-like div.

Problem is: I cannot seem to remove layers from the map, they just keep piling up. I know this by using the map.graphicLayersIds.length function and logging the id.

so my question is, am i piling up graphicslayers and featurelayers? Are they one and the same? Am I trying to remove the wrong thing?

I've seen some other issues posted regarding map.removeLayer but none of those solutions has helped me.

Appreciate any feedback!
Aaron
0 Kudos
1 Solution

Accepted Solutions
__Rich_
Occasional Contributor III
I've modified (hacked!) this sample and added 2 buttons, both remove the FeatureLayer, the top button uses the global reference to the layer the second button uses your loop code to gain a reference to the layer, both work fine.

Without seeing the whole site, it's hard to know specifically what's not working for you, maybe someone else can spot a syntax error etc.

Are you using any development tools e.g. Firebug to help you debug?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html>      <head>     <title>Dynamic Layer</title>     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">     <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/dojo/dijit/themes/claro/claro.css">     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/esri/css/esri.css" />      <script type="text/javascript">dojoConfig = { parseOnLoad: true };</script>      <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.2"></script>     <style>     html, body, #mapDiv, .map.container {       padding:0;       margin:0;       height:100%;     }     </style>     <script type="text/javascript">         dojo.require("esri.map");         dojo.require("esri.layers.FeatureLayer");         var map, featureLayer;          function init() {              esri.config.defaults.geometryService = new esri.tasks.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");              var initialExtent = new esri.geometry.Extent({                 "xmin": -167.3,                 "ymin": -69.59,                 "xmax": 160.32,                 "ymax": 71.91,                 "spatialReference": {                     "wkid": 4326                 }             });             map = new esri.Map("mapDiv", {                 wrapAround180: true,                 extent: esri.geometry.geographicToWebMercator(initialExtent)             });              dojo.connect(map, 'onLoad', initOperationalLayer);              //Add the World Imagery service as a basemap to the map             var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");             map.addLayer(basemap);           }          function initOperationalLayer(map) {              var content = "<b>Name</b>: ${NAME}" + "<br /><b>Area</b>: ${ss6.gdb.Lakes.AREA:NumberFormat(places:0)}";             var infoTemplate = new esri.InfoTemplate("Dynamic Layer", content);              //define the layer's data source from a table             var dataSource = new esri.layers.TableDataSource();             dataSource.workspaceId = "MyDatabaseWorkspaceIDSSR2";             dataSource.dataSourceName = "ss6.gdb.Lakes";             var layerSource = new esri.layers.LayerDataSource();             layerSource.dataSource = dataSource;              //create a new feature layer based on the table data source              featureLayer = new esri.layers.FeatureLayer('http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/dynamicLayer', {                 mode: esri.layers.FeatureLayer.MODE_ONDEMAND,                 outFields: ["*"],                 infoTemplate: infoTemplate,                 source: layerSource             });             dojo.connect(featureLayer, "onLoad", function (layer) {                 //project the extent if the map's spatial reference is different that the layer's extent.                 var gs = esri.config.defaults.geometryService;                 var extent = layer.fullExtent;                 if (extent.spatialReference.wkid === map.spatialReference.wkid) {                     map.setExtent(extent);                 } else {                     gs.project([extent], map.spatialReference).then(function (results) {                         map.setExtent(results[0]);                     });                 }             });              var renderer = new esri.renderer.SimpleRenderer(               new esri.symbol.SimpleFillSymbol("solid", null, new dojo.Color([255, 0, 255, 0.75]) // fuschia lakes!             ));              featureLayer.setRenderer(renderer);             map.addLayer(featureLayer);             map.infoWindow.resize(150, 105);               dojo.connect(window, 'resize', map, map.resize);         }         dojo.addOnLoad(init);          function removeFeatureLayer() {             map.removeLayer(featureLayer);         }         function removeFeatureLayer2() {             console.log(">>>>>>>>>>>>>>>  GL count: " + map.graphicsLayerIds.length);             for (var j = 0, jl = map.graphicsLayerIds.length; j < jl; j++) {                 var currentGraphicsLayer = map.getLayer(map.graphicsLayerIds);                 //console.log("Graphics Layer ID: " + currentGraphicsLayer.id);                 map.removeLayer(currentGraphicsLayer);             }         }     </script>   </head>      <body class='claro'>     <div id="mapDiv"></div>       <input type="button" value="Remove Feature Layer" style="position:absolute;bottom:40px;left:10px;" onclick="removeFeatureLayer()" />       <input type="button" value="Remove Feature Layer 2" style="position:absolute;bottom:10px;left:10px;" onclick="removeFeatureLayer2()" />   </body>  </html>


edit: Hang on...just a thought the removeLayer method uses the layer reference passed in to detect the layer to remove...but I think you may have indirectly changed the referenced layer when you assigned the new layer to the hvaFeatureLayer variable, thus it cannot find a layer in it's list of existing layers that match that reference...so your layer list keeps growing.

Haven't had time to think this through fully though...

View solution in original post

0 Kudos
5 Replies
__Rich_
Occasional Contributor III
A FeatureLayer is a specialised GraphicsLayer - see the inheritance tree (or mixin hierarchy in Dojo terms).

But map.removeLayer() is type-agnostic i.e. you don't need to differentiate between Graphics and non-Graphics layers, that's taken care of in the API.

How are you calling removeLayer()?  You are passing it a reference to the layer you want to remove, aren't you?
AaronWeier
Occasional Contributor
thanks for the quick reply.

FYI: i'm using map and hvaFeatureLayer as global vars; ArcGIS Server v10; jsapi v3.2.

here's the basics:

init calls a function to create the featurelayer:

function createFL(layerid) {

            hvaFeatureLayer = new esri.layers.FeatureLayer("<mapserver url>/" + layerid, {
                mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
                outFields: ["*"]
            });
            hvaFeatureLayer.setRenderer(getRenderer("Stoplight")); //custom green, yellow, red indicators

            AddLayersToMap();

        }


createFL calls AddLayersToMap:

function AddLayersToMap() {

//if current graphics layer exists, call graphics layer function to get layer and remove it
            if (map.graphicsLayerIds.length >= 1) {
                getMapGraphicsLayers();
            }
           
            map.addLayer(hvaFeatureLayer);

            dojo.connect(hvaFeatureLayer, "onUpdateStart", function () {
                hvaFeatureLayer.id = hvaFeatureLayer.name;
            });


            //event listener for when user clicks on map
            dojo.connect(map, "onClick", executeSelectQueryTask);

            dojo.connect(hvaFeatureLayer, "onMouseOver", function (evt) {
                var t = "${LPHA_TRIBE_NAME}";
                var content = esri.substitute(evt.graphic.attributes, t);

                dialog.setContent(content);

                dojo.style(dialog.domNode, "opacity", 1);
                dijit.popup.open({ popup: dialog, x: evt.pageX, y: evt.pageY });

            });

            //close the dialog when the mouse leaves the highlight graphic
            dojo.connect(map, "onLoad", function () {
                map.graphics.enableMouseEvents();
                dojo.connect(map.graphics, "onMouseOut", closeDialog);
            });
  
        }


This function tests for graphics layers and calls function below to get the GL and remove it.

function getMapGraphicsLayers() {
            console.log(">>>>>>>>>>>>>>>  GL count: " + map.graphicsLayerIds.length);
            for (var j = 0, jl = map.graphicsLayerIds.length; j < jl; j++) {
                var currentGraphicsLayer = map.getLayer(map.graphicsLayerIds);
                //console.log("Graphics Layer ID: " + currentGraphicsLayer.id);
                map.removeLayer(currentGraphicsLayer);
            }
        }


After the map loads, the user is presented with a drop down list of layers to choose. After choosing a new layer, createFL gets called with the selected layer id and the process of adding a new feature layer and testing for graphics layer continues:

function changeHaz(value) {

            //if (hvaFeatureLayer){
            //     map.removeLayer(hvaFeatureLayer);
            //}
            
            //alert(value.substring(0,value.length-1));
            layerid = getIdFromMapService($.trim(value));
            createFL(layerid);

        }


i tried the 'map.removeLayer(hvaFeatureLayer);' call here but it doesn't work so i tried the graphics approach.

This is where I felt my lack of understanding between FL and GL came into play. And, obviously, i'm still not quite grasping something here....

Thanks again for any help you can provide!
Aaron
0 Kudos
__Rich_
Occasional Contributor III
I've modified (hacked!) this sample and added 2 buttons, both remove the FeatureLayer, the top button uses the global reference to the layer the second button uses your loop code to gain a reference to the layer, both work fine.

Without seeing the whole site, it's hard to know specifically what's not working for you, maybe someone else can spot a syntax error etc.

Are you using any development tools e.g. Firebug to help you debug?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html>      <head>     <title>Dynamic Layer</title>     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">     <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/dojo/dijit/themes/claro/claro.css">     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/esri/css/esri.css" />      <script type="text/javascript">dojoConfig = { parseOnLoad: true };</script>      <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.2"></script>     <style>     html, body, #mapDiv, .map.container {       padding:0;       margin:0;       height:100%;     }     </style>     <script type="text/javascript">         dojo.require("esri.map");         dojo.require("esri.layers.FeatureLayer");         var map, featureLayer;          function init() {              esri.config.defaults.geometryService = new esri.tasks.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");              var initialExtent = new esri.geometry.Extent({                 "xmin": -167.3,                 "ymin": -69.59,                 "xmax": 160.32,                 "ymax": 71.91,                 "spatialReference": {                     "wkid": 4326                 }             });             map = new esri.Map("mapDiv", {                 wrapAround180: true,                 extent: esri.geometry.geographicToWebMercator(initialExtent)             });              dojo.connect(map, 'onLoad', initOperationalLayer);              //Add the World Imagery service as a basemap to the map             var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");             map.addLayer(basemap);           }          function initOperationalLayer(map) {              var content = "<b>Name</b>: ${NAME}" + "<br /><b>Area</b>: ${ss6.gdb.Lakes.AREA:NumberFormat(places:0)}";             var infoTemplate = new esri.InfoTemplate("Dynamic Layer", content);              //define the layer's data source from a table             var dataSource = new esri.layers.TableDataSource();             dataSource.workspaceId = "MyDatabaseWorkspaceIDSSR2";             dataSource.dataSourceName = "ss6.gdb.Lakes";             var layerSource = new esri.layers.LayerDataSource();             layerSource.dataSource = dataSource;              //create a new feature layer based on the table data source              featureLayer = new esri.layers.FeatureLayer('http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/dynamicLayer', {                 mode: esri.layers.FeatureLayer.MODE_ONDEMAND,                 outFields: ["*"],                 infoTemplate: infoTemplate,                 source: layerSource             });             dojo.connect(featureLayer, "onLoad", function (layer) {                 //project the extent if the map's spatial reference is different that the layer's extent.                 var gs = esri.config.defaults.geometryService;                 var extent = layer.fullExtent;                 if (extent.spatialReference.wkid === map.spatialReference.wkid) {                     map.setExtent(extent);                 } else {                     gs.project([extent], map.spatialReference).then(function (results) {                         map.setExtent(results[0]);                     });                 }             });              var renderer = new esri.renderer.SimpleRenderer(               new esri.symbol.SimpleFillSymbol("solid", null, new dojo.Color([255, 0, 255, 0.75]) // fuschia lakes!             ));              featureLayer.setRenderer(renderer);             map.addLayer(featureLayer);             map.infoWindow.resize(150, 105);               dojo.connect(window, 'resize', map, map.resize);         }         dojo.addOnLoad(init);          function removeFeatureLayer() {             map.removeLayer(featureLayer);         }         function removeFeatureLayer2() {             console.log(">>>>>>>>>>>>>>>  GL count: " + map.graphicsLayerIds.length);             for (var j = 0, jl = map.graphicsLayerIds.length; j < jl; j++) {                 var currentGraphicsLayer = map.getLayer(map.graphicsLayerIds);                 //console.log("Graphics Layer ID: " + currentGraphicsLayer.id);                 map.removeLayer(currentGraphicsLayer);             }         }     </script>   </head>      <body class='claro'>     <div id="mapDiv"></div>       <input type="button" value="Remove Feature Layer" style="position:absolute;bottom:40px;left:10px;" onclick="removeFeatureLayer()" />       <input type="button" value="Remove Feature Layer 2" style="position:absolute;bottom:10px;left:10px;" onclick="removeFeatureLayer2()" />   </body>  </html>


edit: Hang on...just a thought the removeLayer method uses the layer reference passed in to detect the layer to remove...but I think you may have indirectly changed the referenced layer when you assigned the new layer to the hvaFeatureLayer variable, thus it cannot find a layer in it's list of existing layers that match that reference...so your layer list keeps growing.

Haven't had time to think this through fully though...
0 Kudos
__Rich_
Occasional Contributor III
Haven't had time to think this through fully though...

think I may be right, check out this modified code, I think it replicates your issue:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  
  <head>
    <title>Dynamic Layer</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/dojo/dijit/themes/claro/claro.css">
    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.2/js/esri/css/esri.css" />

    <script type="text/javascript">dojoConfig = { parseOnLoad: true };</script>

    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=3.2"></script>
    <style>
    html, body, #mapDiv, .map.container {
      padding:0;
      margin:0;
      height:100%;
    }
    </style>
    <script type="text/javascript">
        dojo.require("esri.map");
        dojo.require("esri.layers.FeatureLayer");
        var map, featureLayer;

        function init() {

            esri.config.defaults.geometryService = new esri.tasks.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");

            var initialExtent = new esri.geometry.Extent({
                "xmin": -167.3,
                "ymin": -69.59,
                "xmax": 160.32,
                "ymax": 71.91,
                "spatialReference": {
                    "wkid": 4326
                }
            });
            map = new esri.Map("mapDiv", {
                wrapAround180: true,
                extent: esri.geometry.geographicToWebMercator(initialExtent)
            });

            dojo.connect(map, 'onLoad', initOperationalLayer);

            //Add the World Imagery service as a basemap to the map
            var basemap = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
            map.addLayer(basemap);


        }

        function initOperationalLayer() {

            var content = "<b>Name</b>: ${NAME}" + "<br /><b>Area</b>: ${ss6.gdb.Lakes.AREA:NumberFormat(places:0)}";
            var infoTemplate = new esri.InfoTemplate("Dynamic Layer", content);

            //define the layer's data source from a table
            var dataSource = new esri.layers.TableDataSource();
            dataSource.workspaceId = "MyDatabaseWorkspaceIDSSR2";
            dataSource.dataSourceName = "ss6.gdb.Lakes";
            var layerSource = new esri.layers.LayerDataSource();
            layerSource.dataSource = dataSource;

            //create a new feature layer based on the table data source 
            featureLayer = new esri.layers.FeatureLayer('http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer/dynamicLayer', {
                mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
                outFields: ["*"],
                infoTemplate: infoTemplate,
                source: layerSource
            });
            dojo.connect(featureLayer, "onLoad", function (layer) {
                //project the extent if the map's spatial reference is different that the layer's extent.
                var gs = esri.config.defaults.geometryService;
                var extent = layer.fullExtent;
                if (extent.spatialReference.wkid === map.spatialReference.wkid) {
                    map.setExtent(extent);
                } else {
                    gs.project([extent], map.spatialReference).then(function (results) {
                        map.setExtent(results[0]);
                    });
                }
            });

            var renderer = new esri.renderer.SimpleRenderer(
              new esri.symbol.SimpleFillSymbol("solid", null, new dojo.Color([255, 0, 255, 0.75]) // fuschia lakes!
            ));

            featureLayer.setRenderer(renderer);
            map.addLayer(featureLayer);
            map.infoWindow.resize(150, 105);


            dojo.connect(window, 'resize', map, map.resize);
        }
        dojo.addOnLoad(init);

        function removeFeatureLayer() {
            initOperationalLayer();  //Simulates the new layer call in your code
            map.removeLayer(featureLayer);
        }
        function removeFeatureLayer2() {
            initOperationalLayer(); //Simulates the new layer call in your code
            console.log(">>>>>>>>>>>>>>>  GL count: " + map.graphicsLayerIds.length);
            for (var j = 0, jl = map.graphicsLayerIds.length; j < jl; j++) {
                var currentGraphicsLayer = map.getLayer(map.graphicsLayerIds);
                //console.log("Graphics Layer ID: " + currentGraphicsLayer.id);
                map.removeLayer(currentGraphicsLayer);
            }
        }
    </script>
  </head>
  
  <body class='claro'>
    <div id="mapDiv"></div>
      <input type="button" value="Remove Feature Layer" style="position:absolute;bottom:40px;left:10px;" onclick="removeFeatureLayer()" />
      <input type="button" value="Remove Feature Layer 2" style="position:absolute;bottom:10px;left:10px;" onclick="removeFeatureLayer2()" />
  </body>

</html>
0 Kudos
AaronWeier
Occasional Contributor
Geos -

I really appreciate all the effort in helping me with this issue. I've been using IE Dev Tools since the site i'm working on will be a site page in SharePoint. All other code works with no errors, so i've only provided the necessary bits that handle the add and remove layer.

I think I've found the problem based on this statement 
I think you may have indirectly changed the referenced layer


I did change the reference layer, right after 'onLoad', with this code (that i've now commented out).

//            dojo.connect(hvaFeatureLayer, "onUpdateStart", function () {
//                hvaFeatureLayer.id = hvaFeatureLayer.name;
//            });


Thanks again for all your assistance!

Aaron
0 Kudos