Search Widget Results - Not Cleared from infoWindow

3234
6
09-03-2015 10:34 AM
DavidColey
Frequent Contributor

So for the past 2 years or so we've been using our local point locator in the geocoder widget as a way to fire a query function that returns geometry and atttibute results from the task.  For example, when using a geocoder we tell the on select event to to fire a 'showLocation' function that takes the sr and geometry from the geocoded point, creates and sets a graphic point to the event, adds it to the map.   We then assign that geometry to a query that performs a select with whatever feature layer or layers we choose then pass the query results into the maps' infowindow (we use a modified side-panel popup instead of the defualt):

var locatorUrl = "https://ags2.scgov.net/arcgis/rest/services/WebPointLocator/GeocodeServer";
var scgGeocoder = [{
     url: locatorUrl,
     name: "WebPointLocator",
     singleLneFieldName: "Single Line Input",
     placeholder: "Find an Address"
}];
var geocoder = new Geocoder({
     map : mapMain,
     autoComplete : true,
     autoNavigate : false,
     arcgisGeocoder : false,
     geocoders : scgGeocoder

}, dom.byId("divSearch"));

function showLocation(event) {
     mapMain.graphics.clear();
     qPoint = event.result.feature.geometry;

     var ptSymbol = new SimpleMarkerSymbol().setStyle(
          SimpleMarkerSymbol.STYLE_SQUARE).setColor(
          new Color([255,0,0,0.5])
     );
     var graphicPoint = new Graphic(qPoint, ptSymbol);
     mapMain.graphics.add(graphicPoint);

     var queryParcels = new Query;
     queryParcels.geometry =  qPoint;

     var parQuery = lyrParcels.selectFeatures(queryParcels,FeatureLayer.SELECTION_NEW); //is a deferred
          mapMain.infoWindow.setFeatures([parQuery]); //comment out if passing query result to next function
          mapMain.infoWindow.show(qPoint); //comment out if passing query result to next function
//center
     if (qPoint !== undefined) {
          mapMain.centerAndZoom(qPoint, 13); //7 for sph
          mapMain.graphics.redraw();
     }
     lyrParcels.on("selection-complete", showZones);
}

Suppose we want to return not only the parcels geometery and attributes, but also the geometry and atributes from whatever

layers that parcel intersects. We simply comment out the infowindow and add an on selection-complete event for our parcels layer

and pass the reuslts into a second query function that uses the extent of the selected poly.  In this case we are using the parcel extent to return whatever floodzone(s) intersect:

function showZones(results) {
     qPoly = results.features[0].geometry;
     // results of first layer returned by point intersect query above
     console.log(qPoly);
     var queryNewZones = new Query;
     queryNewZones.geometry = qPoly.getExtent();
     //.getCenter(); if returning a grid poly
     var newFloodQuery = lyrNewZones.selectFeatures(queryNewZones, FeatureLayer.SELECTION_NEW);

     var queryNewFirm = new Query;
     queryNewFirm.geometry = qPoly.getExtent();
     //evt.result.feature.geometry;
     var newFirmQuery = lyrNewFirm.selectFeatures(queryNewFirm, FeatureLayer.SELECTION_NEW);
     //deferred evacQuery

     mapMain.infoWindow.setFeatures([parQuery, newFloodQuery, newFirmQuery]); //parQuery
     mapMain.infoWindow.show(qPoint);
     //show the parcel
     mapMain.infoWindow.show(qPoly);
     //show the zones - complete the loop
     lyrNewZones.on("selection-complete", returnNull);

}


function returnNull() {
     var retVal = null;
}

Pretty straightfoward (now - not initally!).  Here is a fully working app if you want to see it:

https://ags2.scgov.net/SarcoFlood/

you can use 1660 Ringling Blvd as the address.

Here is our problem:

We want to update this workflow to take advantage of the new search widget so that users can search not only by address but say also by a PID. Of course the search has different on events, but the main problem is that when using the feature layer source as the searchs' activeSource, the result from the first query is not cleared from our info window even though the first query's geometry and attributes are removed. Console logs do show that a new parcel has been selected.  The problem does not occur when the activeSource comes from our locator.

This is what @michael Stranovsky and I have come up with so far:

/*Search */
var s = new Search({
     enableButtonMode: true, //this enables the search widget to display as a single button
     enableLabel: false,
     enableInfoWindow: true,
     showInfoWindowOnSelect: true,
     map: mapMain,
     sources: []
}, "divSearch"); 

var sources = s.get("sources");

sources.push({
     locator: new Locator("https://ags2.scgov.net/arcgis/rest/services/WebPointLocator/GeocodeServer"),
     singleLineFieldName: "Single Line Input", 
     name: "Search by Address",
     localSearchOptions: {
     minScale: 300000,
     distance: 10
     },
     placeholder: "Search by Address",
     maxResults: 3,
     maxSuggestions: 8,
     enableSuggestions: true,
     minCharacters: 0,
         
});

sources.push({
     featureLayer: lyrParcels,
     searchFields: ["ACCOUNT"],
     displayField: "ACCOUNT",
     exactMatch: false,
     outFields: ["ACCOUNT", "Shape_Area"],
     name: "Search by PID",
     placeholder: "ex: 2027070041",
     maxResults: 6,
     maxSuggestions: 6,
        
     //Create an InfoTemplate and include three fields
     infoTemplate: plyParcels, //defined previously
     enableSuggestions: false,
     minCharacters: 0
});
   
//Set the sources above to the search widget
s.set("sources", sources);
s.startup();

console.log(sources);
s.on("select-result", showZones);

In this case we use the searches' on select-result event to pass in the gemoetry but things get really complicated because we first havet to account for the activeSource - whether from a locator or a featureLayer - and the fact that the search widget is (1) already creating a point graphic if a locator source and (2) that the search is already performing a find and query tasks (I think).

Here, when the source is our parcel feature layer, we are essentially performing the query twice as the search is already performing it once.  When we tried setting the evt geometry to the extent of the return itself, the querys' default intersects method returned several parcels, so we set the return to get the center of the extent, and then perform both the parcel and intersecting layer query and display the results:

function showZones(evt) {
     //lyrParcels.clearSelection();   
     mapMain.infoWindow.clearFeatures();
     //mapMain.infoWindow.setFeatures([]);  
     //qPoint = null;  
     //qPoly = null;   
     //lyrParcels.clearSelection();
   
     if (s.activeSource.name == "Search by PID") {
          //console.log(evt);               
          qPoly = evt.result.feature.geometry;      
       ///qPoint = evt.result.extent.getCenter();
          //console.log("qPoint Parcel: ");            
          //console.log(qPoint);
   
          var queryParcels = new Query;
               queryParcels.geometry = qPoint;
          var parQuery = lyrParcels.selectFeatures(queryParcels, FeatureLayer.SELECTION_NEW);
               console.log(parQuery); 
           
         var queryNewZones = new Query;
              queryNewZones.geometry = qPoly.getExtent();
         var newFloodQuery = lyrNewZones.selectFeatures(queryNewZones, FeatureLayer.SELECTION_NEW);
               mapMain.infoWindow.setFeatures([parQuery, newFloodQuery]);
               mapMain.infoWindow.show(qPoly);  
               //console.log(lyrParcels.getSelectedFeatures());
               //console.log(results);
     } else if (s.activeSource.name == "Search by Address") {
          //console.log(evt);
          qPoint = evt.result.feature.geometry;
           //console.log("qPoint Address: ");
           //console.log(qPoint);
          var queryParcels = new Query;
                queryParcels.geometry = qPoint;
          var addQuery = lyrParcels.selectFeatures(queryParcels, FeatureLayer.SELECTION_NEW);
               console.log(addQuery);            
          /*parQuery.then(function(features){
               console.log("select features result: ", features);
               qPoly = features[0].geometry;
               console.log(qPoly);
          });*/
     //var qPoly = lyrParcels.on("selection-complete", getParcelExtent);
     //console.log(qPoly):                    
    lyrParcels.on("selection-complete", function (result){
        qPoly = result.features[0].geometry;
        var queryNewZones = new Query;
        queryNewZones.geometry = qPoly;     
         var newFloodQuery = lyrNewZones.selectFeatures(queryNewZones, FeatureLayer.SELECTION_NEW);
         
     mapMain.infoWindow.setFeatures([addQuery, newFloodQuery]);
     mapMain.infoWindow.show(qPoly); //previous addQuery
     });

     //var queryNewZones = new Query;        
     //queryNewZones.geometry = pPoly    
     //var newFloodQuery = lyrNewZones.selectFeatures(queryNewZones, FeatureLayer.SELECTION_NEW);          
     //var addQ = [parQuery, newFloodQuery];
     //console.log(lyrParcels.getSelectedFeatures());
     //mapMain.infoWindow.setFeatures([parQuery, newFloodQuery]); 
     //newFloodQuery   
     //mapMain.infoWindow.show(qPoint);
     } else {
          console.log("In else");
     }     
}     

Again, the result from the first query is not cleared from our info window dispaly even though the first query's geometry and attributes are removed. Console logs do show that a new parcel has been selected.  The first-result of the parcel query and does clear from the infoWindow display when we enter an address and then enter a subsequent address.  The first-result does

This post is related to:

How can I use a variable that is set in a function on an on event outside of the event?

posted by @michael Stranovsky just the other day in that he is trying to figure out if it is a scope issue that is preventing the infoWindow from clearing the displayed result-

Thanks-

David

6 Replies
thejuskambi
Occasional Contributor III

I found something, l feel it is wrong. Please verify the same. In the below code you are setting  the queryParcels.geometrty = qPoint.  shouldn't you be using qPoly.

  1. if (s.activeSource.name == "Search by PID") { 
  2. //console.log(evt);               
  3.           qPoly = evt.result.feature.geometry;      
  4. ///qPoint = evt.result.extent.getCenter(); 
  5. //console.log("qPoint Parcel: ");             
  6. //console.log(qPoint); 
  7. var queryParcels = new Query; 
  8.               queryParcels.geometry = qPoint;
  9. var parQuery = lyrParcels.selectFeatures(queryParcels, FeatureLayer.SELECTION_NEW); 
  10.               console.log(parQuery);
DavidColey
Frequent Contributor

I think you're right, let me run a test on that and get back to you

0 Kudos
DavidColey
Frequent Contributor

Thejus-

Actually the qPoint is correct.  I mistakenly commented out this line:

//qPoint = evt.result.extent.getCenter(); //feature

where we are setting the geometry to get the center of the extent of the parcel poly feature because when use the geometry of the poly we were also getting coincident neighboring parcels returned in our selection.  We could set up and use something other than the default intersect method later.

0 Kudos
thejuskambi
Occasional Contributor III

Also when you are listening for an event. It will continue to listen till you remove it or the object is destroyed. In your case lyrParcels selection-complete event. If you want it to execute one time then you should use on.once or remove the handler after if has executed.

DavidColey
Frequent Contributor

ok thanks again Thejus -- something came up I'll get back on this tomorrow and post up what we find...

0 Kudos
DavidColey
Frequent Contributor

Ok we made some real progress here, let me see if I can describe what's going on:

function showZones(evt) {
     mapMain.infoWindow.clearFeatures();
     if (evt.source.name == "Search by PID") {
          //console.log(evt);         
          qPoly = evt.result.feature.geometry;
          qPoint = evt.result.extent.getCenter(); //feature

          //console.log(qPoint);
          var queryParcels = new Query;
          queryParcels.geometry =  qPoint; //qpoly;
          var parQuery = lyrParcels.selectFeatures(queryParcels, FeatureLayer.SELECTION_NEW);
      
          lyrParcels.on("selection-complete", function (result){
               var queryNewZones = new Query;
               queryNewZones.geometry = qPoly.getExtent();
               var newFloodQuery = lyrNewZones.selectFeatures(queryNewZones, FeatureLayer.SELECTION_NEW);
            
               mapMain.infoWindow.setFeatures([parQuery, newFloodQuery]);
               mapMain.infoWindow.show(qPoly);
          });

     } else if (evt.source.name == "Search by Address") {
          //console.log(evt);
     
          qPoint = evt.result.feature.geometry;
          var queryParcels = new Query;
          queryParcels.geometry = qPoint;
          var addQuery = lyrParcels.selectFeatures(queryParcels, FeatureLayer.SELECTION_NEW);
          console.log(addQuery);
           
          lyrParcels.on("selection-complete", function (result){
               qPoly = result.features[0].geometry;
               var queryNewZones = new Query;
               queryNewZones.geometry = qPoly;
               var newFloodQuery = lyrNewZones.selectFeatures(queryNewZones, FeatureLayer.SELECTION_NEW);
                
               mapMain.infoWindow.setFeatures([addQuery, newFloodQuery]);
               mapMain.infoWindow.show(qPoly);
          });
            
     } else {
          console.log("In else");
     }     
}

So after the search's on select result event fires fires showZones, it's event is passed into the function, the info window is cleared and then different geometry's are set depeding on the source. 

Regardless of the source, we need both the feature layers' result geometry and the results's geometry center.  When the source is a feature layer (parcel) we get the center because since the search is already returning the poly geometry we have to reset that geometry it's center in order to handle coincident parcels so they won't be returned in the results.

We then take the feature layers' geometry to pass into the on select-complete event newly added in the first if block, where that geometry then performs the second spatial query on whatever you want to intersect.  We don't need to show the qPoint event in the select-complete function because the search widget already has it.

That solved our problem.  Everything worked fine by entering address after address or feature layer attribute after feature layer attribute, but not when we changed sources becasue we did not have anything to specifically handle the result from a feature-layer selection.  We knew we had to have a listener to handle the point select event from an address search result because we had to turn that initial point into it's intersecting poly geometry.

The last change we made was to the event's source.  Instead of using the Search's activeSource.name property, Michael Stranovsky set it to the events source name because if a user didn't specifically pick a source, searche's activeSource.name returned null and thus nothing worked.

Thanks Thejus for event idea, that's what got us thinking.  If we run into any more bugs or unexpected behavior I'll be sure to post back. Lastly, I myself had been working on this problem (that is - migrating our geocoder select functions to the search) off and on since the widget was released.  But it was Michael Stranovsky​ that came up with the handlers.  If I can get this up in a fiddle, I will but moving forward I'd like to turn this into a module and then finally maybe as an extension to the search widget itself for WAB.

David