How to perform a spatial query on map service from Identify widget

3425
8
09-09-2015 12:45 PM
DouglasGuess
Occasional Contributor

I'm utilizing Robert Scheitlin's Identify widget and I'm trying to query another map service based on each result items feature centerpoint to return attributes from the map service to be used as parameters in a link within each identify result.  I have the link params established within the identify_config file with the "content" element set to " ", which will be populated once the spatial query is complete with the appropriate values.  What I have so far is that when the user Identify's for the first time, the spatial query values are null.  When the user performs another Identify, the query values are now populated, however, they are from the previous Identify result.  Also, if the user selects any other Identify geometry other than "point", it doesn't work. 

In my old flex app, I was able to achieve this when the user clicked on the link within the identify result item.  With that, it would grab the items centerpoint and use that as query geometry for the specific map service.  The query was an AsyncResponder (asynchronous) function and would then loop through the designated outFields to populate params and update the url used for the link.  Since javascript is not asynchronous, I'm not quite sure how to implement this correctly.

I currently have my code placed within the showIdentifyResults() function which calls another function (_queryFeatureSub) and passes the identifyGeom parameter.  Within the _queryFeatureSub() function is where I query the map service via QueryTask and loop through the attributes to pull the data I need.  Later in the showIdentifyResults() function, I loop through the idResult.links, find the specific link I need, and update it with the specific link url populated from the query params.

I think I might need to use Deferred() but not quite sure how to implement this.  Or, I might be totally wrong with my thought process.  If anyone has some thoughts or input, I'd really appreciate it!

Thanks

Tags (2)
0 Kudos
8 Replies
RobertScheitlin__GISP
MVP Emeritus

Douglas,

  Yes Deffered/promisses are the way to go. If you look at the identifyFeatures function you will see that I use promises there:

this.shelter.show(); ///This is a busy indicator that covers the widget
var tasks = array.map(featureLayers, lang.hitch(this, function (layer) {
          return new QueryTask(layer.url);
        }));
var promises = [];
for (var i = 0; i < tasks.length; i++) {
          promises.push(tasks.execute(params));
        }
var qPromises = new all(promises);
qPromises.then(lang.hitch(this, function (r) {
          //do something now that the promises is done
          //work with r which would be your query result
        }), lang.hitch(this, function (err){
          console.info(err);
        }));
var tPromises = [qPromises];
var allPromises = new all(tPromises);
allPromises.then(lang.hitch(this, function (r) {
         //do something now that all the promises are done
         this.shelter.hide();
}
0 Kudos
DouglasGuess
Occasional Contributor

Thanks for the reply Robert.  So would it make sense to utilize the promise within the showIdentifyResults() function?  That way for each result item, a query could be performed on the map service to return values and update the idResult.links url link?

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

yes

0 Kudos
DouglasGuess
Occasional Contributor

Robert, I've implemented "promise" and everything is querying as expected; however, the link is not being updated before the identify result item is added to the list.  I placed my code within the if(identLinks && identLinks.length) statement within the showIdentifyResults() function.  My code is below.  Is there something else I need to do to populate the link before the result item is added to the results list?

var queryPt;
            if(this.identifyGeom.type === 'point'){
               queryPt = this.identifyGeom;
             }else{
               queryPt = (this.returngeometryforzoom) ? this.getGeomCenter(identifyResult.feature.geometry) : this.getGeomCenter(this.identifyGeom);
             }
             
             // Query map service to populate link url
             if (identLinks.alias === "Deed Information"){
              var qTasks = array.map(this.configDeedLayers, lang.hitch(this, function (layer) {
           return new QueryTask(layer.url + "/" + layer.id);
         }));
             var qParams = this.createDeedQueryParams(this.configDeedLayers, queryPt);
             var promises = [];
             for (var i = 0; i < qTasks.length; i++) {  
      promises.push(qTasks.execute(qParams));
      }
      var qPromises = new all(promises);  
  qPromises.then(lang.hitch(this, function (results) {  
           //work with "results" which would be your query result  
           var subLyrId, lotNum, blkNum, secVal, townVal, rngVal, featAttr, attr, f, r;
        var resultCount = results.length;
        if (resultCount > 0){
        this.subAvailable = true;
        for (r = 0; r < resultCount; r++){
        var displayName = results.displayFieldName;
        switch (displayName){
        case "Subname":{
        for (f = 0; f < results.features.length; f++){
        featAttr = results.features.attributes;
        for (attr in featAttr){
          if (attr === "RODSUBID"){
          subLyrId = featAttr[attr];
          this.deedURL = this.deedURL + "?subid=[subvalue]";
          this.deedURL = this.deedURL.replace("[subvalue]", subLyrId);
          }
          }
        }
        break;
        }
        case "LOT": {
        for (var f = 0; f < results.features.length; f++){
        featAttr = results.features.attributes;
        for (attr in featAttr){
          if (attr === "LOT"){
          lotNum = featAttr[attr];
          this.deedURL = this.deedURL + "&lot=[lotvalue]";
          this.deedURL = this.deedURL.replace("[lotvalue]", lotNum);
          }
          if (attr === "BLOCK"){
          blkNum = featAttr[attr];
          this.deedURL = this.deedURL + "&block=[blkvalue]";
          this.deedURL = this.deedURL.replace("[blkvalue]", blkNum);
          }
          }
        }
        break;
        }
       
        }
          }
          //identLinks.content = this.deedURL;
          link = this.deedURL;
        }else{
        this.subAvailable = false;
        }
         }), lang.hitch(this, function (err){  
           console.info(err);  
         })); 
             }
0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Douglas,

   This is a tricky situation as the JS code is still asynchronous and will not wait for the promises based on the outer structure of my identify code. I am not sure what the answer is without re-writing the widgets workflow to wait before adding to the list.

I would try to keep a reference to the idResult object and see if you can change the link once the queries are done.

Something like: idResult.links.link = yourlinkhere;

That would mean you need to pass the idResult and the "a" from the for loop into your qPromises.then function.

0 Kudos
DouglasGuess
Occasional Contributor

Robert,

I tried what you suggested and I couldn't get it to work as the dom is already populated with the blank link when the list.add function gets called.  I then tried to update the specific dom element with the newly populated link from the query results...it works if the Identify geometry is "point", and then I even have to click on the link twice for it to navigate to the new url.  If the Identify geom is anything but "point", it doesn't work at all.  I've been spinning my wheels on this for a week now.  Do you have any thoughts/suggestions on how to achieve this?  You mentioned re-writing the widgets workflow to wait until the spatial query is complete.  Any thoughts on that???  I'm really in a bind and any input would be really appreciated!

Thanks,

Doug

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Doug,

   Unfortunately none right now. Like I mentioned it would be a total re-write of the showIdentifyResults function which I have not even begun to think about as your work flow is pretty specific to your needs. Sorry I can not be of more help.

0 Kudos
DouglasGuess
Occasional Contributor

Thanks Robert.  Last night I actually thought of some things to try so I'll give them a shot.

Thanks for your input.

0 Kudos