Call it a coincidence, but two people asked me recently how to populate a dropdown list using records from an ArcGIS point layer, and have the form calculate a geopoint when a list choice is selected. The idea is illustrated in the animation below. I will call it a geolist. Patent pending!
I think this is kind of a nice trick, as it allows you to create an alternative experience to define a location: No map, no address... just a list! Your list could display city names, postal codes, hospital names...
This is not really a new concept: In Survey123 Connect we have a survey sample called 'Calculate location from CSV'. However, it is worth revisiting it with a different twist: Using an ArcGIS feature layer instead of a CSV as the source of choices in the list.
I have attached the XLSForm I used to put together the animation above. I bet many of you will not need further explanation, but just in case, I will highlight how all of this works:
The first question in the XLSForm is a select_one. Note that I added the autocomplete and search appearances to it.
autocomplete search("cities_list?url=https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/World_Cities/FeatureServer/0")
The autocomplete appearance is optional, but highly recommended when you work with very long lists.
The search appearance is used to feed the list with records from a layer. You can see the URL of my layer in there. The search appearance indicates the exact layer from which we will populate the list, but not what fields should be used for the label and name of the choices. That, is done in the choices worksheet as shown below:
In this particular case, I chose the CITY_NAME field for the labels, and the OBJECTID for the names, or values. If you save and test your survey at this moment, you will get a list showing all cities in the layer. You do not have to use the OBJECTID for the name. You could use the CITY_NAME again if you like, or any other field that uniquely identifies the record selected.
To get the point geometry of the selected record, we will use the pulldata("@layer") function.
Note that I am using the getValue operation and asking it to return the 'geometry' field on the record that coincides with the OBJECTID selected. The source URL for the pulldata() function is the same as for the list.
pulldata("@layer", "getValue","geometry", "https://services.arcgis.com/P3ePLMYs2RVChkJx/ArcGIS/rest/services/World_Cities/FeatureServer/0", concat("OBJECTID =", ${city}))
The output from this calculation will be a small JSON object that will look something like this:
{"x":20.8320034155833,"y":13.83699601616103}
Typically, you will not want to show this value in the form. To hide the question you can either change the question type to calculate, or apply the hidden appearance.
Next, we are going to calculate the geopoint question with the geometry we have from the selection. Note how the pulldata('@json') function allows us to easily extract the x and y coordinates from the JSON, and how the concat() function is used to compose the actual geometry in the geopoint question.
Technically, you do not need to add the x and y questions into your design. You can construct the geometry object all in one expression:
concat(number(pulldata("@json",${city_JSON},"y")), " ",number(pulldata("@json",${city_JSON},"x")))
As indicated above, you can choose to show or hide the map question. I like to use the hidden appearance on the geopoint question when I need to hide it. If you want to apply conditional visibility to the geopoint question, it is a good idea to set its default value to null. This is to avoid any timing issues where the map question may first try to center at the user's location and then immediately get recalculated to the location of the selected choice.
Remember also to set the bind::esri:fieldType value to null in any question that you do not want to store in the ArcGIS layer. For example, you may not want to store the JSON value.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.