Query, highlight, zoom and center on feature

9508
17
07-30-2017 09:25 PM
KirstenFrost_Andersen
New Contributor III

Need a little guidance for an ArcGIS for JavaScript newbie.

I have a custom set of layers from a MapImageLayer displaying over an ESRI basemap.  I'm trying to take a parameter from the URL (in this case a unique parcel number) and find it in a layer (in this case Parcels layer), highlight that feature, zoom to it and center the map on it.  A colleague did that in JavaScript 3.16, however I'm using JS 4.4 and the methods and objects have changed a bit.  Below is a subset of my code that was pulled from the JS 3.16 example and I've been trying to massage it into something useful in JS 4.4.  The object graphicsUtils doesn't appear to exist in 4.4, the query results in a blank map screen, the method setSelectionSymbol breaks my code...  Can anyone give me some sample code I can use to fix this to result in my goals to find the parcel, zoom to, center and highlight it?  Thank you. 

             //Parcel Selection Layer

            parcels = new FeatureLayer("http://[myServer]/arcgis/rest/services/[mapservicename]/MapServer/0", {
                 outFields: ["*"],
                 //Needs to be Selection Mode, on demand results in odd parcel shapes
                 mode: FeatureLayer.MODE_SELECTION
             });

             parcels.setSelectionSymbol(sfs); //sfs = simplefillsymbol
             map.addLayers([parcels]);

             var parcelid = document.getElementById("<%= hfParcel.ClientID%>").value;// prompt("Give me input");
             selectParcel(parcelid);

             //select parcel from the feature layer by creating a query to look for the input parcel id
             function selectParcel(parcelid) {
                 if (parcelid) {
                     var query = new Query();
                     query.where = "PID_NUM = '" + parcelid + "'";
                     var deferred = parcels.selectFeatures(query, FeatureLayer.SELECTION_NEW, function (selection) {
                         var center = graphicsUtils.graphicsExtent(selection).getCenter();
                         var extent = esri.graphicsExtent(selection);
                         var extHandler = map.on("extent-change", function () {
                             extHandler.remove();
                             //zoom to the center then display the popup
                             map.infoWindow.setFeatures(selection);
                         });
                         map.setExtent(extent.getExtent().expand(2));
                         map.centerAt(center);
                     });
                 }
             }

0 Kudos
17 Replies
KirstenFrost_Andersen
New Contributor III

Here's what the app that is querying properly in JS 3.16 shows for that query URL: 

http://[myServer]/arcgis/rest/services/[myMapServiceName]/MapServer/0/query?f=json&where=PID_NUM%20%...

0 Kudos
KenBuja
MVP Esteemed Contributor

Here's an example using the Chrome debugging tools. I put a breakpoint at line 185 and clicked the Do Query button in the sample. The code halts before running the query and I can see (and copy) the whereclause when I hover the cursor over params.where line. Or you could add the line "console.log(query.where);" to write it to the console. This can then be used in the REST endpoint query to see if it works.

0 Kudos
KirstenFrost_Andersen
New Contributor III

I see.  Thank you.

So here's what DT says with JS 3.16, which is working:

Here's what DT says with my code in JS 4.4, which is failing to execute:

Here is that where clause in the rest endpoint query:

0 Kudos
KirstenFrost_Andersen
New Contributor III

Now that I think on this, the JS 3.16 is actually selecting from a feature service.  It's using query.where, but not querying the rest endpoint in the same way.  I wonder if I need to set up the rest URL differently to allow it to be queried against. 

0 Kudos
DavidColey
Frequent Contributor

Hi Kirsten, if I may we've been doing something similar since about 3.7:

function showZones(evt) {
    mapMain.graphics.clear();
    if (evt.source.name == "Search by House Address" || evt.source.name == "Search by Street Address") {
       qPoint = evt.result.feature.geometry;
       var queryElemZones = new Query;
       queryElemZones.geometry = qPoint;
 
    var elemQuery = lyrElemZones.selectFeatures(queryElemZones,FeatureLayer.SELECTION_NEW);
    mapMain.infoWindow.setFeatures([elemQuery]);
    mapMain.infoWindow.show(qPoint);
   elemQuery = lyrElemZones.selectFeatures(queryElemZones,FeatureLayer.SELECTION_SUBTRACT);
 }

This shows how we take the return geometry from an returned address and then use that to select the intersecting features, in this case a school zone.  Set the features in the infoWindow and show the window at the point return location.

For 4.x, selectFeature method is not yet available for feature layer so the only option is to employ a queryFeatures method, something I'm still working on.  Here, we are using an address return point as an input to a buffer, then using the extent of the buffer to intersect and return features:

function showResults(evt) {
    app.activeView.graphics.clear;
    console.log(app.search.sources);
 
    if (app.search.sources.items[0].name == "Search by Address") {
       console.log(app.search.sources);
 
       var qPoint = evt.results[0].results[0].feature.geometry;
       console.log(qPoint);
 
       buffer = geometryEngine.geodesicBuffer(qPoint, [1], 9035, true); 
       var symbol = new SimpleFillSymbol({
          color: [100,100,100,0.15],
          style: "solid",
          outline: { // autocasts as esri/symbols/SimpleLineSymbol
             color: "white",
             width: 0
          }
       });
   graphicPoly = new Graphic({
       geometry: buffer, 
       symbol: symbol,
    });
    app.activeView.graphics.add(graphicPoly); //geometry 
 
    var queryTran = new Query;
    queryTran.geometry = buffer;
    queryTran.spatialRelationship = "intersects";
    //queryTran.where = ObjectID > 0 //Don't really need this since we're using the spatial relationship
 
    var tranQuery = lyrMobBnds.queryFeatures(queryTran).then(function(tranResult) { //,    FeatureLayer.SELECTION_NEW);
    console.log(tranResult); //Does get features! Can't seem to set the attributes in the popup though
    if (tranResult && tranResult.features.length > 0) {
       app.activeView.popup.open({
       features: tranResult.features,
       location: qPoint//result.geometry.centroid
          });
       }
    });
    }
}

But I can't seem to figure out how to pass the results' return array and set that in my popup as opposed to the search result's return address.  I don't know if this will help you but maybe if there are more eyes on this some will have some ideas.

0 Kudos
KirstenFrost_Andersen
New Contributor III

Hi David,

Thank  you for the response!  I'm still banging my head against a wall with this, even after trying to make your example work with my code.  It simply doesn't want to work.  I'm considering demoting my JavaScript version back to something where I have .selectFeatures and highlighting, since querying doesn't seem to work with my map service at all even at the REST url.  I appreciate the advice you offered!

0 Kudos
DavidColey
Frequent Contributor

Sure.  As I recall we had difficulties with the logic for this type of "near me" workflow using queryFeature at 3.x which is why we went to the selectFeature method in the first place.  My goal above at 4.x isn't to necessarily highlight the intersecting features (but I do want to do that), but rather to pass the results into the popup. I think I have to find a way to clear the address info from the popup first before it can be reset with the returns from the queryFeauure array . . . 

KirstenFrost_Andersen
New Contributor III

I am still trying every which way from Sunday to make this work and keep hitting walls.  I'm now able to run the query from the REST and here is the JSON result:

Here is my code that is failing:

 

var upadalLayers = new MapImageLayer({
   url:  "http://[myServer]/arcgis/rest/services/EnvironmentalServices/UPadal_MiniMap/MapServer"
  });
  
  var parcelLayer = new FeatureLayer("http://[myServer]/arcgis/rest/services/EnvironmentalServices/UPadal_MiniMap/MapServer/41",
  {
   mode: FeatureLayer.MODE_SELECTION,
   outFields: ["*"]
  });
    
  var map = new Map({
   basemap: "topo",
   layers: [upadalLayers, parcelLayer]
  })

  var view = new MapView({
   container: "viewDiv",
   map: map,
   zoom: 10,
   center: [-117.42, 47.65]
  })


  var urlParams = urlUtils.urlToObject(document.URL);
  if (urlParams.query){
   var urlParcelIDParam = parseFloat(urlParams.query.PID);
   selectParcel(urlParcelIDParam);
  }

  function selectParcel(urlParcelIDParam) {
   if (urlParcelIDParam) {
    var queryParcelsTask = new QueryParcelsTask({
     URL: parcelLayer.URL
    });
    var query = new Query();
    query.where = "PID_NUM = '" + urlParcelIDParam + "'";
    query.returnGeometry = true;
    query.outFields = "PID_NUM";
    
    queryParcelsTask.execute(query).then(zoomparcel);
  } 


  function zoomparcel(result) {
   var AOI = result.features;
   view.goTo(AOI);
  }

Here is the Developer Tools/F12 result that says nothing about my query, but still doesn't zoom to the parcel -- i get the same results when I throw in Ken's example for the promise:

I've tried FeatureLayer.createQuery() or FeatureLayer.queryFeatures() and get nowhere. I've tried converting to JS 3.16, 3.21 and 4.3; I couldn't get the map to even display with the first two and had troubles finding documentation for 4.3.  I'm back on 4.4 at the moment.  Any other suggestions?  I've been told I need to find a way to just select from the existing layer in the map rather than querying, but from all examples, it looks like that's what's being done here with the newer QueryTask library and the REST query is working which I'm trying to emulate in code. 

0 Kudos