Ga naar hoofdinhoud

CnFormWidgetBase

The abstract form-shaped dashboard widget. It owns the shape of a form widget — a stack of labelled fields, a right-aligned action row, one inline error line — and no domain logic at all: no schema, no endpoint, no save.

A concrete form widget declares its fields, holds its own model, and does its own submitting. What it gets back is a rendering identical to every other form widget's, because the markup and the CSS live in one place (src/css/form-widget.css).

Extracted from CnInteractionFormWidget, whose rendering is the reference. The extraction had to be invisible, and e2e/interaction-form-widget.e2e.js screenshots the widget to prove it: the PNGs taken before and after are byte-identical.

Usage​

<CnFormWidgetBase
block-class="cn-my-form-widget"
:fields="fields"
:model="form"
:errors="{ subject: subjectError }"
:can-submit="canSave"
:submitting="saving"
:submit-label="t('myapp', 'Save')"
:error-message="errorMessage"
@update:field="({ key, value }) => (form[key] = value)"
@submit="onSave" />

Field descriptors​

Each entry in fields is { key, label, type } plus per-type extras:

typeRendersExtras
selectNcSelectoptions ([{ value, label }]), clearable, optionValue, optionLabel
textareaa labelled <textarea>rows
text (default)NcTextFieldinputType

Any field also takes visible: false to omit it and disabled: true to freeze it.

Replacing one control​

A field whose control the base has no type for — a resource picker, a date range — keeps its place, its wrapper and the stack's spacing through the field-{key} slot:

<template #field-client="{ value, update }">
<CnResourceSelect :model-value="value" @update:modelValue="update" />
</template>

Extra buttons beside submit​

The actions-start slot adds buttons to the action row, left of the submit button, such as a link to open what was just saved. The actions slot replaces the submit button itself.

Keeping an existing widget's class names​

blockClass mirrors a second BEM block onto every element (cn-my-form-widget__field alongside cn-form-widget__field). Pass it when moving an existing widget onto the base so app CSS written against the old names keeps matching.

The host owns the state​

The base never writes into model. It emits update:field with { key, value } and the host applies it — which is what lets a widget do something on change (stream a value into a page-level workspace context, say) rather than only store it.

OpenRegister reliance​

none: this component does not touch OpenRegister, directly or through anything it imports. 0 direct references, 0 files reached through imports.

See the reliance overview for the filterable list.

Props​

NameTypeRequiredDefaultDescription
blockClassstring''Extra BEM block prefix mirrored onto every element alongside the canonical cn-form-widget* classes (e.g. cn-interaction-form-widget also emits cn-interaction-form-widget__field). Exists so a widget that had its own class names before the extraction keeps them, and app CSS targeting those names keeps matching.
fieldsArray<{key: string, label?: string, type?: string, options?: Array, rows?: number, visible?: boolean, disabled?: boolean}>[]Field descriptors, in render order. See the component description for the shape.
modelobject\{\}The form values, keyed by field key. Read-only here: the base emits update:field and the host owns the mutation.
errorsobject\{\}Per-field validation messages, keyed by field key. A non-empty entry puts its field into the error state and shows the text as helper text.
canSubmitbooleantrueWhether the submit button is enabled (before submitting).
submittingbooleanfalseWhether a submit is in flight — disables the button and swaps its label.
submitLabelstring() =&gt; t('nextcloud-vue', 'Save')Pre-translated submit button label.
submittingLabelstring() =&gt; t('nextcloud-vue', 'Saving…')Pre-translated label shown while submitting.
errorMessagestring''Form-level error message, shown as one line below the actions.

Events​

NamePayloadDescription
update:field—
submit—The user asked to submit the form. Carries no payload — the host owns the model, so it already has the values. Only reachable while the button is enabled, i.e. while neither submitting nor !canSubmit holds.
update:field A field's value changed.—

Slots​

NameBindingsDescription
'field-' + field.keyname, field, value, updatefield-{key} Replace one field's control entirely, keeping
actions-start—actions-start Extra buttons in the action row, left of the submit button.
actions—actions Replace the submit row entirely (e.g. to add a

Submit labels​

submitLabel is the button's resting label; submittingLabel replaces it while submitting is true, and the button is disabled for exactly as long as that stays true.