happymappy
happymappy

Reputation: 181

Uncaught (in promise) TypeError: cannot read property graphic of undefined

Very new at JavaScript and trying to build a web map using the ArcGIS API for JavaScript 4x loosely following the tutorial here: https://developers.arcgis.com/javascript/latest/sample-code/views-composite-views/index.html

I mostly wanted to keep the highlight function while allowing zooming and panning, all within a single view using my own web layers.

The error I get in the console is: Uncaught (in promise) TypeError: Cannot read property 'graphic' of undefined

I've looked at a few questions discussing similar errors, but still don't understand exactly what I mis-edited here from the tutorial code for it to throw the error. Let me know if seeing other parts of the code would be helpful. I'm banging my head against the wall here - any help would be appreciated!

Here is the highlight function code:

// highlight function

mainView
    .when(maintainFixedExtent)
    .then(disableNavigation)
    .then(enableHighlightOnPointerMove);

function maintainFixedExtent(view) {
    var fixedExtent = view.extent.clone();
    view.on("resize", function () {
        view.extent = fixedExtent;
    });
    return view;
}

let highlight = null;
let lastHighlight = null;

function enableHighlightOnPointerMove(view) {
    view.whenLayerView(basinsLayer).then(function (layerView) {
        view.on("pointer-move", function (event) {
            view.hitTest(event).then(function (response) {
                lastHighlight = highlight;

                var id = null;

                if (response.results.length) {
                    var feature = response.results.filter(function (result) {
                        return result.graphic.layer === basinsLayer;
                    })[0].graphic;

                    feature.popupTemplate = basinsLayer.popupTemplate;
                    id = feature.attributes.OBJECTID;
                    highlight = layerView.highlight([id]);
                    var selectionId = mainView.popup.selectedFeature
                        ? mainView.popup.selectedFeature.attributes.OBJECTID
                        : null;

                    if (highlight && id !== selectionId) {
                        mainView.popup.open({
                            features: [feature]
                        });
                    }
                } else {
                    if (mainView.popup.visible) {
                        mainView.popup.close();
                        mainView.popup.clear();
                    }
                }

                // remove the previous highlight
                if (lastHighlight) {
                    lastHighlight.remove();
                    lastHighlight = null;
                }
            });
        });
    });
}

function disableNavigation(view) {
    view.popup.dockEnabled = true;

    view.popup.actions = [];

    function stopEvtPropagation(event) {
        event.stopPropagation();
    }

    return view;
}

Edit:

Here is a full working example using public data. I think the issue is related to me having both a point layer and a polygon layer. I only want to use the highlight function on the polygon layer, but if you hover around enough, the "uncaught (in promise) TypeError: cannot read property graphic of undefined" appears in the console and I think this is related to the point layer. Is there a workaround?

<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <!--
  ArcGIS API for JavaScript, https://js.arcgis.com
  For more information about the views-composite-views sample, read the original sample description at developers.arcgis.com.
  https://developers.arcgis.com/javascript/latest/sample-code/views-composite-views/index.html
  -->
<title>Create an app with composite views - 4.15</title>

    <style>
      html,
      body,
      #mainViewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }

      #akViewDiv {
        padding: 0;
        margin: 0;
        height: 225px;
        width: 300px;
        background-color: rgba(255, 255, 255, 0.9);
      }

      #hiViewDiv {
        padding: 0;
        margin: 0;
        height: 135px;
        width: 200px;
        background-color: rgba(255, 255, 255, 0.9);
      }
    </style>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.15/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.15/"></script>

    <script>
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer",
        "esri/widgets/Legend"
      ], function(Map, MapView, FeatureLayer, Legend) {
        var layer = new FeatureLayer({
          portalItem: {
            id: "b234a118ab6b4c91908a1cf677941702"
          },
          outFields: ["NAME", "STATE_NAME", "VACANT", "HSE_UNITS"],
          title: "U.S. counties"
        });

       var layer2 = new FeatureLayer({
          url: "https://services1.arcgis.com/0MSEUqKaxRlEPj5g/arcgis/rest/services/ncov_cases_US/FeatureServer/0"
        }); 

        var map = new Map({
          layers: [layer, layer2]
        });

        var mainView = new MapView({
          container: "mainViewDiv",
          map: map,
          popup: {
            highlightEnabled: false,
            dockEnabled: true,
            dockOptions: {
              breakpoint: false,
              position: "top-right"
            }
          },
          extent: {
            xmin: -3094834,
            ymin: -44986,
            xmax: 2752687,
            ymax: 3271654,
            spatialReference: {
              wkid: 5070
            }
          },
          spatialReference: {
            // NAD_1983_Contiguous_USA_Albers
            wkid: 5070
          },
          ui: {
            components: ["attribution"]
          }
        });
        mainView.ui.add(
          new Legend({
            view: mainView
          }),
          "bottom-right"
        );


mainView
          .when(disablePopupOnClick)
          .then(enableHighlightOnPointerMove);

        let highlight = null;
        let lastHighlight = null;

        function enableHighlightOnPointerMove(view) {
          view.whenLayerView(layer).then(function(layerView) {
            view.on("pointer-move", function(event) {
              view.hitTest(event).then(function(response) {
                lastHighlight = highlight;

                // if a feature is returned, highlight it
                // and display its attributes in the popup
                // if no features are returned, then close the popup
                var id = null;

                if (response.results.length) {
                  var feature = response.results.filter(function(result) {
                    return result.graphic.layer === layer;
                  })[0].graphic;

                  feature.popupTemplate = layer.popupTemplate;
                  id = feature.attributes.OBJECTID;
                  highlight = layerView.highlight([id]);
                  var selectionId = mainView.popup.selectedFeature
                    ? mainView.popup.selectedFeature.attributes.OBJECTID
                    : null;

                  if (highlight && id !== selectionId) {
                    mainView.popup.open({
                      features: [feature]
                    });
                  }
                } else {
                  if (mainView.popup.visible) {
                    mainView.popup.close();
                    mainView.popup.clear();
                  }
                }

                // remove the previous highlight
                if (lastHighlight) {
                  lastHighlight.remove();
                  lastHighlight = null;
                }
              });
            });
          });
        }

        // prevents the user from opening the popup with click

        function disablePopupOnClick(view) {
          view.on("click", function(event) {
            event.stopPropagation();
          });
          return view;
        }
      });
    </script>
  </head>

  <body>
    <div id="mainViewDiv"></div>
    <div id="akViewDiv" class="esri-widget"></div>
    <div id="hiViewDiv" class="esri-widget"></div>
  </body>
</html>

enter image description here

Upvotes: 1

Views: 2870

Answers (1)

cabesuon
cabesuon

Reputation: 5270

Example of what I think you are trying to achieve. Based on the ArcGIS example of the question, just remove everything that stop the navigation on the map, and the extra views.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>highlight features - 4.15</title>

    <style>
      html,
      body,
      #mainViewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }
    </style>

    <link
      rel="stylesheet"
      href="https://js.arcgis.com/4.15/esri/themes/light/main.css"
    />
    <script src="https://js.arcgis.com/4.15/"></script>

    <script>
      require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/FeatureLayer"
      ], function(Map, MapView, FeatureLayer) {
        var layer = new FeatureLayer({
          portalItem: {
            id: "b234a118ab6b4c91908a1cf677941702"
          },
          outFields: ["NAME", "STATE_NAME", "VACANT", "HSE_UNITS"],
          title: "U.S. counties"
        });

        var map = new Map({
          layers: [layer]
        });

        var mainView = new MapView({
          container: "mainViewDiv",
          map: map,
          popup: {
            highlightEnabled: false,
            dockEnabled: true,
            dockOptions: {
              breakpoint: false,
              position: "top-right"
            }
          },
          extent: {
            xmin: -3094834,
            ymin: -44986,
            xmax: 2752687,
            ymax: 3271654,
            spatialReference: {
              wkid: 5070
            }
          },
          spatialReference: {
            // NAD_1983_Contiguous_USA_Albers
            wkid: 5070
          },
          ui: {
            components: ["attribution"]
          }
        });
        
        mainView
          .when(disablePopupOnClick)
          .then(enableHighlightOnPointerMove);
        
        let highlight = null;
        let lastHighlight = null;

        function clearPopup() {
          if (mainView.popup.visible) {
            mainView.popup.close();
            mainView.popup.clear();
          }
        }

        function clearHighlight(lastHighlight) {
          if (lastHighlight) {
            lastHighlight.remove();
            lastHighlight = null;
          }
        }

        function enableHighlightOnPointerMove(view) {
          view.whenLayerView(layer).then(function(layerView) {
            view.on("pointer-move", function(event) {
              view.hitTest(event).then(function(response) {
                lastHighlight = highlight;
                var id = null;
                
                if (response.results.length) {
                  clearPopup();
                }

                var filterFeatures = response.results.filter(function(result) {
                  return result.graphic.layer === layer;
                });

                if (filterFeatures && filterFeatures.length > 0) {
                  var feature = filterFeatures[0].graphic;
                  feature.popupTemplate = layer.popupTemplate;
                  id = feature.attributes.OBJECTID;
                  highlight = layerView.highlight([id]);
                  var selectionId = mainView.popup.selectedFeature
                    ? mainView.popup.selectedFeature.attributes.OBJECTID
                    : null;

                  if (highlight && id !== selectionId) {
                    mainView.popup.open({
                      features: [feature]
                    });
                  }

                } else {
                  clearPopup();
                  console.log('filterFeatures is empty');
                }
                
                clearHighlight(lastHighlight);

              });
            });
          });
        }
        
        // prevents the user from opening the popup with click

        function disablePopupOnClick(view) {
          view.on("click", function(event) {
            event.stopPropagation();
          });
          return view;
        }
      });
    </script>
  </head>

  <body>
    <div id="mainViewDiv"></div>
  </body>
</html>

Upvotes: 1

Related Questions