Динамично търсене
Динамичното търсене зарежда опции от отдалечен API в реално време, докато анкетьорът пише, позволявайки работа с големи или часто актуализирани набори от данни.
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)
Параметри
| Parameter | Description |
|---|---|
method | Always use 'POST' |
url | The API endpoint to query |
post_body | JSON body sent to the API. Use %__input__% as a placeholder for the enumerator’s current search text |
value_column | The key in the response object to use as the stored value |
display | The key (or template) to use as the label shown in the dropdown. Supports ##key## placeholders and @{func} expressions |
data_path | JSONPath to the array of result objects in the response (e.g., $.data, $.hits.hits.*._source) |
save_path | A 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:
| type | name | label | appearance |
|---|---|---|---|
| select_one | facility | Select health facility | search-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 type | Use case |
|---|---|
select_one | Single selection from search results |
select_multiple | Multiple selections from search results |
text | Autocomplete — 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():
| type | name | label | calculation |
|---|---|---|---|
| select_one | facility | Select facility | search-api(..., 'facility_data') |
| calculate | facility_district | pulldata('facility_data', 'district') | |
| calculate | facility_type | pulldata('facility_data', 'type') |
Best Practices
- Ensure your API endpoint responds within 1–2 seconds — slow APIs make the search feel unresponsive.
- Use
%__input__%in thepost_bodyso the API only returns matching results, not the entire dataset. - Index the search field on the server side (e.g., Elasticsearch, database full-text index) for fast responses.
- Limit results to 20–50 items per query — returning thousands of results defeats the purpose of search.
- 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.