Out of Bounds?

2371
11
11-22-2020 07:48 PM
GlenShepherd
Esri Contributor
9 11 2,371

Setting boundaries for survey submission using JavaScript in Survey123

 

The Premise:

Let's consider workflows when survey submission should be dependent on the user's location inside/outside of a boundary and where we might want to control these submissions using our Survey123 form...

  • Working on private property
  • Field teams assigned to different land parcels
  • Collecting data in proximity to hazards
  • Conducting surveys of assets for a particular city council

One method of quality control might be to restrict submissions based on where field workers are located in regards to specific geometry (i.e. within council boundary, 10m from a major freeway, on private property, etc...)

This can be implemented by taking advantage of writing and referencing custom JavaScript functions to automate spatial queries. @Ismael Chivite's blog post, "Extending Survey123 smart forms with custom JS functions" introduces us to using the pulldata() function to implement JavaScript functions in our XLSForm by storing our JavaScript files in a dedicated 'scripts' folder. Furthermore, the JavaScript Sample survey in Survey123 Connect provides us with examples of scripts that can query the geometry of our feature services:

sampleSurvey.png

This workflow will utilise a modified version of the "url_requests.js" script from the above sample survey. To follow along with this example, you'll need the following:

  • Survey123 Connect Desktop Application (download here)
  • "OutOfBounds.xlsx" and "OutOfBounds.js" files from the .zip attached to this blog
  • A polygon feature layer available through your web portal (ArcGIS Online or ArcGIS Portal)

In this example, we're simply going to indicate whether a Survey123 mobile app user is inside or outside of a set boundary (polygon feature layer) using an intersect query, and limit their submission capability accordingly...

 

The Workflow:

Create a new survey from file, using the "OutOfBounds.xlsx" form mentioned above.
To store our script(s), we'll want to create a folder within our Survey project location titled "scripts", as follows:

Please Note: Later, when we add a pulldata("@javascript") calculation to the survey, Survey123 will look to the "scripts" folder for the name of the JavaScript file we've saved. The "scripts" folder must be manually created by you, the survey author.Please Note: Later, when we add a pulldata("@javascript") calculation to the survey, Survey123 will look to the "scripts" folder for the name of the JavaScript file we've saved. The "scripts" folder must be manually created by you, the survey author.

We'll start by adding a "geopoint" question to our survey.

Then, add a "hidden" question and place the service URL of your polygon feature layer in the Default column.

Furthermore, if our feature service is secured (i.e. not public), we will want to include another "hidden" question to incorporate the pulldata("@property","token") function and provide a token which our JavaScript function will require to access the service:

Table1.png

We're going to save the following script (attached; "OutOfBounds.js") into our "scripts folder and reference it from within our survey form to carry out the intersect query and return a string relevant to whether the geopoint lies within the feature service polygon boundary or not.

Please Note: a double forward-slash (//) denotes a non-functional comment in JavaScript. Near the bottom of this script, you will see comments where we can edit the text strings that warn the user whether they are "Within Boundary" or "Out of Bounds"

 

// "echo" checks that JavaScript is working correctly
function echo(input) {
	return input.toString();
}
// Query feature service and determine if the geopoint intersects

function featureByLocation(layerURL, location, token) {
	let outValue = "";

	if (layerURL == null || layerURL === "" || location == null || location === "") {
		return location;
	}

	let coordsArray = location.split(" ");
	let coords = `${coordsArray[1]},${coordsArray[0]}`;

	let f = "f=json";
	let geometry = `geometry=${coords}`; 
	let geometryType = "geometryType=esriGeometryPoint";
	let inSR = "inSR=4326";
	let spatialRel = "spatialRel=esriSpatialRelIntersects";
	let outFields = "outFields=*";
	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}`;

	let xhr = new XMLHttpRequest();
	xhr.open("GET", url, false);
	xhr.send();
	
	if (xhr.readyState === xhr.DONE) {
		if (xhr.status !== 200) {
			return "bad request: " + url
		} else {
			let response = JSON.parse(xhr.responseText);
			if (response.error) {
				return "There was a problem with the query"
			} else {
				if (response.features[0]) {
					outValue = "Within Boundary";			// Positive intersect "string"
				} else {
					return "Out of Bounds"					// Negative intersect "string"
				}
			}
		}
	}
	return outValue;
}

 

In a 'note' question, we add the following function to the calculation field:

pulldata("@javascript","OutOfBounds.js","featureByLocation",${boundaryurl},string(${droppoint}),string(${tokenpull}))

  • "@javascript" - looks for .js files in the scripts folder
  • "OutOfBounds.js" - specifies the name of which .js file to pull
  • "featureByLocation" - specifies which function to use from the script (there's only one in this example)
  • We then populate the parameters of the function (specified in Line 7 of the attached script):
    • ${boundaryurl} - our hidden question containing the layer URL
    • string(${droppoint}) - stringified geopoint question providing user location
    • string(${tokenpull}) - stringified hidden question providing the feature service token

Table2.png

Now, once the mobile device has captured a location for the geopoint question, the JavaScript function will return either "Within Boundary" or "Out of Bounds" depending whether the user's location is intersecting a feature in the feature service.

Furthermore, we might like to add extra questions for quality control of our field team:

  1. Prevent submissions if the user is outside of the boundary
  2. Add a dateTime question for users within the boundary

Please Note: These have already been added to the attached example survey form "OutOfBounds.xlsx"Please Note: These have already been added to the attached example survey form "OutOfBounds.xlsx"

 

The result for the end-user in the Survey123 mobile application may look similar to the following:

OutOfBounds.gif

 

Other quality control considerations and notes:

  • Make the geopoint question read-only.
  • Add a web map with the polygon ‘boundary’ feature layer as Linked Content in Survey123 Connect and use it as the Basemap for the GeoPoint question.
  • The "OutOfBounds.js" file in the attached .zip contains further comments regarding the specific JavaScript functions in the script example above and what they do.

 

11 Comments
About the Author
Esri Australia team member based in Melbourne. Delivering support and training across Enterprise, Desktop and Field Apps. Learning something new every day.