Dynamic Search (also called Search API) allows a select_one, select_multiple, or text field to load its choices from a remote web service at runtime as the enumerator types. This is the right approach when your choice list is too large to bundle in a CSV file, is updated frequently, or comes from a live database.


search-api() appearance

The dynamic search is configured through the appearance column using the search-api() function:

  search-api(method, url, post_body, value_column, display, data_path, save_path)
  

Параметри

ParameterDescription
methodAlways use 'POST'
urlThe API endpoint to query
post_bodyJSON body sent to the API. Use %__input__% as a placeholder for the enumerator’s current search text
value_columnThe key in the response object to use as the stored value
displayThe key (or template) to use as the label shown in the dropdown. Supports ##key## placeholders and @{func} expressions
data_pathJSONPath to the array of result objects in the response (e.g., $.data, $.hits.hits.*._source)
save_pathA name under which the raw response is saved for use by other fields

Основно example

A health facility lookup where the enumerator types part of the facility name:

typenamelabelappearance
select_onefacilitySelect health facilitysearch-api('POST', 'https://api.example.com/facilities/search', '{"query": "%__input__%"}', 'id', 'name', '$.results', 'facility_data')

The API receives {"query": "nair"} when the enumerator types “nair” and returns:

  {
  "results": [
    {"id": "HF001", "name": "Nairobi Central Clinic"},
    {"id": "HF002", "name": "Nairobi West Hospital"}
  ]
}
  

The dropdown shows Nairobi Central Clinic and Nairobi West Hospital; the stored value is HF001 or HF002.


Разширено display formatting

Using ##key## templates

Show multiple fields in the label:

  search-api('POST', 'https://api.example.com/search', '{"q": "%__input__%"}', 'id', '##name## (##district##)', '$.data', 'res')
  

Displayed as: Nairobi Central Clinic (Nairobi).

Using @{func} expressions

Apply conditional logic in the display label:

  search-api('POST', 'https://api.example.com/search', '{"q": "%__input__%"}', 'id',
  '@{if_else(eq("##status##", "active"), "✓ ##name##", "✗ ##name##")}',
  '$.data', 'res')
  

Active results show ✓ Clinic Name; inactive show ✗ Clinic Name.


Setting a default value: search-default-api()

Use search-default-api() after search-api() to pre-populate the field with a default choice loaded from a separate API call (e.g., when editing an existing record):

  appearance: search-api(...) search-default-api('POST', 'https://api.example.com/get', '{"id": "##saved_id##"}', 'id', 'name', '$.item')
  

Custom separator for select_multiple: search-default-separator()

For select_multiple fields, specify how multiple selected values are joined in the stored string:

  appearance: search-api(...) search-default-separator(' || ')
  

Default separator is a space.


Supported question types

Question typeUse case
select_oneSingle selection from search results
select_multipleMultiple selections from search results
textAutocomplete — enumerator types freely but can select a suggestion

Using saved response data

The save_path stores the full API response object under the given name. Other fields can reference it with pulldata():

typenamelabelcalculation
select_onefacilitySelect facilitysearch-api(..., 'facility_data')
calculatefacility_districtpulldata('facility_data', 'district')
calculatefacility_typepulldata('facility_data', 'type')

Best Practices

  1. Ensure your API endpoint responds within 1–2 seconds — slow APIs make the search feel unresponsive.
  2. Use %__input__% in the post_body so the API only returns matching results, not the entire dataset.
  3. Index the search field on the server side (e.g., Elasticsearch, database full-text index) for fast responses.
  4. Limit results to 20–50 items per query — returning thousands of results defeats the purpose of search.
  5. Include a minimum input length requirement in the API to avoid triggering broad queries on single-character inputs.

Limitations

  • Dynamic Search requires network connectivity — it does not work offline.
  • The %__input__% placeholder is injected as-is; sanitise inputs on the server side to prevent injection attacks.
  • Complex @{func} display expressions may have limited support across all rtSurvey client versions.
Беше ли полезна тази страница?