Executing selections based on another query's results - managing scope

2969
6
09-02-2015 08:10 AM
TracySchloss
Frequent Contributor

I have two layers.  I want to query staffLayer based on the a buffer of a selected feature in alertLayer.  I am looking at Select with Feature Layer | ArcGIS API for JavaScript  for an example.  The difference is I don't want a map click, I want to select the feature in alertLayer based on a row in a grid.

I'm getting a feature from alertLayer with my grid click.   I then need to buffer it, then use that buffer as the input geometry for a Query on staffLayer.  I am getting as far as generating a circle based on the selected row, which draws in the correct location.  However, I'm never getting any features found in that circle, even though I see there are several in the vicinity that should be returned.

I have changed this around several times, and I know I have a scope problem with the sequence of what I'm trying to do.  I started out with something more straight forward, but changed to more a lang.hitch type of syntax, which I'm still getting the hang of.

I'm getting the error Uncaught TypeError: app.staffLayer.on(...).then is not a function 

      updateAlertGrid: function(){
        var queryParams = new Query();
        queryParams.geometry = app.currentExtent;
        queryParams.spatialRelationship = Query.SPATIAL_REL_CONTAINS;
        queryParams.outFields = ["*"];
        queryParams.outSpatialReference = app.spatialReference;
        var queryTask = new QueryTask(app.alertLayer.url);
        queryTask.on('error', queryErrorHandler);
        queryTask.execute(queryParams, lang.hitch(this, updateGridHandler));
        
        function updateGridHandler(results){
          var data = [];
          if (app.alertGrid) {
            app.alertGrid.refresh();
          }
          data = arrayUtils.map(results.features, function(feature){
            return feature.attributes;
          });
          var currentMemory = new Memory({
            data: data,
            idProperty: 'ESRI_OID'
          });
          
          app.alertGrid.set("store", currentMemory);
          app.alertGrid.sort('FlagStatusCode');
          app.alertGrid.on('.dgrid-row:click', function(event){
            var row = app.alertGrid.row(event);
            var gridQuery = new Query();
            gridQuery.objectIds = [row.data.ESRI_OID];
            app.alertLayer.selectFeatures(gridQuery, FeatureLayer.SELECTION_NEW, function(results){
              if (results.length > 0) {
                app.alertFeature = results[0];
                app.alertFeature.setInfoTemplate(app.alertTemplate);
                //    map.centerAndZoom(results[0].geometry,14);  
                var resultGeometry = results[0].geometry;
                app.map.infoWindow.setFeatures(results);
                app.map.infoWindow.show(resultGeometry);
              }
              else {
                console.log("error in grid.on click function");
              }
            });
          });
          on(app.alertGrid, ".dgrid-cell:click", function(evt){
            var cell = app.alertGrid.cell(evt);
            var col = cell.column;
            //var row = cell.row;
            if (col.field === 'staff') {
              //   console.log("you clicked the staff cell");
              findStaffbyLocation(app.alertFeature.geometry);
            }
          });
        }
        function queryErrorHandler(err){
          console.log("error in queryTask is " + err.error);
        }
        //functions for finding staff near a server alert
        function findStaffbyLocation(geom){
          var circle = new Circle({
            center: geom,
            geodesic: true,
            radius: 50,
            radiusUnit: "esriMiles"
          });
          
          var circleSymb = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NULL, new           SimpleLineSymbol(SimpleLineSymbol.STYLE_SHORTDASH, new Color([105, 105, 105]), 2), new Color([255, 255, 0, 0.25]));
          var graphic = new Graphic(circle, circleSymb);
          app.map.graphics.add(graphic);  //circle is added correctly around the selected row
          app.map.setExtent(circle.getExtent());
          var query = new Query();
          query.geometry = circle.getExtent();
          app.staffLayer.queryFeatures(query);
       
         app.staffLayer.on( 'query-features-complete', lang.hitch(this, function(response){   //there are never any features found here  
            var feature;
            var features = response.features;
            var inBuffer = [];
            
            //started with extent,now filter out features that are not actually within buffer
            for (var i = 0; i < features.length; i++) {
              feature = features;
              if (circle.contains(feature.geometry)) {
                inBuffer.push(feature.attributes[ESRI_OID]);
              }
            }
          })).then(function(){
            var query = new Query();
            query.objectIds = inBuffer;
            var staffList = [];
            app.staffLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function(results){
              arrayUtils.forEach(results, function(feature){
                staffList.push(feature.attributes.Contact_FirstName + " " + feature.attributes.Contact_LastName + "</br>");
              });
              alert("Staff near selected server: " + staffList);
            });
          });
        }
      }
0 Kudos
6 Replies
thejuskambi
Occasional Contributor III

The dojo/on does not return a promise so, cannot use .then. Try changing that and see if it works.

0 Kudos
TracySchloss
Frequent Contributor

I changed it around, but I still have no results from querying my circle's extent.  I don't have these features turned on when I run the query, but I didn't think that would matter.  I notice when I run it a 2nd time, I will sometimes get results when I didn't before.

I'm not getting an error, but still no results,

  updateAlertGrid: function(){
        var queryParams = new Query();
        queryParams.geometry = app.currentExtent;
        queryParams.spatialRelationship = Query.SPATIAL_REL_CONTAINS;
        queryParams.outFields = ["*"];
        queryParams.outSpatialReference = app.spatialReference;
        var queryTask = new QueryTask(app.alertLayer.url);
        queryTask.on('error', queryErrorHandler);
        queryTask.execute(queryParams, lang.hitch(this, updateGridHandler));
       
        function updateGridHandler(results){
          var data = [];
          if (app.alertGrid) {
            app.alertGrid.refresh();
          }
          data = arrayUtils.map(results.features, function(feature){
            return feature.attributes;
          });
          var currentMemory = new Memory({
            data: data,
            idProperty: 'ESRI_OID'
          });
         
          app.alertGrid.set("store", currentMemory);
          app.alertGrid.sort('FlagStatusCode');
          app.alertGrid.on('.dgrid-row:click', function(event){
            var row = app.alertGrid.row(event);
            var gridQuery = new Query();
            gridQuery.objectIds = [row.data.ESRI_OID];
            app.alertLayer.selectFeatures(gridQuery, FeatureLayer.SELECTION_NEW, function(results){
              if (results.length > 0) {
                app.alertFeature = results[0];
                app.alertFeature.setInfoTemplate(app.alertTemplate);
                //    map.centerAndZoom(results[0].geometry,14); 
                var resultGeometry = results[0].geometry;
                app.map.infoWindow.setFeatures(results);
                app.map.infoWindow.show(resultGeometry);
              }
              else {
                console.log("error in grid.on click function");
              }
            });
          });
          on(app.alertGrid, ".dgrid-cell:click", function(evt){
            var cell = app.alertGrid.cell(evt);
            var col = cell.column;
            //var row = cell.row;
            if (col.field === 'staff') {
              //  console.log("you clicked the staff cell");
              findStaffbyLocation(app.alertFeature.geometry);
            }
          });
        }
        function queryErrorHandler(err){
          console.log("error in queryTask is " + err.error);
        }
        //functions for finding staff near an address
        function findStaffbyLocation(geom){
          var circle = new Circle({
            center: geom,
            geodesic: true,
            radius: 25,
            radiusUnit: "esriMiles"
          });
         
          var circleSymb = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NULL, new SimpleLineSymbol(SimpleLineSymbol.STYLE_SHORTDASH, new Color([105, 105, 105]), 2), new Color([255, 255, 0, 0.25]));
          var graphic = new Graphic(circle, circleSymb);
          app.map.graphics.add(graphic);
          app.map.setExtent(circle.getExtent());
          var cirquery = new Query();
          cirquery.geometry = circle.getExtent();
        //  app.staffLayer.queryFeatures(cirquery);
           
        app.staffLayer.queryFeatures(cirquery,lang.hitch(this, function(response){   
            var feature;
            var features = response.features;
            app.inBuffer = [];
           
            //started with extent,now filter out features that are not actually within buffer
            for (var i = 0; i < features.length; i++) {
              feature = features;
              if (circle.contains(feature.geometry)) {
                app.inBuffer.push(feature.attributes.ESRI_OID);
              }
            }
            var query = new Query();
            query.objectIds = app.inBuffer;
            var staffList = [];
            app.staffLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function(results){
              arrayUtils.forEach(results, function(feature){
                staffList.push(feature.attributes.Contact_FirstName + " " + feature.attributes.Contact_LastName );
              });
              alert("Staff near selected server: " + staffList);
            });
           
        })); 
         
        }
      }
0 Kudos
thejuskambi
Occasional Contributor III

I am not sure why you are doing the query twice, may be for selection. In any case I made some changes yo your implementation. I believe the app.alertFeatureGeometry is not being set properly and this what I usually do, I append the geometry along with the attributes and pass it to dgrid, this I will be able to get access to the geometry on click event. see if this helps you.

PS: Make sure the dgrid is not showing the geometry column.

     updateAlertGrid: function(){  
            var queryParams = new Query();  
            queryParams.geometry = app.currentExtent;  
            queryParams.spatialRelationship = Query.SPATIAL_REL_CONTAINS;  
            queryParams.outFields = ["*"];  
            queryParams.outSpatialReference = app.spatialReference;  
            var queryTask = new QueryTask(app.alertLayer.url);  
            queryTask.on('error', queryErrorHandler);  
            queryTask.execute(queryParams, lang.hitch(this, updateGridHandler));  
             
            function updateGridHandler(results){  
              var data = [];  
              if (app.alertGrid) {  
                app.alertGrid.refresh();  
              }  
              data = arrayUtils.map(results.features, function(feature){  
                //changed here to create a clone and merge the geometry to the data source
                var clone = lang.clone(feature.attributes);
                return lang.mixin( clone, { geometry : feature.geometry });  
              });
              
              var currentMemory = new Memory({  
                data: data,  
                idProperty: 'ESRI_OID'  
              });  
               
              app.alertGrid.set("store", currentMemory);  
              app.alertGrid.sort('FlagStatusCode');  
              app.alertGrid.on('.dgrid-row:click', function(event){  
                var row = app.alertGrid.row(event);  
                var gridQuery = new Query();  
                gridQuery.objectIds = [row.data.ESRI_OID];  
                app.alertLayer.selectFeatures(gridQuery, FeatureLayer.SELECTION_NEW, function(results){  
                  if (results.length > 0) {  
                    app.alertFeature = results[0];  
                    app.alertFeature.setInfoTemplate(app.alertTemplate);  
                    //    map.centerAndZoom(results[0].geometry,14);   
                    var resultGeometry = results[0].geometry;  
                    app.map.infoWindow.setFeatures(results);  
                    app.map.infoWindow.show(resultGeometry);  
                  }  
                  else {  
                    console.log("error in grid.on click function");  
                  }  
                });  
              });  
              on(app.alertGrid, ".dgrid-cell:click", function(evt){  
                var cell = app.alertGrid.cell(evt);  
                var col = cell.column;  
                //var row = cell.row;  
                if (col.field === 'staff') {  
                  //  console.log("you clicked the staff cell");  
                  findStaffbyLocation(row.data.geometry);   //changed to used row geometry
                }  
              });  
            }  
            function queryErrorHandler(err){  
              console.log("error in queryTask is " + err.error);  
            }  
            //functions for finding staff near an address  
            function findStaffbyLocation(geom){  
              var circle = new Circle({  
                center: geom,  
                geodesic: true,  
                radius: 25,  
                radiusUnit: "esriMiles"  
              });  
               
              var circleSymb = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NULL, new SimpleLineSymbol(SimpleLineSymbol.STYLE_SHORTDASH, new Color([105, 105, 105]), 2), new Color([255, 255, 0, 0.25]));  
              var graphic = new Graphic(circle, circleSymb);  
              app.map.graphics.add(graphic);  
              app.map.setExtent(circle.getExtent());  
              var cirquery = new Query();  
              cirquery.geometry = circle.getExtent();  
            //  app.staffLayer.queryFeatures(cirquery);  
                 
            app.staffLayer.queryFeatures(cirquery,lang.hitch(this, function(response){     
                var feature;  
                var features = response.features;  
                app.inBuffer = [];  
                 
                //started with extent,now filter out features that are not actually within buffer  
                for (var i = 0; i < features.length; i++) {  
                  feature = features
                  if (circle.contains(feature.geometry)) {  
                    app.inBuffer.push(feature.attributes.ESRI_OID);  
                  }  
                }  
                var query = new Query();  
                query.objectIds = app.inBuffer;  
                var staffList = [];  
                app.staffLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function(results){  
                  arrayUtils.forEach(results, function(feature){  
                    staffList.push(feature.attributes.Contact_FirstName + " " + feature.attributes.Contact_LastName );  
                  });  
                  alert("Staff near selected server: " + staffList);  
                });  
                 
            }));   
               
            }  
          }
0 Kudos
TracySchloss
Frequent Contributor

I don't typically return the geometry from a query that's populating a grid.  Somehow I didn't think it would be retained as part of the row object.  I have the other query because I don't see how else I'm going to display the infoTemplate for the feature.  Maybe you typically go about this some other way.   I added returnGeometry from my initial query, but I'm not still getting any results from

app.staffLayer.queryFeatures(cirquery,lang.hitch(this, function(response){

The length of the response is always 0.  All my layers are in wkid 102100.  At first I thought I wasn't getting anything because I my spatialReferences didn't go together, but the coordinates all look to match up.

I'm going to try to post something for people to look at. The initial project contains sensitive data, which is all secured.

0 Kudos
RobertWinterbottom
Occasional Contributor

Hi Tracy,

I don't believe 'on' is a deferred type which means the .then function won't exist. dojo's on module takes an event name and a callback function. You may be able to move that code in the then into the callback function like below:

app.staffLayer.on( 'query-features-complete', lang.hitch(this, function(response){   //there are never any features found here    
            var feature;  
            var features = response.features;  
            var inBuffer = [];  
              
            //started with extent,now filter out features that are not actually within buffer  
            for (var i = 0; i < features.length; i++) {  
              feature = features
              if (circle.contains(feature.geometry)) {  
                inBuffer.push(feature.attributes[ESRI_OID]);  
              }  
            }


  var query = new Query();  
            query.objectIds = inBuffer;  
            var staffList = [];  
            app.staffLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW, function(results){  
              arrayUtils.forEach(results, function(feature){  
                staffList.push(feature.attributes.Contact_FirstName + " " + feature.attributes.Contact_LastName + "</br>");  
              });  
              alert("Staff near selected server: " + staffList);  
            });
  
          }));

EDIT: Just noticed @thejus replied while I was typing, but we essentially are saying the same thing

0 Kudos
TracySchloss
Frequent Contributor

My layer is initially turned off, but I have a TOC that lets the user change it.  I notice that it consistently finds the points I expect  once the layer is turned on. 

I wouldn't expect the visibility to make a difference on whether or not queryFeatures works. 

0 Kudos