Components

customdoubleidinput

Captures and verifies two identities simultaneously as a paired unit, triggering one combined API fetch. Use for paired records like marriage lookups or joint applicants.

Captures and verifies two identities simultaneously as a paired unit, triggering one combined API fetch. Use for paired records like marriage lookups or joint applicants.

Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.

When to use

  • Two identities must be verified together against a single integration endpoint (e.g. a marriage record lookup)
  • The response is a combined payload that populates fields for both identities
  • A single document type dropdown can serve both sub-fields

When NOT to use

Instead of customdoubleidinput, use…For…
Two customidinput fieldsIndependent fetches with separate result sets per identity
customidinputA single identity lookup
customcrvsidinputA CRVS (Civil Registration) lookup keyed by a single identity

Props

PropTypeRequired?Description
labelstringrequiredField label. Can be empty if sub-labels carry the context.
urlstringrequiredIntegration endpoint path — always /integration/v1/fetch/sync.
endpointCodestringrequiredIntegration endpoint code that identifies the lookup service.
allowedDocumentTypesarrayrequiredList of accepted document type objects — see shape below.
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 endpoints.
populatesarrayoptional{ valueKey, targetKey } mappings that auto-fill downstream fields from the response.
firstIdentityLabelstringoptionalLabel above the first identity sub-field. Default "First Identity".
firstIdentityPlaceholderstringoptionalPlaceholder for the first identity input.
firstIdentityValueKeystringoptionalResponse + payload key for the first document number. Default "firstDocumentNumber".
firstIdentityDocumentTypeKeystringoptionalPayload key for the first document type. Default "firstDocumentType".
secondIdentityLabelstringoptionalLabel above the second identity sub-field. Default "Second Identity".
secondIdentityPlaceholderstringoptionalPlaceholder for the second identity input.
secondIdentityValueKeystringoptionalResponse + payload key for the second document number. Default "secondDocumentNumber".
secondIdentityDocumentTypeKeystringoptionalPayload key for the second document type. Default "secondDocumentType".
hideFieldbooleanoptionalHides the field and excludes its value from submission. Toggle via expressions["props.hideField"].

allowedDocumentTypes item shape

KeyTypeDescription
labelstringDisplay name shown in the document type dropdown.
valuestringCode sent in the API payload (e.g. "NID", "PASSPORT_ID").
patternstringRegex the entered document number must match.
maxLengthnumberMaximum character count for the document number.
minLengthnumberMinimum character count for the document number.
placeholderstringOptional custom placeholder for this document type.

Examples

Minimal — marriage record by NID

{
  "key": "COUPLE_IDENTITY",
  "type": "customdoubleidinput",
  "props": {
    "label": "",
    "required": false,
    "defaultRequired": true,
    "url": "/integration/v1/fetch/sync",
    "useBaseUrl": true,
    "endpointCode": "FGETMARRIAGERECORD",
    "firstIdentityLabel": "Husband",
    "secondIdentityLabel": "Wife",
    "allowedDocumentTypes": [
      {
        "label": "National ID",
        "value": "NID",
        "pattern": "^\\d*$",
        "maxLength": 16,
        "minLength": 16
      }
    ]
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "This field is required.",
      "invalidInput": "Invalid identity document."
    }
  }
}

Full example — NID or Passport with populates

{
  "key": "COUPLE_IDENTITY",
  "type": "customdoubleidinput",
  "props": {
    "label": "",
    "required": false,
    "defaultRequired": true,
    "url": "/integration/v1/fetch/sync",
    "useBaseUrl": true,
    "endpointCode": "FGETMARRIAGERECORD",
    "firstIdentityLabel": "Husband",
    "firstIdentityPlaceholder": "Husband's Details",
    "firstIdentityValueKey": "HUSBAND_DOCUMENT_NUMBER",
    "firstIdentityDocumentTypeKey": "HUSBAND_DOCUMENT_TYPE",
    "secondIdentityLabel": "Wife",
    "secondIdentityPlaceholder": "Wife's Details",
    "secondIdentityValueKey": "WIFE_DOCUMENT_NUMBER",
    "secondIdentityDocumentTypeKey": "WIFE_DOCUMENT_TYPE",
    "allowedDocumentTypes": [
      {
        "label": "National ID",
        "value": "NID",
        "pattern": "^\\d*$",
        "maxLength": 16,
        "minLength": 16
      },
      {
        "label": "Passport",
        "value": "PASSPORT_ID",
        "pattern": "^[a-zA-Z0-9]*$",
        "maxLength": 10,
        "minLength": 5
      }
    ],
    "populates": [
      { "valueKey": "husbandDetails.surName", "targetKey": "HUSBAND_SURNAME" },
      { "valueKey": "civilStatusOfficeName", "targetKey": "OFFICE_OF_REGISTRATION" }
    ]
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "This field is required.",
      "invalidInput": "Invalid identity document."
    }
  }
}

Common mistakes

  • Setting required: true directly — use the required: false + defaultRequired: true + expression pattern from Form Rules.
  • Omitting url — the component throws at runtime; always set it to /integration/v1/fetch/sync.
  • Omitting endpointCode — the component throws at runtime; always required.
  • Omitting allowedDocumentTypes — the document type dropdown renders empty and the user cannot select a type.
  • Using customdoubleidinput when the two identities trigger independent fetches with separate result sets — use two customidinput fields instead.
  • Using dot-notation valueKey (e.g. "husbandDetails.surName") without confirming the API response uses nested objects — flat keys are safer unless the response shape is verified.

Checklist

  • key is UPPER_SNAKE_CASE and unique across the entire form
  • props.label is present (may be empty if sub-labels carry context)
  • Field is nested at the correct depth: sections > formly-group > block > customdoubleidinput
  • required: false is set (never true)
  • defaultRequired is set (true or false)
  • expressions["props.required"] is present with the exact required expression
  • url is /integration/v1/fetch/sync and useBaseUrl is true in production
  • endpointCode matches a valid integration endpoint
  • allowedDocumentTypes has at least one entry with label, value, pattern, minLength, maxLength
  • If populates is used, every targetKey corresponds to a declared field in the form
  • validation.messages.required and validation.messages.invalidInput are both present

On this page