Background
The use of dynamic (constantly changing) choice lists in Survey123 has become a popular feature for survey authors since the introduction of linked content CSV files. This method uses the data contained in a CSV file hosted in an ArcGIS organisation as the choice list values in your surveys. This allows the choice list values to be managed outside of Survey123 by updating the linked CSV file if necessary when the survey is opened, and ensures the latest choice list values available to your survey users.
An additional method for incorporating dynamic choice lists into your surveys is supported in the 3.13 release of the field app and web app. This blog will take a deeper look into this new search() appearance and provide more details on what is possible and how to set it up.
This new method is configured by adding a search() expression to the appearance column of a select_one or select_multiple question in your XLSForm. The search() expression can reference a hosted CSV file, or a feature layer or table in ArcGIS through its REST URI. Referencing a layer that has geometry gives the additional capability to utilise spatial queries to populate the choice list. Some example use cases for spatial queries include populating a choice list dynamically with:
- incident report ID values from features within a search polygon (defined in the survey itself).
- asset ID values within a specified distance on your current location.
Getting Started
If you’re new to using choice lists in Survey123, please check out the blog titled Survey123 Tricks of the Trade: Choice Filters as a starting point.
To get up and running with the search() appearance we should first set up a survey with a select_one or select_multiple question. You must still include an entry on the choices worksheet but instead of listing each of the choices, you will reference the field name from the existing feature layer or table.
In the following screenshot a choice list called ‘us_states’ is defined on the choices worksheet and will use the field ‘STATE_NAME’ for both the choice name and label.
The search() appearance can be used alongside other appearances, and should be used with the ‘minimal’ or ‘autocomplete’ appearance (best practice for all very large choice lists). This prevents the form from trying to render all available choices, causing performance issues.
Understanding the Search Expression
Let’s take a look at the syntax used when building a search expression:
search(‘tableName’, ‘searchType’, ‘searchColumn’, ‘searchText’, ‘filterColumn’, ‘filterText’)
tableName
The ‘tableName’ parameter is the only required parameter, it specifies which table is going to be queried. This parameter has a different format depending on whether you’re referencing a local CSV (just use the CSV filename, without the file extension):
or an ArcGIS layer (use the format ‘<unique_name>?url=<Layer REST URL>’, including the layer index). The <unique_name> can be anything, it doesn't need to match the name of the hosted layer, but as this is how Survey123 internally refers to your search, must be different from all other table names and CSVs used in the survey:
Since both of these search expressions don’t use any other query parameters, the entire contents of the table will be used to populate the choice list.
Tip: You can optionally append query request parameters to the REST endpoint of your feature layer or map service layers to configure the search behaviour. This can be really useful for incorporating buffers of query geometry using &distance= and &units=, as well as limiting the number of query results using &resultRecordCount=. These URL parameters can also be set by the user in the form itself, see the Point intersects buffered points (with attribute filter) example below for details.
Optional Parameters
There are tables in the documentation that describe each of the optional parameters that can be used to narrow down the query results:
Let’s use these reference tables to help us understand two search expressions that utilise spatial queries (both are included in the ‘Dynamic Choice Lists using Search Appearance’ sample survey available in Survey123 Connect).
Polygon contains points
This example populates a choice list by returning values (in this case public school names, but can be any attribute value) from point features that are contained in the search polygon digitised by the survey user. It uses a geoshape question to allow users to define the search polygon and then a select_one question for users to select from the dynamic choice list.
Here is the search expression in full:
search('school?url=https://services1.arcgis.com/Ua5sjt3LWTPigjyD/arcgis/rest/services/Public_School_Location_201819/FeatureServer/0', 'contains', '@geoshape', ${search_poly})
tableName:
- unique name school for Survey123 internal reference (could be any unique string):
- REST endpoint URL including the layer index (0):
searchType:
- using the spatial relationship ‘contains’, to return features in the layer that are completely contained by query geometry. Any appropriate spatial relationship could be used:
searchColumn:
- using ‘@geoshape’ for this spatial query, as this is the query geometry type (ie polygon / geoshape):
searchText:
- for spatial queries, this references the survey question that will provide the query geometry. Notice that parameter values don’t need inverted commas when they reference a previous survey question, ${search_poly} in this case:
Point intersects buffered points (with attribute filter)
There are two examples in this group. The first example is supported in both the web and field apps as the search geometry (a 0.5 mile buffer) is hardcoded into the search expression. We will look at the second example here as this extends upon the first example to allow the survey user to define the buffer parameters on the fly (currently not supported in the web app). Both examples use all of the optional search expression parameters.
The use case for this example is a scenario where a choice list (in this case Store names) is populated dynamically based on your location and the search distance you specify. You can optionally apply a filter based on the Store category to further refine the choice list.
It uses a geopoint question to define your location, which is intersected with the buffered Store locations based on search distance (range question) and search distance unit (select_one question). Additional select_one questions provide the optional Store category filter and the final Store selection to make use of the resultant dynamic choice list.
Here the search expression is built in 2 steps.
Step 1 - creates the tableName parameter by adding the buffer parameters to the feature layer URL using the ‘concat’ function (in the calculate question named ‘search_url’). The calculation in full is:
concat("store?url=https://services6.arcgis.com/Do88DoK2xjTUCXd1/ArcGIS/rest/services/OSM_Shops_NA/FeatureServer/0&units=",${search_distance_unit},"&distance=",${search_distance})
tableName:
- unique name store for Survey123 internal:
- REST endpoint URL including the layer index (0):
- the optional query request parameters (‘units’ and ‘distance’) are appended to the REST URL of our feature layer (see documentation for feature service layers or map service layers for the full list of request parameters). These values can be hardcoded, but this example takes them from previous survey questions, namely ${search_distance} and ${search_distance_unit}.
The ‘search_distance’ question is displayed as a slider (ie a ‘range’ question type), while the ‘search_distance_unit’ question provides the options across the screen (ie a ‘select_one’ question with the ‘horizontal’ appearance).
Step 2 - adds the optional search parameters to complete the expression, here it is in full:
search(${search_url}, 'intersects', '@geopoint', ${search_point2}, 'shop', ${store_cat2})
searchType:
- using the spatial relationship ‘intersects’, to return features in the layer where the buffer intersects the query geometry. Any appropriate spatial relationship could be used:
searchColumn:
- using ‘@geopoint’ for this spatial query as this is the query geometry type (ie the location point):
searchText:
- the survey question that will provide the query geometry. Once again, notice that that parameter values don’t need inverted commas when they reference a previous survey question, ${search_point2} in this case:
filterColumn:
- the field from the feature layer for which we can apply an additional attribute filter. This will obviously depend on the feature layer itself, in this example we’re using the ‘shop’ field (this contains the store categories).
filterText:
- this text value can be hardcoded into the expression but is far more useful if it refers to a previous survey question. This way the survey user has control over applying the filter. Since we’re filtering on store categories in this example, these options are supplied in a static choice list named ‘us_stores_cat’ which is used by the select_one question ${store_cat2} in this case:
The explanations for these example search expressions should improve your understanding of dynamic choice lists in Survey123. You can use the ‘Dynamic Choice Lists using Search Appearance’ sample available in Survey123 Connect to view how these examples work and edit them to fit your needs.