Unable to Remove Graphics from Graphics Layer - ArcGIS API for JS

1637
5
Jump to solution
07-15-2019 12:47 PM
PaulMcCord
Occasional Contributor

I'm using ArcGIS API for JS v 4.11, and I'd like to remove a group of graphics from a Graphics Layer according to which checkbox is checked. In my code below, I'm giving the user the option to check either basketball, volleyball, or both. The layer on the ArcGIS Server is queried and the appropriate graphics are added to the map. This works fine when I'm adding graphics to the map. However, when I uncheck basketball, volleyball, or both, I'm unable to remove the appropriate graphics. When viewing the console window, it looks like I'm capturing the correct graphics, but when I attempt to remove with them with the removeMany() method (line 56 below), nothing is removed from the map.

$(document).on("click", ".featureCheck", function(){
        var trgt = $(this).attr("data-rel");

        //This 'if' statement will execute the query and get the query results
        if(trgt == "bball"){
          params.where = "Park_Att_4 = 'Y'"
          if ($(this).is(".checked")){
            console.log("checked");
            myMap.remove(wayneCoParks);
            qTask.execute(params).then(getResults); 
          } else{
            console.log("unchecked");
            qTask.execute(params).then(removeLayer); 
            //resultsLayer.removeAll();
          }
        }
        else if(trgt == "vball"){
          params.where = "Park_At_45 = 'Y'";
          if ($(this).is(".checked")){
            console.log("volleyball is checked");
            myMap.remove(wayneCoParks);
            qTask.execute(params).then(getResults);
          } else{
            console.log("unchecked");
            qTask.execute(params).then(removeLayer); 
          }
        }
      });

      //Add and remove parks according to community
      /*$("#multi-select").change(function(){
        console.log("change to selection");
        x = $("#multi-select").val()
        console.log(x);
      })*/

      //Called once promise is resolved
      function getResults(response){
        console.log("in getResults");
        console.log(response);
        var parkResults = response.features.map(function(feature){
          feature.symbol = parkSymbol;
          feature.popupTemplate = resultsPopupTemplate;
          return feature;
        });

        //Add results to the Layer
        console.log(parkResults);
        resultsLayer.addMany(parkResults);
        console.log(resultsLayer);
      };

      //Called once promise is resolved
      function removeLayer(response){
        console.log(response.features);
        resultsLayer.graphics.removeMany(response.features);
        console.log(resultsLayer);
      };

Note that the resultsLayer and several of the server query parameters are defined earlier in the code.

Please let me know if I'm missing something. Thank you.

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Esteemed Contributor

Paul,

   When you query the map service the graphics that are returned from the query are unique and will not be identical to the graphics that are already added to the map so you can not do removeMany and specify the results of your query from the map service. You can remove all the graphics from the GL and re-add the ones for the checked sport type each time, or you can add a specific attribute to the graphics before added them to the GL and then loop through the GLs graphics and only remove those graphics that have that specific attribute. 

View solution in original post

5 Replies
PaulMcCord
Occasional Contributor

I believe I'm getting closer to what I want, but it still isn't there. Is there a way that each selected set of graphics can be added to the same same graphics layer (and similarly removed from the same graphics layer). In my updated code below, I'm using a workaround where I create separate Graphics Layers for each sport. It is now successfully turning on and off each Graphics Layer individually. However, I'm ultimately going to want all of the graphics in the same layer. Is there a way to do this?

Here is my updated code:

//Create Graphics Layers      
      var bballGraphics = new GraphicsLayer();
      var vballGraphics = new GraphicsLayer();

//Add and remove parks according to features
      $(".featureCheck").checkbox();

      $(document).on("click", ".featureCheck", function(){
        var trgt = $(this).attr("data-rel");

        //This 'if' statement will execute the query and get the query results
        if(trgt == "bball"){
          params.where = "Park_Att_4 = 'Y'"
          if ($(this).is(".checked")){
            console.log("checked");
            myMap.remove(wayneCoParks);
            qTask.execute(params).then(getResults.bind(null, "bball")); 
          } else{
            console.log("unchecked");
            myMap.remove(bballGraphics);
          }
        }
        else if(trgt == "vball"){
          params.where = "Park_At_45 = 'Y'";
          if ($(this).is(".checked")){
            console.log("volleyball is checked");
            myMap.remove(wayneCoParks);
            qTask.execute(params).then(getResults.bind(null, "vball"));
          } else{
            console.log("unchecked");
            myMap.remove(vballGraphics); 
          }
        }
      });

      //Add and remove parks according to community
      /*$("#multi-select").change(function(){
        console.log("change to selection");
        x = $("#multi-select").val()
        console.log(x);
      })*/

      //Called once promise is resolved
      function getResults(text, data){
        console.log(text);
        console.log("in getResults");
        console.log(data);
        var parkResults = data.features.map(function(feature){
          feature.symbol = parkSymbol;
          feature.popupTemplate = resultsPopupTemplate;
          return feature;
        });

        //Add results to the Layer
        console.log(parkResults);
        //resultsLayer.addMany(parkResults);
        resultsLayer = eval(text +  "Graphics").removeAll();
        resultsLayer = eval(text +  "Graphics").addMany(parkResults);
        //console.log(resultsLayer);
        //console.log(bballGraphics);
        //myMap.add(bballGraphics);
        console.log(resultsLayer);
        myMap.add(resultsLayer);
      };


    });‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Paul,

   When you query the map service the graphics that are returned from the query are unique and will not be identical to the graphics that are already added to the map so you can not do removeMany and specify the results of your query from the map service. You can remove all the graphics from the GL and re-add the ones for the checked sport type each time, or you can add a specific attribute to the graphics before added them to the GL and then loop through the GLs graphics and only remove those graphics that have that specific attribute. 

PaulMcCord
Occasional Contributor

Thanks Robert, this is really helpful, but I still must have something wrong with my code. I've added an attribute to the graphics before they get added to the graphics layer, but when I try to remove the graphic from the graphic layer, I get the message: "Uncaught TypeError: Cannot read property 'attribute' of undefined."

Here is my revised code: 

Creating the Graphics Layer near the beginning of my code:

      var resultsLayer = new GraphicsLayer();

      myMap = new Map({
        basemap: basemap,
        layers: [resultsLayer],  //Add graphics layer to the map
        sliderPosition: "bottom-right"
      });‍‍‍‍‍‍‍‍‍

The below functions, first, add the selected sport(s), and then remove the selected sport(s). Note that "text" is the name of the sport that is passed to each function.

      function getResults(text, response){
        console.log("in getResults");
        console.log(response);
        var parkFeatures = response.features.map(function(feature){
          feature.symbol = parkSymbol;
          feature.popupTemplate = resultsPopupTemplate;
          feature.attribute = text; //adds an identifier to all graphics belonging to the same sport
          return feature;
        });

        //Add results to the Layer
        console.log(parkFeatures);
        resultsLayer.graphics.addMany(parkFeatures);
      };

      //Remove the de-selected sport
      function removeLayer(text){
      	for (gL = resultsLayer.graphics.length; gL>=0; gL--){
      		//console.log(gL);
      		if (resultsLayer.graphics[gL].attribute == text){
      			resultsLayer.remove(resultsLayer.graphics[gL]);
      		}
      	}
    }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Am I not adding the attribute to the graphic correctly (line 7)? The error is being thrown at line 20. Thanks.

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Paul,

   That would be 

feature.attributes.sport = text; //adds an identifier to all graphics belonging to the same sport

if (resultsLayer.graphics[gL].attributes.sport === text){
0 Kudos
PaulMcCord
Occasional Contributor

Okay, that makes sense. I now have it working. In addition to adding the park feature, which I'm calling 'amenity' now, to the attributes, I also had to change how I was targeting each individual graphic. Initially I wasn't getting the graphic item. Here is my revised if statement:

if (resultsLayer.graphics.items[gL].attributes.amenity == text){
      			console.log("in remove statement");
      			resultsLayer.remove(resultsLayer.graphics.items[gL]);
      		}

Thanks for your help!

0 Kudos