Hello,
I am trying to loop through a string array of place names, build a query statement for each place, get the extent for the place, and build a bookmarks list. I am however baffled with how the results are built. Basically, it looks like while the query task is located inside the loop, it waits for the loop to finish to be executed. Therefore I get multiple and identical query results in the end. The core of the problem can be shown with this piece of code:
for (i = 1; i < allSysNames.length; i++) {
query.where = "SysName =" + allSysNames;
console.log("i inside the loop is: " + i);
queryTask.executeForExtent(query, function(result){
console.log("i inside query task equals to: " + i);
});
}
console.log("outside the loop");
The log is the following.
i inside the loop is: 1
i inside the loop is: 2
i inside the loop is: 3
outside the loop
i inside query task equals to 4
i inside query task equals to 4
i inside query task equals to 4
I am probably missing something very basic here, as I am new to Javascript and the API. What do I need to execute the queryTask for my purposes? Thank you!
Naci
Solved! Go to Solution.
Those query tasks are asynchronous, so won't be executed immediately.
You have a couple of options
var queries = []; for (i = 1; i < allSysNames.length; i++) { query.where = "SysName =" + allSysNames; console.log("i inside the loop is: " + i); queries.push(queryTask.executeForExtent(query)); } // dojo/promise/all all(queries).then(, function(results){ // another for loop for (var j = 0; j < results.length; j++) { console.log("j inside query task equals to: " + j); } }); console.log("outside the loop"); // or // I prefer this method var queries = allSysNames.map(function(name) { query.where = "SysName =" + name; return queryTask.executeForExtent(query) }); // dojo/promise/all all(queries).then(, function(results){ // another for loop for (var j = 0; j < results.length; j++) { console.log("j inside query task equals to: " + j); } }); console.log("outside the loop");
I have a couple of posts on Promises you could check out.
ArcGIS JavaScript Promises - odoenet
Since the Promises is asynchronous, it will finish after your last console statement.
Hope that helps a bit.
Those query tasks are asynchronous, so won't be executed immediately.
You have a couple of options
var queries = []; for (i = 1; i < allSysNames.length; i++) { query.where = "SysName =" + allSysNames; console.log("i inside the loop is: " + i); queries.push(queryTask.executeForExtent(query)); } // dojo/promise/all all(queries).then(, function(results){ // another for loop for (var j = 0; j < results.length; j++) { console.log("j inside query task equals to: " + j); } }); console.log("outside the loop"); // or // I prefer this method var queries = allSysNames.map(function(name) { query.where = "SysName =" + name; return queryTask.executeForExtent(query) }); // dojo/promise/all all(queries).then(, function(results){ // another for loop for (var j = 0; j < results.length; j++) { console.log("j inside query task equals to: " + j); } }); console.log("outside the loop");
I have a couple of posts on Promises you could check out.
ArcGIS JavaScript Promises - odoenet
Since the Promises is asynchronous, it will finish after your last console statement.
Hope that helps a bit.
One more useful thing to know about Promises is that they are returned in the same order that they are passed in. Therefore, you'll always know that result1 will be what's returned from query1, result2 will be what's returned from query2, etc
Thank you very much! This helps a lot. I have a couple of follow up questions. First, Aptana gives me an error for the use of comma in this line
all(queries).then(, function(results){
I removed the comma, and it seems to be working fine. Is that OK?
Second issue is another one that confuses me. As I mentioned before, I use this loop to build a bookmarks list (following this example Bookmarks widget | ArcGIS API for JavaScript), which I defined as
bookmarks = new esri.dijit.Bookmarks({
map: map,
}, dojo.byId('bookmarks'));
I then created a temp bookmark:
var tempBookmark ={ |
"extent": {
"spatialReference": {
"wkid": 0
},
"xmin":0,
"ymin":0,
"xmax":0,
"ymax":0
},
"name": "Temp"
};
In the procedure you described, I assigned the extents of the results
all(queries).then(function(results){
// another for loop
for (var j = 0; j < results.length; j++) {
console.log("j inside query task equals to: " + j);
console.log(results
tempBookmark.extent = results
tempBookmark.name = allSysNames
console.log(tempBookmark.extent);
bookmarks.addBookmark(tempBookmark);
}
});
So the bookmark list is built just fine, with the correct names from the allSysNames array. Apparently the statement tempBookmark.name = allSysNames
For the first one, that was a typo on my part, sorry.
For second one
The tempBookmark you are updating is a single bookmark, so you keep updating the same one and adding it multiple times, but inside the bookmark widget, you basically added the same bookmark multiple times.
Create a new bookmark on each loop and you should be ok.
Thanks a lot, that solved my problem!
Hi Rene,
Why doesn't this work? Where visible is coming from an array of layerId's that are providing indexes for myQuery (it works for any random array eg ["alpha", "beta", "charlie"]:
var myQuery = ["Population>10000" , "Hispanic > 1500" , "Employees > 10000"];
var result = visible.map(function(e) {
return myQuery
});
Rene, I hope you have chance to see this as I have a similar question as this. I understand that I can't call a query inside of a for loop. Here is what I am trying to do. I reach out to an API that returns information on Bus Stops that are currently closed. I want to display these Bus Stops on a map but the information from the API doesn't include lat/lon. So what I do is take the response from the API and iterate through them getting the Bus Stop number and then running a query on our Bus Stop Feature Class that can return the lat/lon that I in turn create a graphics layer from. Problem of course is the query doesn't work as expected. Wondering how I can incorporate your answer above into my scenario.
layerList.on("trigger-action", (event) => {
const id = event.action.id;
if (id === "refresh-ClosedBusStops") {
var settings = {
"url": 'api to get closed bus stops',
"method": "GET",
"timeout": 0,
"headers": {
"Authorization": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json"
}
};
$.ajax(settings).done(function (response) {
var Xcoord = 0;
var Ycoord = 0;
for(i = 0; i < response.adjustments.length; i+=1) {
busID = response.adjustments[i].details.stopIds;
routeAffected = response.adjustments[i].details.routesAffected;
notes = response.adjustments[i].notes;
reason = response.adjustments[i].reason;
const query = new Query();
var queryValue = "Id = " + response.adjustments[i].details.stopIds;
query.where = queryValue;
query.outFields = [ "Xcoord", "Ycoord" ];
query.returnGeometry = true;
ClosedBusStops.queryFeatures(query).then(function(results) {
Xcoord = results.features[0].attributes.Xcoord;
Ycoord = results.features[0].attributes.Ycoord;
createClosedBusStop(busID, routeAffected, notes, reason, Xcoord, Ycoord);
});
};
});
}
});
function createClosedBusStop(busID, routeAffected, notes, reason, Xcoord, Ycoord) {
const busStop = new Point({
type: "point",
longitude: Xcoord,
latitude: Ycoord,
wkid: 4326
});
var markerSymbol = {
type: "simple-marker",
style: "square",
color: "RED",
size: "10px"
};
popupClosedBusStops = {
title: "Bus Stop: " + busID,
content:"<b>Route(s) Impacted: </b>" + routeAffected + "<br/>" +
"<b>Notes: </b>" + notes + "<br/>" +
"<b>Reason: </b>" + reason
};
const busStopGraphic = new Graphic ({
geometry: busStop,
symbol: markerSymbol,
popupTemplate: popupClosedBusStops
});
view.graphics.add(busStopGraphic);
};