Hello,
I am trying to pass location in xy or address format from Workforce to a Survey. I want to be able to populate a text field in Connect with the coordinates or the address and then convert to coordinates, so that I can use it as a parameter for the 'Working with a feature service' Javascript example published by Survey123.
I want to be able to determine what district the survey is in using that script, it works good on its own, but with Workforce not so much.
Passing Workforce Location is fine, but in Workforce when you click on the map an xy populates the location, while searching for an address populates the location field in address format. Therefore it cant be expected of end users to consistently submit an assignment with either or.
I was wondering if anyone had any ideas, I'm thinking there might be a way to calculate a location field in survey123 that accounts for either address or xy but im not sure how to go about it. I am aware of the geocode and reverse geocode functions, but how to account for both formats I'm not sure. I'm new to Connect and super new to Javascript so thank you for any advice.
Here is the script im using;
// Query a feature layer and returns a specific field value from
// the feature that intersects the location
function fieldValueByLocation(layerURL, location, field, token) {
// Output value. Initially set to an empty string (XLSForm null)
let outValue = "";
// Check to make sure both layerURL and location are provided
if (layerURL == null || layerURL === "" || location == null || location === "") {
// The function can't go forward; exit with the empty value
return outValue;
}
// The coordinates will come in as `<lat> <lon> <alt> <acc>`.
// We need <lon>,<lat> for the query
// Note that I'm using the relatively new ` ` string that lets me place variables ${var}
let coordsArray = location.split(" ");
let coords = `${coordsArray[1]},${coordsArray[0]}`;
// Set up query parameters
let f = "f=pjson";
let geometry = `geometry=${coords}`;
let geometryType = "geometryType=esriGeometryPoint";
let inSR = "inSR=4326";
let spatialRel = "spatialRel=esriSpatialRelIntersects";
let outFields = `outFields=${field}`;
let returnGeometry = "returnGeometry=false";
let returnCount = "returnCount=1";
let parameters = [f,geometry,geometryType,inSR,spatialRel,outFields,returnGeometry,returnCount].join("&");
if (token) {
parameters = parameters + `&token=${token}`;
}
let url = `${layerURL}/query?${parameters}`;
/*
https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Administrative_Divisions/FeatureServer/0/query?
f=pjson
&geometry=-122.32759252280006,47.59698828035203
&geometryType=esriGeometryPoint
&inSR=4326
&spatialRel=esriSpatialRelIntersects
&outFields=NAME
&returnGeometry=false
&returnCount=1
https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Administrative_Divisions/FeatureServer/0/query?where=&objectIds=&time=&geometry=-117.19605707130171%2C34.0675386635019&geometryType=esriGeometryPoint&inSR=4326&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&returnGeodetic=false&outFields=NAME&returnGeometry=false&returnCentroid=false&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=html&token=
*/
// return url;
// Create the request object
let xhr = new XMLHttpRequest();
// Make the request. Note the 3rd parameter, which makes this a synchronous request
xhr.open("GET", url, false);
xhr.send();
// Process the result
// This an abbreviated version without being able to distinguish different types of errors
if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText);
if (!response.error) {
if (response.features[0]) {
outValue = response.features[0].attributes[field];
}
}
}
return outValue;
}
Here is the form for reference as you see it in the example.
Here is the excel that comes with it as well.
geopoint | location | Please set a location | |||||||||||||||||||||||||||||||||
hidden | adminURL | URL for feature layer of 1st level admin boundaries | The URL is added as a hidden question to make the pulldata() function more readable and so that it can be changed outside of the script. | https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/World_Administrative_Divisions/Fea... | null | ||||||||||||||||||||||||||||||
note | adminFeature | The 1st level admin area feature the location is in | Queries a feature layer to return the feature the point intersects. Returns a JSON object that can be processed in the form. | multiline | pulldata("@javascript", "url_requests.js", "featureByLocation", ${adminURL}, string(${location})) | null | 100000 | ||||||||||||||||||||||||||||
text | adminISO | ISO_CODE value | A specific value can be extracted using the pulldata("@json") function. | pulldata("@json", ${adminFeature}, "attributes.ISO_CODE") | |||||||||||||||||||||||||||||||
text | adminName | NAME attribute | Uses a different function that returns only the text value. | pulldata("@javascript", "url_requests.js", "fieldValueByLocation", ${adminURL}, string(${location}), 'NAME') |
Hi, Assuming your workflow is:
(1) In Workforce, click on an assignment point and then click on a button like "Survey at Assignment" to open a Survey123 form.
(2) And in Survey123 you want to get the coordinates of that assignment point and put them into a text field.
Because the integration between Workforce and Survey123 by default passes the coordinates to the opened form (regardless of whether there's a geopoint question or not), we just need to extract the coordinates from the form or the geopoint question.
To confirm the integration is passing the coordinates, you can check the integration URL within the Workforce feature service.
You can refer to the 'Extract geopoint values' section of this page to use the pulldata() function to extract the 'x' and 'y': https://doc.arcgis.com/en/survey123/desktop/create-surveys/geopoints.htm
I hope this will help.
All:
I have been experiencing the same issues described in this thread: trying to create an attribute expression that calculates lat/long coordinates from a hosted feature layer, then integrate Field Maps with Survey123 to open a form and have the geopoint plot the submitted survey on top of the feature using the result of the attribute expression using a custom URL via the custom URL popup (¢er=).
I have been using the "Expression/expr2 - Code to calculate geometry" formula called out in this post (and a multitude of others on the community page) and it was correctly calculating the coordinates in ArcGIS Online Web Viewer Classic, but then when we tested this functionality in the field, the point was not mapping.
I found that the original formula in the "Expression/expr2 - Code to calculate geometry" results in an Array data type, with associated brackets. These brackets do not show up in ArcGIS Online, but when you view the popup in Field Maps, you can see the brackets. So because of this, i tested further and in the original function, i removed the brackets in the result line, which worked but was not perfect. It was not perfect because the coordinate results ended up being truncated to 2 decimals, and even though the submitted form was executing, the point was being plotted hundred of feet away.
After 10 hours of testing and researching these threads (which by the way, all of the contributions are EXPONENTIALLY HELPFUL AND I AM SO GRATEFUL OF YOUR KNOWLEDGE) i was able to find the CORRECT SOLUTION:
1.) Create an attribute expression for latitude:
var lat;
var originShift = 2.0 * PI * 6378137.0 / 2.0;
lat = number(Geometry($feature).y / originShift) * 180.0;
lat = 180.0 / PI * (2.0 * Atan( Exp( lat * PI / 180.0)) - PI / 2.0);
return lat;
2.) Create an attribute expression for longitude:
var lon;
var originShift = 2.0 * PI * 6378137.0 / 2.0;
lon = number(Geometry($feature).x / originShift) * 180.0;
return lon;
3.) Because of the "number" identifier, In ArcGIS Online Web Map Viewer Classic go to Configure Popups, make sure your pop up display is custom, then the important step is to click Configure Attributes. Navigate to the newly created expressions and expand the decimal places to a minimum of 5.
4.) Lastly, in the custom URL make the "¢er={expression/expr3},{expression/expr4} where expr 3 is Lat and expr 4 is Long.
I have been testing since i discovered this and it has been running smoothly. Happy Mapping!