custommultiselectdatafetch
A search-filter form plus results table with checkbox selection, driven by an integration engine endpoint. Use when the user must search a dynamic dataset and pick one or more results.
A search-filter form plus results table with checkbox selection, driven by an integration engine endpoint. The user fills filter inputs, clicks search, and selects one or more rows; the field value is an array of full row objects for every checked row.
Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.
When to use
- Searching a large dynamic dataset via filter inputs (e.g. "find students by name and school code")
- Multi-row selection where each row carries multiple data points the form needs to keep
- API-driven pickers with optional pagination
- Selection summaries showing counts, sums, or first-row metadata
When NOT to use
Instead of custommultiselectdatafetch, use… | For… |
|---|---|
customdropdown | Small static lists, or single-select API-driven dropdowns |
customgenericdatafetch | A single input that triggers a lookup and populates other fields (no row table, no multi-pick) |
customdropdownpaginated | Paginated dropdowns where the user selects exactly one option from the list |
This is the multi-select sibling of the data-fetch family: instead of one input → one populated record, the user runs a search and picks multiple rows.
How it works
- The component renders one or more search-filter input fields above a results table.
- The user fills in the filters and clicks the search button.
- The component POSTs to
props.urlwith this shape:{ "endpointCode": "YOUR_ENDPOINT_CODE", "payload": { "filterKey": "filterValue" } } - Results populate the table; each row has a checkbox.
- The field value is an array of full row objects for every checked row.
Props
Core (required)
| Prop | Type | Required? | Description |
|---|---|---|---|
label | string | required | Display label; must be unique across the entire form. |
url | string | required | Integration engine endpoint path (e.g. /integration/v1/data-fetch). |
endpointCode | string | required | Endpoint code sent in every POST payload. |
inputFields | InputFieldConfig[] | required | Search-filter inputs shown above the table. |
columns | MultiSelectTableColumn[] | required | Column definitions for the results table. |
dataPath | string | required | Dot-notation path to the results array in the API response (e.g. "data.content"). |
Selection and data extraction
| Prop | Type | Required? | Description |
|---|---|---|---|
selectionKey | string | optional | Key in each row used to track selection identity; defaults to "id". |
useBaseUrl | boolean | optional | Prepend the API gateway base URL; set true for integration engine calls. |
paginationConfig | PaginationConfig | optional | Enables paginated results; omit when the API returns all results at once. |
Display text
| Prop | Type | Required? | Description |
|---|---|---|---|
tableTitle | string | optional | Heading displayed above the results table; defaults to "Results". |
tableDescription | string | optional | Sub-heading below the title; defaults to "Please select items before continuing.". |
emptyMessage | string | optional | Message shown when the search returns no results; defaults to "No results found.". |
validateButtonLabel | string | optional | Label for the search trigger button; defaults to "Validate". |
Payload construction
| Prop | Type | Required? | Description |
|---|---|---|---|
useMultiplePayloadKeys | boolean | optional | Set true to enable payloadKeyMappings. |
payloadKeyMappings | PayloadKeyMapping[] | optional | Maps form fields or static values into the request payload; only active when useMultiplePayloadKeys is true. |
Preview and errors
| Prop | Type | Required? | Description |
|---|---|---|---|
previewMetadata | PreviewMetadataConfig[] | optional | Metadata entries for the selection summary panel shown after selection. |
disabled | boolean | optional | Disables the entire widget. |
showGlobalError | boolean | optional | Shows a global error banner on request failure. |
errorMapping | object | optional | Maps integration error codes to user-facing messages. |
PaginationConfig shape
{
"pageablePath": "data.pageable",
"totalElementsPath": "data.totalElements",
"totalPagesPath": "data.totalPages"
}PayloadKeyMapping shape
[
{ "key": "districtCode", "sourceField": "district" },
{ "key": "year", "isStatic": true, "staticValue": 2024 }
]InputFieldConfig shape
| Field | Type | Required? | Description |
|---|---|---|---|
key | string | required | Parameter name sent in the POST payload. |
label | string | required | Display label for the input. |
type | string | optional | HTML input type: "text" (default), "number", "email". |
placeholder | string | optional | Ghost text. |
hint | string | optional | Helper text below the input. |
required | boolean | optional | Prevents search until filled. |
pattern | string | optional | Regex validation pattern. |
minLength | number | optional | Minimum character count. |
maxLength | number | optional | Maximum character count. |
defaultValue | string | optional | Pre-filled value. |
MultiSelectTableColumn shape
| Field | Type | Required? | Description |
|---|---|---|---|
header | string | required | Column heading text. |
field | string | required | Top-level key in each row object. |
dataPath | string | optional | Dot-notation path for nested values (e.g. "school.name"). |
formatter | string | optional | "date", "currency", "array-first-name". |
PreviewMetadataConfig shape
| Field | Type | Description |
|---|---|---|
key | string | Unique identifier for this metadata entry. |
label | string | Display label. |
type | "count" | "sum" | "first" | "input" | "static" | How the value is computed from selected rows. |
sourceField | string | Row field used for sum / first computation. |
formatter | "currency" | "number" | "date" | Optional display formatter. |
prefix | string | Text prepended to value (e.g. "RWF "). |
suffix | string | Text appended to value (e.g. " items"). |
Validation
Only required is registered and functional. minSelection / maxSelection are defined in EIremboFormlyValidationTypes but not registered in formlyConfigs() — they have no effect at runtime; do not use them.
"validation": {
"messages": {
"required": "At least one item must be selected"
}
}Examples
Minimal — search students by name
{
"key": "SELECTED_STUDENTS",
"type": "custommultiselectdatafetch",
"props": {
"label": "Students",
"url": "/integration/v1/data-fetch",
"endpointCode": "SEARCH_STUDENTS",
"useBaseUrl": true,
"inputFields": [{ "key": "name", "label": "Name", "required": true }],
"columns": [
{ "header": "Full Name", "field": "fullName" },
{ "header": "Student ID", "field": "studentId" }
]
},
"validation": {
"messages": {
"required": "At least one student must be selected"
}
}
}Full — pagination, multiple filters, payload mappings, preview metadata
{
"key": "SELECTED_STUDENTS",
"type": "custommultiselectdatafetch",
"props": {
"label": "Students",
"url": "/integration/v1/data-fetch",
"endpointCode": "SEARCH_STUDENTS",
"useBaseUrl": true,
"selectionKey": "studentId",
"dataPath": "data.content",
"tableTitle": "Search Results",
"tableDescription": "Select one or more students from the list below",
"emptyMessage": "No students found. Try a different name or ID.",
"validateButtonLabel": "Search",
"inputFields": [
{
"key": "name",
"label": "Name",
"type": "text",
"placeholder": "Enter student name",
"required": true,
"minLength": 2
},
{
"key": "schoolCode",
"label": "School Code",
"type": "text",
"placeholder": "e.g. SCH-001"
}
],
"columns": [
{ "header": "Full Name", "field": "fullName" },
{ "header": "Student ID", "field": "studentId" },
{ "header": "Date of Birth", "field": "dateOfBirth", "formatter": "date" },
{ "header": "School", "field": "school", "dataPath": "school.name" }
],
"paginationConfig": {
"pageablePath": "data.pageable",
"totalElementsPath": "data.totalElements",
"totalPagesPath": "data.totalPages"
},
"useMultiplePayloadKeys": true,
"payloadKeyMappings": [
{ "key": "districtCode", "sourceField": "DISTRICT" },
{ "key": "year", "isStatic": true, "staticValue": 2024 }
],
"previewMetadata": [
{
"key": "selectedCount",
"label": "Selected Students",
"type": "count",
"suffix": " items"
},
{
"key": "totalFees",
"label": "Total Fees",
"type": "sum",
"sourceField": "tuitionFee",
"formatter": "currency",
"prefix": "RWF "
}
]
},
"validation": {
"messages": {
"required": "At least one student must be selected"
}
}
}Common mistakes
- Omitting
endpointCode— the component makes no request; the results table stays empty with no visible error. - Omitting
inputFields— no search form renders; the user has no way to trigger the fetch. - Omitting
columns— the table renders with no headers or data even if the API returns results. - Using
props.dataset.urlinstead ofprops.url— this component reads only fromprops.url, notprops.dataset. - Setting
selectionKeyto a field absent from some rows — selection tracking breaks silently for those rows. - Using
minSelectionormaxSelectionvalidators — defined inEIremboFormlyValidationTypesbut not registered informlyConfigs(); they have no effect at runtime. - Providing
payloadKeyMappingswithout settinguseMultiplePayloadKeys: true— the mappings are ignored. - Setting
dataPathto a key whose value is not an array — the table renders nothing. - Expecting the field value to be an array of IDs — the value is always an array of full row objects; extract the ID in the submission mapping if needed.
Checklist
-
keyisUPPER_SNAKE_CASEand unique across the entire form -
props.labelis present, unique, and correctly cased -
url,endpointCode, anduseBaseUrl: trueare set -
inputFieldsdefines at least one search filter -
columnsdefines every column shown in the results table -
dataPathmatches the array path returned by the endpoint -
selectionKeymatches a unique field present on every row -
paginationConfigis set whenever the API returns paginated results -
useMultiplePayloadKeys: truewheneverpayloadKeyMappingsis set -
validation.messages.requiredis present - Not using the un-registered
minSelection/maxSelectionvalidators
customlabelvaluerepeater
A simple user-driven repeater where each row is a small label/value template. Use when the applicant manually adds and removes rows.
customotpdatafetch
A visible recipient input that sends an OTP to a phone or email, prompts for verification, and then triggers a background data fetch on success.