Dynamic Choice Lists using Search Appearance

67373
74
05-23-2021 09:45 PM
BrettStokes
Esri Regular Contributor
18 74 67.4K

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.

BrettStokes_0-1631753728945.png

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):

  • search(‘usa_states’)

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:

BrettStokes_1-1631753728954.png

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:

BrettStokes_2-1631753728963.png

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.

BrettStokes_3-1631753728967.png

 

BrettStokes_4-1631753728968.png

 

BrettStokes_5-1631753728969.png

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):

BrettStokes_6-1631753728969.png

  • REST endpoint URL including the layer index (0):

BrettStokes_7-1631753728970.png

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:

BrettStokes_8-1631753728971.png

searchColumn:

  • using ‘@geoshape’ for this spatial query, as this is the query geometry type (ie polygon / geoshape):

BrettStokes_9-1631753728972.png

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:

BrettStokes_10-1631753728973.png

 

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.

BrettStokes_11-1631753728989.png

BrettStokes_12-1631753728991.png

BrettStokes_13-1631753728994.png

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:

BrettStokes_14-1631753728996.png

  • REST endpoint URL including the layer index (0):

BrettStokes_15-1631753728999.png

  • 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}.

BrettStokes_16-1631753729001.png

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:

BrettStokes_17-1631753729002.png

searchColumn:

  • using ‘@geopoint’ for this spatial query as this is the query geometry type (ie the location point):

BrettStokes_18-1631753729003.png

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:

BrettStokes_19-1631753729005.png

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).

BrettStokes_20-1631753729006.png

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:

BrettStokes_21-1631753729007.png

 

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.

Tags (1)
74 Comments
ChristopherDawe
Regular Contributor

Hi @BrettStokes ,

This is a very useful tool, thanks! however i am struggling to get some of the functionality to work properly and understanding the filter lists and search text etc.  

I have a survey where a user will go out and set up some equipment and collect data on locations using a repeat ('LTVSRecord') including a project number (${LTVSprojectName}) covering all locations and then input individual location references ($LTVSlocationRef}) for each one

Some time later the surveyor will go back out and using a different repeat (LTVCRecord) to add more information about these locations. I have successfully managed to have a drop down list of the projects but am struggling at getting a secondary drop down list to show the available locations within that project.

my first select_one question (${LTVCprojectName}) for the project looks like the below and is working as expected and provides the drop down list to select projects 

autocomplete search('LTVSRecord?url=https://services7.arcgis.com/CJWMHSBPXpojJnX3/arcgis/rest/services/service_78264694bba54e2dbe6808312...}')

the second select_one question should filter the location references in the same table where the project number matches what is selected from the above - field name ${LTVClocationRef}

autocomplete search('LTVSRecord?url=https://services7.arcgis.com/CJWMHSBPXpojJnX3/arcgis/rest/services/service_78264694bba54e2dbe6808312...}','searchText','LTVSprojectName',${LTVCprojectName})

if i remove the searchText, filterColumn, and filterText parts, i can return a full list of everything that might be stored within the LTVSlocationRef field but i need it filtered by the project and cannot seem to get it working, any help would be massively appreciated

 

Many Thansk

Chris

KyleHeulitt2
Occasional Contributor

Hey Chris,

If I understand correctly, I think this will accomplish what you are trying to do:

Note: Had to edit this post because the autoformatting is preventing the formula from posting properly.  Replace the text after the URL with the following:

'matches','LTVSprojectName',${LTVCprojectName})

The parameters used are SearchType, SearchColumn, and SearchText.  The formula above searches the LTVSprojectName column for matches from the ${LTVCprojectName} question.  Note the ${LTVCprojectName} question would need to be answered first.

Kyle

Luiz_RobertoArueira_da_Silva
Occasional Contributor

Helo!
Can anyone tell me if it is possible to use this function to obtain unique values from a layer? Something like a group by?
Thanks?

DougYurek
Occasional Contributor

I am trying to add a where clause to the URL parameter but I don't believe it's being honored. I have a feature service with 10 types of facilities, but I only want a couple types to show up in the Search(). 

Unless I'm doing something wrong, I don't think the Search() function is honoring the where clause in this URL.

For Example, I want to do something similar to what is below. 

concat("facility?url=https://abcd.abcd@domain.com/portal/rest/services/MyServices/MyService/FeatureServer/0/query?where=S...",${search_distance},"&units=esriSRUnit_StatuteMile")

I understand if I wanted to Filter for Compressor Station I can put it in the searchText parameter, but I want more than one type to be included in in the filter. 

MarcMuehleisen
Occasional Contributor

Hey. I am sucessfully using this approach to query a hosted non-spatial table that gets populated from another database. I have two questions regarding this:

1. Is there a way to increase the size of the box where the answers are presented when choosing the autocomplete search() appereance? Or at least control it to some degree? I know that every user can increase the overall text size in his app settings, but as a designer in Survey123 Connect i have no options here, do i?

2. How can i refresh the choices while recording data? Basically having it in real-time when some data in my hosted table is being edited while someone is recording data?
So far i tested it and it seems to only query the choices once the survey is being opened and after that, no updates seem to happen. 
Could anyone clarify, if this is a technical limitation or if there is a workaround like having a refresh button? I tried it with a relevant statement, but that did not work.

Thank you!

RobertAnderson3
MVP Regular Contributor

@Hangglide 

I know your post is from a while ago, but I'm looking to do the same thing, I have asset IDs that I want stored as the value, but for the user they want additional information in the drop down list.

You say you mostly resolved it by changing the name and label fields on the choice list, how so?

Would it be possible for me to have it query the layer and combine two fields? Like (UNITID)+(Description)?

RobertAnderson3_0-1705000609436.png

 

AndrewWallick
Frequent Contributor

Hi @BrettStokes or anyone else who might have an idea: I'm trying to have users input a parcel number (polygon ID number), then have the survey pull which address point features are in that parcel. The trick is, I want the users to be able to enter a different address if they want to. Is this possible? Maybe using an "other" option. I also would like there to be a "None" option if possible.

 

The other tricky thing about what I'm trying to do is this - I'd like the users to be able to:
1) Type in parcel number
2) Have an address auto-populate in an address question
3) Have a geopoint question zoom to the address selected; or if none is selected then the parcel in question, with the point selector starting at some area in the parcel.

Is this possible? My users (appraisers) mostly care about the APN, but we need to capture the address as well, and I want my output data to be in a point feature class.

MarcMuehleisen
Occasional Contributor

Hello @BrettStokes and others!

The documentation gives us this example search: 

search('csvName', 'matches', 'breed', ${DogQuestion})

Is it also possible to have multiple conditions f.e. connected with another column like 'matches', 'status_code', '1' where i would filter according to a status that is either 1 or 0?

The documentation and this blog are not talking about this so i suppose this is a technical limitation?

ChrisJRoss13
Occasional Contributor

@IsmaelChivite What happens when you are developing a choice list from a feature layer service and the field name list place holder variable is longer than the acceptable length of any input value?

My example is, I am using the select_one AboiteauIDs. The feature service field name that I need is AboiteauID. My apperance section is 

autocomplete search("AboiteauID?url=https://services6.arcgis.com/LToPLrsKQBrQZIJZ/arcgis/rest/services/Aboiteaux_with_Tracking_(View)/Fe...")

 

In the choices section the list name is AboiteauIDs with AboiteauID for the name and label. I have a max value length for this field as 9. The choice list works but when I go to publish the form, I get the error: 

ChrisJRoss13_0-1712287860675.png

Any way I can get around this without having to change the accepted field value length?

 

abureaux
MVP Frequent Contributor

@ChrisJRoss13You set your field length to "9" in S123 Connect and are trying to publish to a preexisting feature layer. In that preexisting feature layer, your field length is not "9". Go to the feature layer in Portal and check how long the field length actually is. You can change your preexisting feature layer to be "9" and then go back to Connect and re-publish.

To do this...

  1. Go to your Portal
  2. Locate the Feature Layer and open it
  3. Click "Data" then "Fields"
    abureaux_0-1712326317916.png
  4. Locate AboiteauActivityTracking and click on it
  5. Check the actual field length
    abureaux_1-1712326384102.png
  6. EDIT: forgot to mention, but to update a field length, you will most likely need to delete and recreate this field in Portal. Alternatively, you could also republish from ArcPro.
ChrisJRoss13
Occasional Contributor

@abureaux  My field length is 9. See below.

ChrisJRoss13_0-1712326545372.png

 

abureaux
MVP Frequent Contributor

@ChrisJRoss13My bad. I read the field name as AboiteauActivityTracking, but that is the layer.

In the top left of that same page on Portal, are you in the correct layer (i.e., AboiteauActivityTracking)?

abureaux_2-1712326800484.png

I am wondering if there are duplicate fields named AboiteauID.

Given that this issue is related to republishing, if this doesn't resolve the issue, you may wish to create a new thread as it will be easier to help there. Be sure to include your XLSX if you do make a new thread.

ChrisJRoss13
Occasional Contributor

@abureauxI've confirmed I'm working within the correct layer. The problem arises with the use of the autocomplete search() function on a hosted feature layer. When incorporating a select_one option in the choices tab of the survey, it's necessary to define the list name. Additionally, in both the name and label columns, the queried field name must be specified. For our situation, that field name is 'AboiteauID'. Essentially, 'AboiteauID' acts as a temporary marker. As the search() function executes, it generates a list of actual 'AboiteauID' values, each no longer than 9 characters. However, Survey123 Connect interprets the field name 'AboiteauID' itself as a selectable option within the list, leading to a discrepancy as it exceeds the 9-character limit by being 10 characters long. This discrepancy triggers an error. I'm seeking a solution to utilize 'AboiteauID' values in the choice list without encountering this error.

abureaux
MVP Frequent Contributor

Right. I see what you are saying now (I was able to recreate this issue). Seems like a bug. And the bug appears upon every publish attempt. This would need to be logged with Esri support and a deficiency created. I'd recommend calling support to get this process started.

Publish #1:
abureaux_0-1712328549037.png
abureaux_1-1712328584334.png

Publish #2:

abureaux_2-1712328590503.png

 

But this doesn't help you right NOW... So, I will ask: Do you really need to specify a field length on a select_one? Seems redundant. Removal of that limitation should resolve your issue I'd think. And being a select_one, the user can only select what you specify anyways.

ChrisJRoss13
Occasional Contributor

@abureaux Appreciate you looking into this deeper. I will likely log with Esri support. I am not specifying a field length on the select_one. The field length definition comes from the original hosted feature layer which is used in other applications including map viewer, field maps. I had the field length set to 9 to ensure that they values that get entered via map viewer/field maps are not longer than this value. This was done before I planned to use Survey123 as well. I will likely have another scenario where this error will occur. If I am carrying out the same search() function on a field that has a domain. The field name will be longer and the values will be restricted to that are which defined by the domain. May have to see what comes back from support.

JCable
by
Regular Contributor

@PeterMacKenzie2 

I'm curious how you got it to work for you. What you described sounds similar to what I'm attempting to accomplish. Basically, I want the question to provide a choice list of unique values from previously submitted survey responses, but also give users the option to add their own value if it has not been submitted before. This last part is especially important for the first person submitting a response to my survey!

I've got the search() functionality working, but it won't let me add my own value

So if previous submissions for a question include 'T1', 'T2' and 'T3', I can get the 3 options to appear in the choice list. I need to give users the ability to input new values (e.g. 'T4') so that subsequent survey users will see 4 options appear in the choice list...

GarrettFast
New Explorer

I just want to say thank you Brett! I was having issues with dynamic pick lists from feature layers and this post cleared it all up for me. 

KristinThorpe1
Regular Contributor

@JCable Any update on this? I also want to have a "New" option in a dynamic list.

So far I have a dynamic list of existing clients and a separate Yes/No, select_one question for if the user wants to add a new client, which will display a group of textboxes to input new client information. I added a hidden question that will calculate to either the selected client from the list or the new input depending what is selected for the yes/no question. This works, but I think it would be better from a user perspective to have a "New" option in the dynamic list.

JCable
by
Regular Contributor

@KristinThorpe1 No, nothing, sorry. I had to move on to other, more pressing tasks and haven't been able to come back to dive into this more

SamBialorucki
Frequent Explorer

@RobertAnderson3 Did you ever figure out how to do this? I'm also trying to do this but I didnt see if @Hangglide replied to you or not.

SWT_TL
by
Emerging Contributor

Hi there,

I have used this solution to generate a dynamic choice list for my survey and it works, but seemingly only for me... Any users are getting an error message saying "failed to load the choice list".

Full issue is detailed here: https://community.esri.com/t5/arcgis-survey123-questions/survey123-quot-failed-to-load-the-choice-li...

Any solutions would be greatly appreciated as I'm struggling to find more information on the problem.

Thanks!

BrandonA_CDPH
Frequent Contributor

@SWT_TL- Is this an external choice list (csv)? I have had issues with external choice lists not being shared to the same group as the form (i.e. user can access the form, but not the choice list). You can update sharing for the external choice similarly to other items in your portal.

SWT_TL
by
Emerging Contributor

Hi @BrandonA_CDPH,

This is occurring when using the feature layer connected to the form itself, so they definitely have access. Maybe something is going on with permissions but it would be strange for publicly available surveys not be able to use the search expression for their own layer.

I have used a csv in the media folder to get round the problem, but it means my survey is now much less dynamic as new options need to be sent to me to be added for the list before users can select them from the choice list, rather than being added by them through the form once and thereafter being available in the choice list.

MaazaMekuria
Frequent Contributor

It was not clear to me first since the field name in the choices list was not the same as in the underlying feature class that was given.  The STATE_NAME field does not exist in the underlying feature class as provided in the link, but once I read the documentation that it should be the actual field, it worked.

Also it is confusing to have the table name in the search without any usefulness and the documentation does not provide reasons why it should even be there.  But It probably acts the same as a choice table name?  It would be nice to include some documentation as to the purpose of the search table parameter. 

Thank you!