Components

customdropdowndatafetchpaginated

A paginated dropdown that fetches options through the integration engine. It can also re-fetch when another form field changes.

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.

When to use

  • Options must come through the integration engine (an endpointCode is required)
  • The list is large enough to need pagination
  • The available options depend on the value of another field in the form (optional — this component also works with no dependency, as a plain integration-backed lookup)

When NOT to use

Instead of customdropdowndatafetchpaginated, use…For…
customdropdownpaginatedA direct backend API call (no integration endpoint)
customdropdownSmall static option lists
customcascadingdropdownsHard-wired province → district → sector hierarchies

Props

PropTypeRequired?Description
labelstringrequiredDisplay label; must be unique across the form.
bindLabelstringrequiredKey in each option object used as the display text.
bindValuestringrequiredKey in each option object used as the stored value.
urlstringrequiredIntegration engine API URL (typically /integration/v1/fetch/sync).
endpointCodestringrequiredIntegration endpoint code sent in the request payload.
dataset.dataFieldstringrequiredDot-notation path to the array of options inside the integration response.
dataset.paginationbooleanrequiredMust be true to enable load-more scrolling.
requiredbooleanrequiredAlways false. The expression controls the runtime value.
defaultRequiredbooleanrequiredtrue for required fields, false for optional ones.
useBaseUrlbooleanoptionalPrepend the API gateway base URL to url. Set true for production.
dataset.httpMethodstringoptional'GET' or 'POST'. Default 'POST'.
dataset.paramsobjectoptionalExtra params merged into the integration request payload.
dataset.headersobjectoptionalExtra HTTP headers.
dataset.totalPagesKeystringoptionalPath to total pages in the response. Default 'totalPages'.
dataset.currentPageKeystringoptionalPath to current page in the response. Default 'currentPage'.
dataset.pageKeystringoptionalParam name for page number in the request. Default 'page'.
dataset.sizeKeystringoptionalParam name for page size in the request. Default 'size'.
dataset.pageStartnumberoptionalInitial page number. Default 0.
dataset.searchingbooleanoptionalShows 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.searchLocalbooleanoptionalWhen true, filters already-loaded items client-side instead of calling the API. Do not combine with searching: true.
dataset.searchKeystringoptionalParam name for the search value in API requests. Default 'search'.
triggerTypestringrequiredAlways '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.
payloadKeystringoptionalField 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.
useMultiplePayloadKeysbooleanoptionalWhen true, use payloadKeyMappings instead of payloadKey.
payloadKeyMappingsarrayoptionalMultiple 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.
debounceTimenumberoptionalMilliseconds to debounce field-listener re-fetches. Default 500.
populatesarrayoptional{ valueKey, targetKey } mappings to auto-fill downstream fields on selection.
placeholderstringoptionalGhost text shown before a value is selected.
multiplebooleanoptionalAllows selecting multiple values.
virtualScrollbooleanoptionalEnables virtual scrolling.
minnumberoptionalMinimum number of selectable items when multiple: true.
maxnumberoptionalMaximum number of selectable items when multiple: true.
hideFieldbooleanoptionalHides the field and excludes its value from submission. Toggle via expressions["props.hideField"].

Examples

Minimal — doctor lookup via integration, no dependency

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

Full example — country lookup that re-fetches when gender changes

{
  "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."
    }
  }
}

Common mistakes

  • Omitting 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.
  • Omitting endpointCode — the component silently makes no requests and the list stays empty.
  • Omitting dataset.pagination: true — load-more never triggers.
  • Confusing props.url with dataset.url — this component reads the URL from props.url, not dataset.url.
  • Using customdropdowndatafetchpaginated when no endpointCode exists — use customdropdownpaginated instead.
  • Setting dataset.searchLocal: true and dataset.searching: true simultaneously — they serve different purposes; pick one.
  • Setting 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.
  • Setting isStatic: true in a payloadKeyMappings entry but supplying sourceField instead of staticValue — the sent value is undefined.

Checklist

  • key is UPPER_SNAKE_CASE and unique across the entire form
  • props.label is present, unique, and correctly cased
  • Field is nested at the correct depth: sections > formly-group > block > customdropdowndatafetchpaginated
  • required: false is set (never true)
  • defaultRequired is set (true or false)
  • expressions["props.required"] is present with the exact required expression
  • url is the integration endpoint path (typically /integration/v1/fetch/sync); useBaseUrl: true in production
  • endpointCode is set
  • triggerType: 'FIELD_LISTENER' is set, even when the field has no dependency
  • bindLabel and bindValue match real keys in the response option objects
  • dataset.dataField matches the response array path
  • dataset.pagination: true
  • If a dependency drives the fetch, payloadKey or payloadKeyMappings is set; if a mapping is isStatic: true, it carries staticValue, not sourceField
  • searching and searchLocal are not both true
  • validation.messages.required is present when the field is required

On this page