Skip to Content
@alza/hateoasCoreGetting started

Hateoas form helpers

Installation

yarn add @alza/hateoas --exact

Field map utility (auto-mapping)

@alza/hateoas works with a fieldMap object. It is used to map server field names to your local (client/UI) field names.

In many cases you want a 1:1 mapping where local field names are the same as server field names. For that, use:

  • createFieldMapFromForm(form, options) (named export)
  • Hateoas.createFieldMapFromForm(form, options) (same function on the Hateoas helper)

It builds a HateoasFieldMap from HateoasFormV2.value[] and infers "string"/"integer" field types. Unsupported itemTypes are skipped by default.

Terminology (current names):

  • Raw API form type: HateoasFormV2
  • Field map type: HateoasFieldMap

Example: identity mapping

import { Hateoas } from "@alza/hateoas"; const fieldMap = Hateoas.createFieldMapFromForm(form); const fields = Hateoas.getUiFields(form, fieldMap); // fields.password.validators?.(t) ...

Example: rename fields (server -> local)

import { createFieldMapFromForm } from "@alza/hateoas"; const fieldMap = createFieldMapFromForm(form, { rename: { password: "auth.password", }, }); // Use the local name "auth.password" in your UI / form library.

Example: skip or throw on unsupported itemTypes

import { createFieldMapFromForm } from "@alza/hateoas"; // Default: unsupported fields are skipped const fieldMap1 = createFieldMapFromForm(form); // Throw when encountering unsupported fields const fieldMap2 = createFieldMapFromForm(form, { unsupported: "throw" });

Generic parameters

  • required
    • by field.isRequired (V3 has to be true, V2 cannot be false - implicit true)
    • also marks labelAsRequired (*)
  • disabled
    • by field.isEnabled (V3 has to be true, V2 cannot be false - implicit true)
  • label
    • by field.label
  • hidden
    • by field.isHidden
  • placeholder
    • by field.placeholder
  • description
    • by field.description
  • validationError
    • by field.validationError
    • error returned from API

String

Standard text input (field.itemType === 'string' or field.type === 'string')

  • pattern
    • by field.pattern
    • validates string by provided RegExp pattern
  • email
    • by field.semanticItemType === 'email'
    • uses field.pattern if present, otherwise falls back to local email regex
  • phone
    • by field.semanticItemType === 'phone'
    • uses field.pattern if present, otherwise falls back to local phone regex
  • IBAN
    • by field.semanticItemType === 'iban'
    • uses field.pattern if present, otherwise falls back to local IBAN validation
  • minLength
    • by field.minLength or field.min
    • validates string minimal length (characters)
  • maxLength
    • by field.maxLength or field.max
    • validates string maximal length (characters)

Behaviour can also be modified by field.semanticItemType with values of password, textArea.

Integer

Text input limited to numbers (field.itemType === 'string' or field.itemType ==='decimal')

  • max
    • by field.max
    • validates maximum value
  • min
    • by field.min
    • validates minimum value

Boolean

Checkbox input (field.itemType === 'boolean')

Set

Select input (field.itemType === 'set' or field.type === 'set'). Can be multichoice.

  • minSize
    • by field.minSize
    • validates minimum selected size (e.g. you have to pick atleast 3 options)
  • maxSize
    • by field.maxSize
    • validates maximum selected size (e.g. you can pick up to 3 options)

Example: render set as <select>

SetField is the UI model produced by Hateoas.getUiFields(form, fieldMap).

  • field.options contains available options (with disabled already mapped from isEnabled)
  • field.multiple tells you whether to render multi-select
  • field.value is UI-friendly:
    • single-select: string | ""
    • multi-select: string[]
import { Hateoas } from "@alza/hateoas"; import type { HateoasFieldMap, HateoasFormV2, SetField } from "@alza/hateoas"; const fieldMap = { day: ["day", "set"], } as const satisfies HateoasFieldMap; export function Example({ form }: { form: HateoasFormV2 }) { const fields = Hateoas.getUiFields(form, fieldMap); const day = fields.day as SetField; // Render: // <select multiple={day.multiple} defaultValue={day.value}> // {day.options.map(o => ( // <option key={o.value} value={o.value} disabled={o.disabled}> // {o.label} // </option> // ))} // </select> }

Example: submit set values

Server expects set values as an array.

When mapping local UI values back to server values you can pass:

  • single-select value as string → it is coerced to [string]
  • multi-select value as string[] → stays as-is
import { AlzaHateoasForm, Hateoas } from "@alza/hateoas"; import type { HateoasFieldMap, HateoasFormV2 } from "@alza/hateoas"; const fieldMap = { day: ["day", "set"], } as const satisfies HateoasFieldMap; const hateoasFields = Hateoas.getUiFields(form, fieldMap); // UI values (single-select) const localValues = { day: "nextday" }; const serverValues = Hateoas.mapLocalValuesToHateoas( localValues, fieldMap, hateoasFields, ); const hf = new AlzaHateoasForm(form as HateoasFormV2); hf.changeFormValues(serverValues); const submit = hf.getFormSubmitData(); // submit.data.day === ["nextday"]

Range

Slider number input (field.itemType === 'range or field.type === 'range' or field.itemType === 'integer). Pick number between min-max values. // opravdu integer? legacy bug?

DateTime

Date or DateTime input (field.itemType === 'dateTime' or field.semanticItemType === 'date' or field.semanticItemType === 'dateTime'). field.semanticItemType specifies if its date or dateTime.

  • maxDate
    • by field.max
  • minDate
    • by field.min

BlobAttachment

Attachment upload input (field.itemType === 'blobAttachment' or field.type === 'blobAttachment)

  • uploadUrl
    • by field.uploadUrl
    • url where to upload the files (returns attachment ids that are then used as actual values)
  • minSize
    • by field.min
    • minimum attachment count
  • maxSize
    • by field.maxCount
    • maximum attachment count
  • allowedContentTypes
    • by field.allowedContentTypes
    • validates attachment content types (e.g. jpg, png, pdf…)
  • maxAttachmentSize
    • by field.maxAttachmentSize
    • validates each attachment (file) size in Bytes

SubmitButton

Submit button defined from API (field.itemType === 'submitButton or field.type === 'submitButton)

ObjectArray

Custom object array field (field.itemType === 'objectArray) - usually requires custom implementation. Used to just pass predefined complex data structures generated by API.

Last updated on