Select to view content in your preferred language

querytask: executeLastResult vs. AsyncResponder

3911
6
10-07-2010 11:52 AM
CarmenDurham
Frequent Contributor
Okay, this is driving me crazy.  According to what I read, a queryTask.executeLastResult should return a FeatureSet.  I should be able to then use myFeatureSet.features.length to find out how many features were returned .  But it's not working.  However, using the AsyncResponder with an onResult function, works fine.

For example, this querytask using the Asyncresponder will process fine  so I KNOW the querytask works with the queryFloodStudies query (but I can't use the asyncresponder for other reasons):
cityfloodstudiesQueryTask.execute(queryFloodStudies, new AsyncResponder(onCityFloodResult, onCityFloodFault));
      function onCityFloodResult(cityfloodfeatureSet:FeatureSet, token: Object=null):void
      {             
 if(cityfloodfeatureSet.features.length == 0)
   {
      floodZonetext = "The Parcel doesn't touch a 100 or 500 yr Flood Zone" + "\n" + floodVerificationNote;
   }
 else   // did find that parcel intersected a flood poly from the City Flood Studies
 {
 floodZonetext = "This parcel touches a Flood Hazard area";
 }  // end else
        }  //end onresult




But the below code will not.  Compiles fine, but when running, it just hangs at the If statement. What am I missing? 

var cityfloodfeatureSet:FeatureSet;  
cityfloodstudiesQueryTask.execute(queryFloodStudies);
cityfloodfeatureSet = cityfloodstudiesQueryTask.executeLastResult;
  if (cityfloodfeatureSet.features.length == 0)
 {
 floodZonetext = "The Parcel doesn't touch a 100 or 500 yr Flood Zone" + "\n" + floodVerificationNote;
 }
  else   // did find that parcel intersected a flood poly from the City Flood Studies
 {
 floodZonetext = "This parcel touches a flood hazard area";
 }


OR if someone can tell me how to force Flex to WAIT for the AsyncResponder to finish before continuing with the code, that's would help.  This query is nested within another QueryTask's onResult function.

I hope it is something simple that I am missing.  Thanks!
Tags (2)
0 Kudos
6 Replies
ReneRubalcava
Esri Frequent Contributor
Problem is you'll need to use an EventListener or use the AsyncResponder method.
var qt:QueryTask = new QueryTask();
qt.addEventListener(QueryEvent.EXECUTE_COMPLETE, onExecuteComplete);
qt.execute(query);

// somewhere else in your code
private function onExecuteComplete(event:QueryEvent):void {
 // stuff
}


Without them, you have no way of knowing when the query is done.

I'm thinking maybe you need to use the queryTask.executeLastResult somewhere else in the code outside the function, which is why you want to avoid the AsyncResponder method you posted. EventListeners work fine as well.

I never did like the name 'executeLastResult', it's misleading. I'd think it should just be 'lastResult'.
0 Kudos
CarmenDurham
Frequent Contributor
Thanks, this answered the question I had, but didn't solve the overall problem.  I may have to totally change the logic that I am trying to follow. 

It just seems like there should be a way to force one querytask to wait for a nested querytask to complete before continuing.  Anyone know a way that isn't based on a timer?  Or should nested querytasks be totally avoided?

Thanks,
Carmen
0 Kudos
DasaPaddock
Esri Regular Contributor
The *lastResult properties are mostly there for when you just want to bind to them.

Here's some options for controlling what happens when you overlap requests:
http://help.arcgis.com/en/webapi/flex/apiref/com/esri/ags/tasks/BaseTask.html#concurrency

Your best bet is probably to chain requests by making the next call when the first one finishes.
0 Kudos
eddiequinlan
Deactivated User
Hi all,

I've had similar issues like this and have posted questions concerning them; so please be patient with me because I am not understanding the concept.... I guess.

Here's what I'm doing:

I have a featureSet returned from a QueryEvent.... lets say 10 records.  In the QueryEvent complete function I loop thru those records to extract various values from the attribute table.  If the value meets a certain condition, I then run another Query based on that value to return records from that layer/table.  The problem which confuses me, is that the first query run's thru the 10 records and then runs the 2nd Query.  I need the 2nd Query to run when my condition is met; return the value; then continue with the loop in the 1st QueryEvent.....  confusing?


It seems like a simple set of task's, but I am missing something.  Any help would be appreciated.

Sincerely,
Eddie





private function query_SaleTable_complete(qEvt:QueryEvent):void
{
 // example here query found 10 records......
    
 if(qEvt.featureSet.attributes.length > 0)
 { 
  for each (var myGraphic:com.esri.ags.Graphic in qEvt.featureSet.features )
  { 
   // shade returned parcels.........................      
   if(i == 1)
   {
    //Pin of first sale record added to datagrid
    myData.addItem({"SAPROP" : DSPPIN, 
     "SAPRICE" : myGraphic.attributes.SAPRICE, 
     "SARDATE" : myGraphic.attributes.SARDATE});
       
             
    ShadePclQuery.where = "PRCL_PARCE = '" + myGraphic.attributes.SAPROP + "'"; 
     
    ShadePclQueryTask.execute(ShadePclQuery);  //execute 2nd query

    //  I need the myGraphic.attributes.APPRVAL value from function ShadeSelectedPcl returned here
    //    before the next iteration in the for each loop........

    //  so I can do this...........................
    myData.addItem({"SAPROP" : DSPPIN, 
     "SAPRICE" : myGraphic.attributes.SAPRICE, 
     "SARDATE" : myGraphic.attributes.SARDATE,
     "APPRVALUE" : value from ShadeSelectedPcl function});
    
   }
   else if (i > 1)
   {
    // all sales info added to datagrid
    myData.addItem({"SAPRICE" : myGraphic.attributes.SAPRICE, "SARDATE" : myGraphic.attributes.SARDATE});  
   }
      
  }
 }
}

//  listener event on ShadePclQueryTask runs this.........
private function ShadeSelectedPcl(fs:QueryEvent):void
{
 if (fs.featureSet.features.length > 0)
 { 
  for each (var myGraphic:com.esri.ags.Graphic in fs.featureSet.features )
  {        
   myGraphic.symbol = SaleSymbol; 
   SalesGraphicsLayer.add(myGraphic);
      
   trace(myGraphic.attributes.APPRVAL);      
  }
}
0 Kudos
karldailey
Deactivated User
you cant use 'executeComplete'  of the query task to run your function?
0 Kudos
IvanBespalov
Frequent Contributor
eddie,

from your code:
1 - query �?? 1 - params - execute - parse results (for ex. 10 results)
2 - query �?? 2 - params (1 of 10) - execute - parse result - add to graphics layer
3 - query �?? 3 - params (2 of 10) - execute - parse result - add to graphics layer
4 - query �?? 4 - params (3 of 10) - execute - parse result - add to graphics layer
...
~ minimum 11 requests to server, as a result you need to parse minimun 11 responses ... (what happens if first query returns 500 features :cool:)

if you have 2 layers, maximum number of queries is 2, non more:
1 - query �?? 1 - params - execute - parse results (for ex. 10 results) - collect params (where clause, or geometry union ...) for second query - hold result as class vaiable, or use as token in second query
2 - query �?? 2 - collected params - execute - parse result - combine with first query results - add to graphics layer

try it (code is illustrative):
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx"  
      xmlns:ags="http://www.esri.com/2008/ags">
 
 <!-- Adobe Flex SDK 4.6.0 -->
 <!-- ArcGIS API for Flex 2.5 -->
 <!-- http://web.zone.ee/bespiva/ -->
 
 <fx:Script>
  <![CDATA[
   import com.esri.ags.FeatureSet;
   import com.esri.ags.Graphic;
   import com.esri.ags.SpatialReference;
   import com.esri.ags.events.LayerEvent;
   import com.esri.ags.geometry.Extent;
   import com.esri.ags.geometry.Geometry;
   import com.esri.ags.symbols.SimpleFillSymbol;
   import com.esri.ags.symbols.SimpleLineSymbol;
   import com.esri.ags.tasks.QueryTask;
   import com.esri.ags.tasks.supportClasses.Query;
   
   import mx.collections.ArrayCollection;
   import mx.events.FlexEvent;
   import mx.rpc.AsyncResponder;
   import mx.rpc.Fault;
   import mx.utils.StringUtil;
   
   private const FIRST_LAYER_URL:String = "http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Population_by_Sex/MapServer/4";
   private const SECOND_LAYER_URL:String = "http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Tapestry/MapServer/4";
   
   private const SPATIAL_REFERENCE:SpatialReference = new SpatialReference(4326);
   
   [Bindable]
   private var resultsSource:ArrayCollection = new ArrayCollection();
   
   protected function onLayerLoad(event:LayerEvent):void
   {
    trace("onLayerLoad");
    executeFirstQuery();
   }
   
   private function executeFirstQuery():void
   {
    trace("executeFirstQuery");
    var query:Query = new Query();
    query.outFields = new Array("*"); // All fields
    query.where = "1=1"; // All features
    query.returnGeometry = true;
    
    var token:Object = new Object();
    token.layer = 1;
    
    var queryTask:QueryTask = new QueryTask(FIRST_LAYER_URL);
    queryTask.execute(query, new AsyncResponder(onQueryResult, onQueryFault, token));
   }
   
   private function executeSecondQuery(whereClause:String, intermediateResult:ArrayCollection):void
   {
    trace("executeSecondQuery");
    var query:Query = new Query();
    query.outFields = new Array("*"); // All fields
    query.where = whereClause;
    query.returnGeometry = false;
    
    var token:Object = new Object();
    token.layer = 2;
    token.features = intermediateResult;
    
    var queryTask:QueryTask = new QueryTask(SECOND_LAYER_URL);
    queryTask.execute(query, new AsyncResponder(onQueryResult, onQueryFault, token));
   }
   
   protected function onQueryResult(featureSet:FeatureSet, token:Object = null):void
   {
    var queryLayer:int;
    var intermediateResult:ArrayCollection = new ArrayCollection();
    if (token != null)
    {
     queryLayer = token.layer;
     intermediateResult = token.features;
    }
    else
    {
     return;
    }
    
    trace(StringUtil.substitute("onQueryResult for {0}-st layer", queryLayer));
    
    switch (queryLayer)
    {
     case 1:
     {
      parseFirstQueryResult(featureSet);
      break;
     }
     case 2:
     {
      parseSecondQueryResult(featureSet, intermediateResult);
      break;
     }
    }
   }
   
   protected function onQueryFault(fault:Fault, token:Object = null):void
   {
    var queryLayer:int;
    if (token != null)
    {
     queryLayer = token.layer;
    }
    else
    {
     return;
    }
    
    trace(StringUtil.substitute("onQueryFault for {0}-st layer", queryLayer));
   }
   
   private function parseFirstQueryResult(featureSet:FeatureSet):void
   {
    trace("parseFirstQueryResult");
    var intermediateResult:ArrayCollection = new ArrayCollection();
    var secondQueryWhere:String = "";
    if (featureSet != null && featureSet.features.length > 0)
    {
     var features:Array = featureSet.features;
     for each (var graphic:Graphic in features)
     {
      var attributes:Object = graphic.attributes;
      if (attributes != null)
      {
       var name:String = attributes["NAME"];
       var males:Number = attributes["MALES_CY_12"];
       
       var resultItem:Object = new Object();
       resultItem.name = name;
       resultItem.males = males;
       resultItem.geometry = graphic.geometry;
       
       intermediateResult.addItem(resultItem);
       if (secondQueryWhere.length > 0)
       {
        secondQueryWhere = StringUtil.substitute("{0} OR NAME = '{1}'", secondQueryWhere, name);
       }
       else
       {
        secondQueryWhere = StringUtil.substitute("NAME = '{0}'", name);
       }
      }
     }
     
     executeSecondQuery(secondQueryWhere, intermediateResult);
    }
    else
    {
     trace("First query no features found");
    }
   }
   
   private function parseSecondQueryResult(featureSet:FeatureSet, intermediateResult:ArrayCollection):void
   {
    trace("parseSecondQueryResult");
    if (featureSet != null && featureSet.features.length > 0)
    {
     var intermediateResult2:ArrayCollection = new ArrayCollection();
     var features:Array = featureSet.features;
     for each (var graphic:Graphic in features)
     {
      var attributes:Object = graphic.attributes;
      if (attributes != null)
      {
       var total:Number = attributes["TOTPOP_CY"];
       var name:String = attributes["NAME"];
       
       var resultItem:Object = new Object();
       resultItem.name = name;
       resultItem.total = total;
       
       intermediateResult2.addItem(resultItem);
      }
     }
     combineResults(intermediateResult, intermediateResult2);
    }
    else
    {
     trace("Second query no features found");
    }
   }
   
   private function combineResults(intermediateResult1:ArrayCollection, intermediateResult2:ArrayCollection):void
   {
    trace("combineResults");
    resultsSource = new ArrayCollection(); // do not use resultsSource.removeAll();
    
    var iExtent:Extent = null;
    
    for each (var obj1:Object in intermediateResult1)
    {
     for each (var obj2:Object in intermediateResult2)
     {
      if (obj1.name == obj2.name)
      {
       var attributes:Object = new Object();
       attributes.name = obj1.name;
       attributes.total = obj2.total;
       attributes.males = obj1.males;
       
       var geom:Geometry = Geometry(obj1["geometry"]);
       
       var graphic:Graphic = new Graphic();
       graphic.geometry = geom;
       graphic.symbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_CROSS, 0xF5F500, 0.5, new SimpleLineSymbol())
       graphic.attributes = attributes;
       graphic.toolTip = StringUtil.substitute("Name: {0}\nTotal: {1}\nMales: {2}", 
        attributes.name, 
        attributes.total, 
        attributes.males);
       
       resultsSource.addItem(graphic);
       
       if (iExtent != null)
       {
        // union extents
        var minX:Number = (geom.extent.xmin < iExtent.xmin) ? geom.extent.xmin : iExtent.xmin;
        var maxX:Number = (geom.extent.xmax > iExtent.xmax) ? geom.extent.xmax : iExtent.xmax;
        var minY:Number = (geom.extent.ymin < iExtent.ymin) ? geom.extent.ymin : iExtent.ymin;
        var maxY:Number = (geom.extent.ymax > iExtent.ymax) ? geom.extent.ymax : iExtent.ymax;
        
        iExtent = new Extent(minX, minY, maxX, maxY, SPATIAL_REFERENCE);
       }
       else
       {
        iExtent = geom.extent;
       }
       
       break;
      }
     }
    }
    
    myMap.initialExtent = iExtent.expand(1.1);
    myMap.zoomToInitialExtent();    
   }

  ]]>
 </fx:Script>

 <ags:Map id="myMap" 
    zoomSliderVisible="false" 
    scaleBarVisible="false">
  <ags:GraphicsLayer load="onLayerLoad(event)" 
                                           graphicProvider="{resultsSource}"/>
 </ags:Map>
 
</s:Application>
0 Kudos