[data-reveal]{opacity:1!important;transform:none!important}
AntelopeJS DMS
DocumentationAdd and edit forms

Add and edit forms

Where a table view opens its add, edit and view forms, and the fields that show or recompute as the form changes.

A TableView builds its add, edit and view forms from the controller's fields. This page covers where those forms open, conditional fields, and form watches.

Form containers

formContainer.type controls where the add/edit/view form opens:

  • page (default). TableView generates hidden sub-pages at <page slug>/<key>/new, <page slug>/<key>/:id/edit and <page slug>/<key>/:id/view, each gated by the matching permission. <key> is the key the table view is mounted under (static invoices = TableView(...) gives .../invoices/new), so several table views on one page, nested ones included, each get form pages of their own. A page entry of formContainer.pages (new/edit/details) can also set its urlSlug: a declared slug is relative to the page with no key segment inserted, which is full control over the URL; custom edit/details slugs must contain :id. Set customPage: true to skip auto-generation and register the page yourself. Two table views resolving to the same form URL fail the page's registration, naming both.
  • drawer. Slides in from the side.
  • modal. Opens centered and accepts a size.

Whatever the container, formContainer.pages titles the forms: each of new, edit and details takes a displayName and a description ($-prefixed: i18n keys). Left out, the forms read "New entry", "Edit entry" and "Entry details", a drawer or modal naming the caption in its description; the row's label (labelKey) follows the edit and details titles.

Whatever the container, the form behaves the same way with unsaved changes: its Save and Discard buttons show once a value changed, its footer sticks to the bottom of the page, drawer or modal when the form is longer than it, and closing the drawer or modal, leaving the page or going back in the browser with changes not saved asks first in a warning dialog. A clean form shows Cancel in their place, in the same spot: it closes the drawer or modal, or, on a form page, goes back to the list. Navigating to another page closes an open drawer or modal.

Forms are built from the controller's @Column fields, honoring @Access, @Mandatory, readonlyBehavior, and @ColumnGroup. See Forms.

Conditional fields

A field shown, required or locked only for some values of another column is declared on its @Column, with no watch: visibleWhen shows it only while the other column holds one of the listed values, disabledWhen makes it read-only then. Both take { field, in: [...] } (null matches an empty field).

ts
@Mandatory("new", "edit")
@Column({ name: "Loss reason", type: reasonType, visibleWhen: { field: "stage", in: ["lost"] } })
declare lostReason: string;

@Column({ name: "Probability", type: percentType, disabledWhen: { field: "stage", in: ["won", "lost"] } })
declare probability: number;

The generated forms apply them from the values they open with, and the new and edit routes apply them to whatever a client sends, on the row as it will be stored (an edit's stored row under its body):

  • a hidden field is not mandatory (@Mandatory binds it while it shows, and there an edit must leave it filled). The value sent for it is ignored, and an edit that hides it clears the value it stored (a business turned household loses its VAT number);
  • a disabled field's sent value is ignored; it keeps the value it stored.

Form watches

forms hands each generated form's builder to a callback, by form kind, before the table view embeds it. It is for input comfort only, such as a value filled in from another or a field one table's forms leave out, and holds no data rule: the routes never see it, so what must hold whichever client writes is a column's visibleWhen / disabledWhen or a guard. The callback declares on it what it would on a module's own Form: .watch() with its params, onParam and requirePermission:

ts
import { FormEvents, FormFunctions } from "@antelopejs/interface-dms/base/form-types";

const fillProbability = (form: FormBuilder) =>
  form.watch(FormEvents.FIELD_CHANGE, FormFunctions.SET_FIELD_VALUE, {
    params: { targetField: "probability", valueMap: { won: 100, lost: 0 } },
    onParam: { key: "fieldId", value: "stage" },
  });

static deals = TableView(DealAPI, {
  formContainer: { type: "drawer" },
  forms: { new: fillProbability, edit: fillProbability },
});

What the callback declares holds wherever the form opens (a drawer, a modal or its form page), and the new form's also on a duplicated row. A watch with requirePermission reaches only the callers holding that permission, as on a page's own components: the page checks the watches of every component it serves, those a host embeds in its options (a table view's forms, a drawer's content) included.