A paginated dropdown that fetches options through the integration engine. It can also re-fetch when another form field changes.
This component always requires triggerType: 'FIELD_LISTENER' in props, even when no other field drives the fetch. This prop starts the initial data load. Without it, the dropdown never loads any options.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
endpointCode is required)Instead of customdropdowndatafetchpaginated, use… |
For… |
|---|---|
customdropdownpaginated |
A direct backend API call (no integration endpoint) |
customdropdown |
Small static option lists |
customcascadingdropdowns |
Hard-wired province → district → sector hierarchies |
| Prop | Type | Required? | Description |
|---|---|---|---|
label |
string |
required | Display label; must be unique across the form. |
bindLabel |
string |
required | Key in each option object used as the display text. |
bindValue |
string |
required | Key in each option object used as the stored value. |
url |
string |
required | Integration engine API URL (typically /integration/v1/fetch/sync). |
endpointCode |
string |
required | Integration endpoint code sent in the request payload. |
dataset.dataField |
string |
required | Dot-notation path to the array of options inside the integration response. |
dataset.pagination |
boolean |
required | Must be true to enable load-more scrolling. |
required |
boolean |
required | Always false. The expression controls the runtime value. |
defaultRequired |
boolean |
required | true for required fields, false for optional ones. |
useBaseUrl |
boolean |
optional | Prepend the API gateway base URL to url. Set true for production. |
dataset.httpMethod |
string |
optional | 'GET' or 'POST'. Default 'POST'. |
dataset.params |
object |
optional | Extra params merged into the integration request payload. |
dataset.headers |
object |
optional | Extra HTTP headers. |
dataset.totalPagesKey |
string |
optional | Path to total pages in the response. Default 'totalPages'. |
dataset.currentPageKey |
string |
optional | Path to current page in the response. Default 'currentPage'. |
dataset.pageKey |
string |
optional | Param name for page number in the request. Default 'page'. |
dataset.sizeKey |
string |
optional | Param name for page size in the request. Default 'size'. |
dataset.pageStart |
number |
optional | Initial page number. Default 0. |
dataset.searching |
boolean |
optional | Shows the search box and sends a search query to the API as the user types. Default true — the search box shows unless you set this to false explicitly. |
dataset.searchLocal |
boolean |
optional | When true, filters already-loaded items client-side instead of calling the API. Do not combine with searching: true. |
dataset.searchKey |
string |
optional | Param name for the search value in API requests. Default 'search'. |
triggerType |
string |
required | Always 'FIELD_LISTENER'. This is what makes the component fetch data at all — not just for re-fetching on a dependency change. Leave it out and the dropdown never loads any options. |
payloadKey |
string |
optional | Field key whose value re-triggers the fetch when it changes. Leave unset for a plain lookup with no dependency — the component still fetches once, on load. |
useMultiplePayloadKeys |
boolean |
optional | When true, use payloadKeyMappings instead of payloadKey. |
payloadKeyMappings |
array |
optional | Multiple payload params — each { key, sourceField, isStatic, staticValue }. Set staticValue when isStatic: true; a mapping with isStatic: true and only sourceField sends undefined for that param. |
debounceTime |
number |
optional | Milliseconds to debounce field-listener re-fetches. Default 500. |
populates |
array |
optional | { valueKey, targetKey } mappings to auto-fill downstream fields on selection. |
placeholder |
string |
optional | Ghost text shown before a value is selected. |
multiple |
boolean |
optional | Allows selecting multiple values. |
virtualScroll |
boolean |
optional | Enables virtual scrolling. |
min |
number |
optional | Minimum number of selectable items when multiple: true. |
max |
number |
optional | Maximum number of selectable items when multiple: true. |
hideField |
boolean |
optional | Hides the field and excludes its value from submission. Toggle via expressions["props.hideField"]. |
triggerType: 'FIELD_LISTENER' is set even though nothing depends on another field. Without it, the component never fetches and the dropdown stays empty.
{
"key": "DOCTOR",
"type": "customdropdowndatafetchpaginated",
"props": {
"label": "Doctor",
"required": false,
"defaultRequired": true,
"bindLabel": "fullName",
"bindValue": "id",
"url": "/integration/v1/fetch/sync",
"endpointCode": "LIST_DOCTORS",
"useBaseUrl": true,
"triggerType": "FIELD_LISTENER",
"dataset": {
"params": { "page": 0, "size": 20 },
"dataField": "doctors",
"pageStart": 0,
"pagination": true
}
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "Doctor is required."
}
}
}
{
"key": "APPLICANT_NATIONALITY_2",
"type": "customdropdowndatafetchpaginated",
"props": {
"url": "/integration/v1/fetch/sync",
"label": "Nationality",
"required": false,
"defaultRequired": true,
"bindLabel": "name",
"bindValue": "countryCode",
"useBaseUrl": true,
"placeholder": "Select country",
"triggerType": "FIELD_LISTENER",
"endpointCode": "RDB_COUNTRIES_FETCH",
"useMultiplePayloadKeys": true,
"payloadKeyMappings": [{ "key": "searchkey", "sourceField": "APPLICANT_GENDER_2" }],
"dataset": {
"params": { "page": 0, "size": 20 },
"dataField": "data.data",
"pageStart": 1,
"searching": true,
"pagination": true,
"totalPagesKey": "data.totalElements"
}
},
"expressions": {
"hide": "!(model?.APPLICANT_DOCUMENT_TYPE === 'Passport')",
"props.disabled": "model?.IS_RESUBMITTED",
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "Nationality is required."
}
}
}
triggerType: 'FIELD_LISTENER' — this is the most common cause of an empty dropdown. Without it, the component never calls the API, even with a valid endpointCode and no dependency field.endpointCode — the component silently makes no requests and the list stays empty.dataset.pagination: true — load-more never triggers.props.url with dataset.url — this component reads the URL from props.url, not dataset.url.customdropdowndatafetchpaginated when no endpointCode exists — use customdropdownpaginated instead.dataset.searchLocal: true and dataset.searching: true simultaneously — they serve different purposes; pick one.dataset.searching: false to hide the search box, then forgetting it defaults to true elsewhere — check every field that should not show a search box.isStatic: true in a payloadKeyMappings entry but supplying sourceField instead of staticValue — the sent value is undefined.key is UPPER_SNAKE_CASE and unique across the entire formprops.label is present, unique, and correctly casedsections > formly-group > block > customdropdowndatafetchpaginatedrequired: false is set (never true)defaultRequired is set (true or false)expressions["props.required"] is present with the exact required expressionurl is the integration endpoint path (typically /integration/v1/fetch/sync); useBaseUrl: true in productionendpointCode is settriggerType: 'FIELD_LISTENER' is set, even when the field has no dependencybindLabel and bindValue match real keys in the response option objectsdataset.dataField matches the response array pathdataset.pagination: truepayloadKey or payloadKeyMappings is set; if a mapping is isStatic: true, it carries staticValue, not sourceFieldsearching and searchLocal are not both truevalidation.messages.required is present when the field is required