customcascadingdropdowns
A multi-level cascading dropdown for hierarchical selection. Each level filters the options available in the next level based on the parent selection.
A multi-level cascading dropdown for hierarchical selection. Each level filters the options available in the next level based on the parent selection.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
When to use
- Rwanda administrative location selection (Province → District → Sector → Cell → Village)
- Any hierarchical selection where each level depends on the parent
When NOT to use
Instead of customcascadingdropdowns, use… | For… |
|---|---|
customdropdown | A flat, non-hierarchical list |
Props
| Prop | Type | Required? | Description |
|---|---|---|---|
label | string | required | Visible label for the overall field group. |
required | boolean | required | Always false. The expression controls the runtime value. |
defaultRequired | boolean | required | true for required fields, false for optional ones. |
configs | array | required | Ordered array of level definitions, top to bottom. See below. |
locationFirstLevel | string | required | Top-most level key (e.g. "PROVINCE"). |
locationLastLevel | string | required | Bottom-most level key (e.g. "VILLAGE"). |
hideLabel | boolean | optional | Set true to hide the component-level label (individual level labels are still shown). |
placeholder | string | optional | Ghost text for the first level dropdown. |
hideField | boolean | optional | Hides the entire component. Toggle via expressions["props.hideField"]. |
configs array — per-level definition
One entry per level, in order from top to bottom.
| Field | Type | Description |
|---|---|---|
key | string | Model key where this level's selection is stored (e.g. "PROVINCE"). |
label | string | Label shown above this level's dropdown. |
parent | string | null | key of the parent level, or null for the root level. |
parentBindKey | string | The field on the parent's selected object used to filter this level's options. Always "id" for location. |
required | boolean | Whether this level is required. |
bindlabel | string | Key in each option object to display. Always "label" for location. |
bindvalue | string | Key in each option object to store. "" stores the whole object (used for location so child levels can filter by id). |
placeholder | string | Ghost text for this level's dropdown. |
dataset | object | Data source configuration. See below. |
dataset object
| Field | Type | Description |
|---|---|---|
url | string | API path to fetch options. Province uses /by-dataset-code/PROVINCE; all sub-levels use /by-details. |
dataField | string | Key in the API response containing the options array. Always "data" for location. |
useBaseUrl | boolean | Always true — prepends the API gateway base URL. |
Example — full Province → Village location picker
{
"key": "FIELD_LOCATION",
"type": "customcascadingdropdowns",
"props": {
"label": "Location",
"required": false,
"defaultRequired": true,
"locationFirstLevel": "PROVINCE",
"locationLastLevel": "VILLAGE",
"hideLabel": true,
"configs": [
{
"key": "PROVINCE",
"label": "Province",
"parent": null,
"required": true,
"bindlabel": "label",
"bindvalue": "",
"placeholder": "Select Province",
"dataset": {
"url": "/admin/v1/dataset-items/by-dataset-code/PROVINCE",
"dataField": "data",
"useBaseUrl": true
}
},
{
"key": "DISTRICT",
"label": "District",
"parent": "PROVINCE",
"parentBindKey": "id",
"required": true,
"bindlabel": "label",
"bindvalue": "",
"placeholder": "Select District",
"dataset": {
"url": "/admin/v1/dataset-items/by-details",
"dataField": "data",
"useBaseUrl": true
}
},
{
"key": "SECTOR",
"label": "Sector",
"parent": "DISTRICT",
"parentBindKey": "id",
"required": true,
"bindlabel": "label",
"bindvalue": "",
"placeholder": "Select Sector",
"dataset": {
"url": "/admin/v1/dataset-items/by-details",
"dataField": "data",
"useBaseUrl": true
}
},
{
"key": "CELL",
"label": "Cell",
"parent": "SECTOR",
"parentBindKey": "id",
"required": true,
"bindlabel": "label",
"bindvalue": "",
"placeholder": "Select Cell",
"dataset": {
"url": "/admin/v1/dataset-items/by-details",
"dataField": "data",
"useBaseUrl": true
}
},
{
"key": "VILLAGE",
"label": "Village",
"parent": "CELL",
"parentBindKey": "id",
"required": true,
"bindlabel": "label",
"bindvalue": "",
"placeholder": "Select Village",
"dataset": {
"url": "/admin/v1/dataset-items/by-details",
"dataField": "data",
"useBaseUrl": true
}
}
]
},
"expressions": {
"props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
},
"validation": {
"messages": {
"required": "This field is required."
}
}
}The Province level fetches from /by-dataset-code/PROVINCE. Every sub-level (District through Village) fetches from /by-details, passing the parent's selected object's id via parentBindKey: "id". bindvalue: "" stores the whole option object so the child level can read id from it.
Checklist
-
keyisUPPER_SNAKE_CASEand unique across the entire form -
props.labelis present - Field is nested at the correct depth:
sections > formly-group > block > customcascadingdropdowns -
required: falseis set (nevertrue) -
defaultRequiredis set -
expressions["props.required"]is present with the exact required expression -
locationFirstLevelandlocationLastLevelmatch the first and lastkeyinconfigs -
configshas one entry per level, in top-to-bottom order - Root level has
parent: null; all subsequent levels haveparentset to the previous level'skey - Sub-levels (District through Village) have
parentBindKey: "id" -
bindvalue: ""on all levels (stores the whole object so child levels can filter byid) - Province uses
/by-dataset-code/PROVINCE; all other levels use/by-details -
validation.messages.requiredis present
custominternalfileupload
File upload that pre-uploads to the CDN on selection and sends only the CDN reference in the application payload.
customgenericdatafetch
An input field that triggers a backend API lookup through the Irembo gateway and maps the response into downstream form fields. Also covers customdirectdatafetch for calls to arbitrary URLs.