Identify tool implementation issue

1852
10
Jump to solution
10-11-2016 12:52 PM
NhuMai
by
New Contributor II

I'm trying to implement an identify tool akin to the sample found here. However, I am having issues getting it to work. Below, i've tried to print to the console when initFunctionality() is called--this never occurs. Strangely, I occasionally get a TypeError: map is not defined. Refreshing the page gets me past this, but I have a feeling this is linked.

The map is created in Map.js:

var map;
var baseMapLayerWorld;

require([
 "esri/map", "esri/dijit/Search", "esri/layers/ArcGISDynamicMapServiceLayer","esri/layers/FeatureLayer", "esri/InfoTemplate", "dojo/domReady!"
], function (Map, Search, DynamicMapServiceLayer, FeatureLayer, InfoTemplate) {

baseMapLayerWorld = new esri.layers.ArcGISTiledMapServiceLayer("http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer");
 map = new Map("map", {
 center: [-150, -17], // lon, lat
 zoom: 8
 });

map.addLayers([baseMapLayerWorld]);
});

The identify tool is implemented in Identify.js:

var bldgResults, parcelResults, symbol;

      require([
        "esri/map",
        "esri/layers/ArcGISDynamicMapServiceLayer",
        "esri/symbols/SimpleFillSymbol",
        "esri/symbols/SimpleLineSymbol",
        "esri/tasks/IdentifyTask",
        "esri/tasks/IdentifyParameters",
        "dojo/on",
        "dojo/parser",
        "esri/Color",
        "dijit/registry",
        "dijit/form/Button",
        "dijit/layout/ContentPane",
        "dijit/layout/TabContainer",
        "dojo/domReady!"
      ],
        function (
          Map, ArcGISDynamicMapServiceLayer, SimpleFillSymbol, SimpleLineSymbol,
          IdentifyTask, IdentifyParameters, on, parser, Color, registry
        ) {

          parser.parse();

          var identifyTask, identifyParams;

            map.on("load", initFunctionality);

            var landBaseLayer = new ArcGISDynamicMapServiceLayer("https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServe...", {
              opacity: 0.2
            });
            map.infoWindow.on("show", function () {
              registry.byId("tabs").resize();
            });
            map.addLayer(landBaseLayer);

          function initFunctionality () {
            map.on("click", doIdentify);
               console.log("GOT HERE");
            identifyTask = new IdentifyTask("https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServe...");

            identifyParams = new IdentifyParameters();
            identifyParams.tolerance = 3;
            identifyParams.returnGeometry = true;
            identifyParams.layerIds = [0, 2];
            identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
            identifyParams.width = map.width;
            identifyParams.height = map.height;

            map.infoWindow.resize(415, 200);
            map.infoWindow.setContent(registry.byId("tabs").domNode);
            map.infoWindow.setTitle("Identify Results");

            symbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
              new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                new Color([255, 0, 0]), 2),
              new Color([255, 255, 0, 0.25]));
          }

          function doIdentify (event) {
            map.graphics.clear();
            identifyParams.geometry = event.mapPoint;
            identifyParams.mapExtent = map.extent;
            identifyTask.execute(identifyParams, function (idResults) {
              addToMap(idResults, event);
            });
          }

          function addToMap (idResults, event) {
            bldgResults = { displayFieldName: null, features: [] };
            parcelResults = { displayFieldName: null, features: [] };

            for (var i = 0, il = idResults.length; i < il; i++) {
              var idResult = idResults[i];
              if (idResult.layerId === 0) {
                if (!bldgResults.displayFieldName) { bldgResults.displayFieldName = idResult.displayFieldName; }
                bldgResults.features.push(idResult.feature);
              }
              else if (idResult.layerId === 2) {
                if (!parcelResults.displayFieldName) { parcelResults.displayFieldName = idResult.displayFieldName; }
                parcelResults.features.push(idResult.feature);
              }
            }
            registry.byId("bldgTab").set("content", buildingResultTabContent(bldgResults));
            registry.byId("parcelTab").set("content", parcelResultTabContent(parcelResults));

            map.infoWindow.show(event.screenPoint,
              map.getInfoWindowAnchor(event.screenPoint));
          }

          function buildingResultTabContent (results) {
            var template = "";
            var features = results.features;

                template += "<i>Total features returned: " + features.length + "</i>";
                template += "<table border='1'>";
                template += "<tr><th>ID</th><th>Address</th></tr>";

                var parcelId;
                var fullSiteAddress;
                for (var i = 0, il = features.length; i < il; i++) {
                  parcelId = features[i].attributes['PARCELID'];
                  fullSiteAddress = features[i].attributes['Full Site Address'];

                  template += "<tr>";
                  template += "<td>" + parcelId + " <a href='#' onclick='showFeature(bldgResults.features[" + i + "]); return false;'>(show)</a></td>";
                  template += "<td>" + fullSiteAddress + "</td>";
                  template += "</tr>";
                }

                template += "</table>";

            return template;
          }

          function parcelResultTabContent (results) {
            var template = "";
            var features = results.features;

            template = "<i>Total features returned: " + features.length + "</i>";
            template += "<table border='1'>";
            template += "<tr><th>ID</th><th>Year Built</th><th>School District</th><th>Description</th></tr>";

            var parcelIdNumber;
            var residentialYearBuilt;
            var schoolDistrictDescription;
            var propertyDescription;
            for (var i = 0, il = features.length; i < il; i++) {
              parcelIdNumber = features[i].attributes['Parcel Identification Number'];
              residentialYearBuilt = features[i].attributes['Residential Year Built'];
              schoolDistrictDescription = features[i].attributes['School District Description'];
              propertyDescription = features[i].attributes['Property Description'];

              template += "<tr>";
              template += "<td>" + parcelIdNumber + " <a href='#' onclick='showFeature(parcelResults.features[" + i + "]); return false;'>(show)</a></td>";
              template += "<td>" + residentialYearBuilt + "</td>";
              template += "<td>" + schoolDistrictDescription + "</td>";
              template += "<td>" + propertyDescription + "</td>";
              template += "</tr>";
            }

            template += "</table>";

            return template;
          }
        });

      function showFeature (feature) {
        map.graphics.clear();
        feature.setSymbol(symbol);
        map.graphics.add(feature);
      }

I add the map to the page in index.html like this:

<!DOCTYPE html>
<html dir="ltr">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
 <link rel="stylesheet" href="https://js.arcgis.com/3.17/dijit/themes/claro/claro.css">
 <link rel="stylesheet" href="https://js.arcgis.com/3.17/esri/css/esri.css">
 <link rel="stylesheet" href="https://js.arcgis.com/3.18/dojox/layout/resources/ExpandoPane.css">
 <link rel="stylesheet" href="css/widget_styles.css">

<script>
 var dojoConfig = {
 //parseOnLoad: true,
 packages: [
 {
 name: "agsjs",
 //location: location.pathname.replace(/\/[^/]+$/, "") + '../../agsjs'
 "location": '/SPE_SIG/agsjs' // for xdomain load
 }]
 };
 </script>

<script src="https://js.arcgis.com/3.17/"></script>


 

<script src="js/Map.js"></script>
<script src="js/Legend.js"></script>
<script src="js/Search.js"></script>
<script src="js/Identify.js"></script>

<script type="text/javascript">
 dojo.require("dojox.layout.ExpandoPane");
 </script>
 
</head>

<body class="claro">

<div id="content"
 data-dojo-type="dijit/layout/BorderContainer"
 data-dojo-props="design:'headline', gutters:true"
 style="width: 100%; height: 100%; margin: 0;">

<div id="rightPane"
 data-dojo-type="dojox/layout/ExpandoPane"
 data-dojo-props="region:'right',title:'Widgets',startExpanded:false">

<div data-dojo-type="dijit/layout/AccordionContainer">
 <div data-dojo-type="dijit/layout/ContentPane" id="legendPane"
 data-dojo-props="title:'Légende', selected:true">
 <div id="legendDiv"></div>
 </div>
 <div data-dojo-type="dijit/layout/ContentPane"
 data-dojo-props="title:'Pane 2'">
 </div>
 </div>
 </div>

<div id="map"
 data-dojo-type="dijit/layout/ContentPane"
 data-dojo-props="region:'center'"
 style="overflow: hidden;width: 100%; height: 100%; margin: 0;">
 </div>
 <div id="search"></div>
 </div>

</body>

</html>
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Nhu,

   I would suggest just calling initFunctionality();

instead of 

map.on("load", initFunctionality);

as I believe that the map is already loaded before your Identify.js is loaded.

View solution in original post

0 Kudos
10 Replies
RobertScheitlin__GISP
MVP Emeritus

Nhu,

  The map object in your Identify.js is null. Just because you have a require for the map class in your Identify.js does not mean that you have passed the actual map object to your Identify.js. You need to create a variable in your Identify.js for the map and pass the map object from your main js code that uses the Identify.js, so that it can know what the map object is. 

0 Kudos
NhuMai
by
New Contributor II

My intended map object is created in Map.js as var map;

Doesn't this mean that this is a global variable, able to be used in all js files?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Nhu,

 No as your Identify.js module is in a completely different scope it does not have access to the map object. You need to pass the map object to the Identify.js. This is normally done using a constructor method when using dojo/_WidgetBase require.

Something like:

define([
        "dojo/_base/declare",
        "dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dijit/_OnDijitClickMixin",
        "dojo/dom-style",
        "dojo/text!./templates/Census.html",
        "esri/tasks/IdentifyParameters",
        "esri/tasks/IdentifyTask",
        "esri/InfoTemplate",
        "dojo/on",
        "dojo/_base/lang",
        "dojo/dom"
    ],
    function(declare, _WidgetBase, _TemplatedMixin,
        _OnDijitClickMixin, domStyle, dijitTemplate, IdentifyParameters, IdentifyTask,
        InfoTemplate, on, lang, dom) {
        return declare([_WidgetBase, _TemplatedMixin, _OnDijitClickMixin], {
            baseClass: "y2k-census",
            templateString: dijitTemplate,
            constructor: function(options, srcRefNode) {
                console.log("we are in constructor ");
                if (typeof srcRefNode === "string") {
                    srcRefNode = dom.byId(srcRefNode);
                }
                this.map = options.map || null;
                this.domNode = srcRefNode;
            },
0 Kudos
NhuMai
by
New Contributor II

Okay, i think I see what you mean. In your example, what is the "options" parameter from the constructor function referring to? Adapted to my case, I would need to define the constructor for a map object within the map.js file? I'm still not sure how to access the object from identify.js after doing that.

Originally, I was following this example to externalize the map function. How is the global map variable different in their case than mine? 

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Nhu,

Sorry I did not understand your code initially. The issue with your code is you are trying to call initFunctionality on map load but the map is already loaded be you get to your Identify.js code and thus the function is never called. You need to use

map.on("layers-add-result", initFunctionality);

and

map.addLayers([landBaseLayer]);
0 Kudos
NhuMai
by
New Contributor II

Robert,

Thank you for the quick response. Unfortunately, that's still not doing it--the function still isn't connected using the layers-add-result signal. I've also tried to reorder the script imports like this, so that the initFunctionality is already defined when the map layers are added in Map.js :

<script src="js/Identify.js"></script>
<script src="js/Map.js"></script>
<script src="js/Legend.js"></script>
<script src="js/Search.js"></script>

I do wonder if you were on to something, however, with the map object being out of scope. I'm not entirely sure if it's linked to the Identify code, but I do get a TypeError: map is not defined from time to time. Refreshing the page sometimes does the trick..but I have no idea what is causing it.  Would you be interested in looking at the code in depth on github?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

sure

0 Kudos
NhuMai
by
New Contributor II

I sent you an invitation--the branch we've been discussing is called Identify. I've realized that the print branch also causes this typeerror: map is undefined from time to time as well, which is why I'm almost certain this is not directly caused by the identify code.

 

Mahalo

0 Kudos
NhuMai
by
New Contributor II

Checkout branch ID_Mult, actually. Unless you'd already taken a look at the other. Many thanks, by the way.

0 Kudos