Components

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…
customdropdownSmall static lists, or single-select API-driven dropdowns
customgenericdatafetchA single input that triggers a lookup and populates other fields (no row table, no multi-pick)
customdropdownpaginatedPaginated 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

  1. The component renders one or more search-filter input fields above a results table.
  2. The user fills in the filters and clicks the search button.
  3. The component POSTs to props.url with this shape:
    {
      "endpointCode": "YOUR_ENDPOINT_CODE",
      "payload": { "filterKey": "filterValue" }
    }
  4. Results populate the table; each row has a checkbox.
  5. The field value is an array of full row objects for every checked row.

Props

Core (required)

PropTypeRequired?Description
labelstringrequiredDisplay label; must be unique across the entire form.
urlstringrequiredIntegration engine endpoint path (e.g. /integration/v1/data-fetch).
endpointCodestringrequiredEndpoint code sent in every POST payload.
inputFieldsInputFieldConfig[]requiredSearch-filter inputs shown above the table.
columnsMultiSelectTableColumn[]requiredColumn definitions for the results table.
dataPathstringrequiredDot-notation path to the results array in the API response (e.g. "data.content").

Selection and data extraction

PropTypeRequired?Description
selectionKeystringoptionalKey in each row used to track selection identity; defaults to "id".
useBaseUrlbooleanoptionalPrepend the API gateway base URL; set true for integration engine calls.
paginationConfigPaginationConfigoptionalEnables paginated results; omit when the API returns all results at once.

Display text

PropTypeRequired?Description
tableTitlestringoptionalHeading displayed above the results table; defaults to "Results".
tableDescriptionstringoptionalSub-heading below the title; defaults to "Please select items before continuing.".
emptyMessagestringoptionalMessage shown when the search returns no results; defaults to "No results found.".
validateButtonLabelstringoptionalLabel for the search trigger button; defaults to "Validate".

Payload construction

PropTypeRequired?Description
useMultiplePayloadKeysbooleanoptionalSet true to enable payloadKeyMappings.
payloadKeyMappingsPayloadKeyMapping[]optionalMaps form fields or static values into the request payload; only active when useMultiplePayloadKeys is true.

Preview and errors

PropTypeRequired?Description
previewMetadataPreviewMetadataConfig[]optionalMetadata entries for the selection summary panel shown after selection.
disabledbooleanoptionalDisables the entire widget.
showGlobalErrorbooleanoptionalShows a global error banner on request failure.
errorMappingobjectoptionalMaps 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

FieldTypeRequired?Description
keystringrequiredParameter name sent in the POST payload.
labelstringrequiredDisplay label for the input.
typestringoptionalHTML input type: "text" (default), "number", "email".
placeholderstringoptionalGhost text.
hintstringoptionalHelper text below the input.
requiredbooleanoptionalPrevents search until filled.
patternstringoptionalRegex validation pattern.
minLengthnumberoptionalMinimum character count.
maxLengthnumberoptionalMaximum character count.
defaultValuestringoptionalPre-filled value.

MultiSelectTableColumn shape

FieldTypeRequired?Description
headerstringrequiredColumn heading text.
fieldstringrequiredTop-level key in each row object.
dataPathstringoptionalDot-notation path for nested values (e.g. "school.name").
formatterstringoptional"date", "currency", "array-first-name".

PreviewMetadataConfig shape

FieldTypeDescription
keystringUnique identifier for this metadata entry.
labelstringDisplay label.
type"count" | "sum" | "first" | "input" | "static"How the value is computed from selected rows.
sourceFieldstringRow field used for sum / first computation.
formatter"currency" | "number" | "date"Optional display formatter.
prefixstringText prepended to value (e.g. "RWF ").
suffixstringText 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.url instead of props.url — this component reads only from props.url, not props.dataset.
  • Setting selectionKey to a field absent from some rows — selection tracking breaks silently for those rows.
  • Using minSelection or maxSelection validators — defined in EIremboFormlyValidationTypes but not registered in formlyConfigs(); they have no effect at runtime.
  • Providing payloadKeyMappings without setting useMultiplePayloadKeys: true — the mappings are ignored.
  • Setting dataPath to 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

  • key is UPPER_SNAKE_CASE and unique across the entire form
  • props.label is present, unique, and correctly cased
  • url, endpointCode, and useBaseUrl: true are set
  • inputFields defines at least one search filter
  • columns defines every column shown in the results table
  • dataPath matches the array path returned by the endpoint
  • selectionKey matches a unique field present on every row
  • paginationConfig is set whenever the API returns paginated results
  • useMultiplePayloadKeys: true whenever payloadKeyMappings is set
  • validation.messages.required is present
  • Not using the un-registered minSelection / maxSelection validators

On this page