FormSectionRow
Panoramica
FormSectionRow è un componente interno che gestisce il rendering dinamico di righe e campi all'interno di una sezione di DynamicFormLayouts. Non è destinato all'uso diretto nelle applicazioni: viene utilizzato automaticamente da DynamicFormLayouts e DynamicFormDrawerWithTable.
Gestisce:
- Rendering dinamico del componente corretto in base al
typedel campo - Validazione on-blur con messaggi tradotti
- Modalità inplace con conferma/annulla per editing inline
- Visibilità e disabilitazione condizionale dei campi
- Propagazione dello stato di validazione alla sezione parent
- Supporto
spanper campi che occupano più colonne
Caratteristiche tecniche
Mappatura tipo → componente
Il rendering avviene tramite componentMap, che mappa ogni type al componente Vue corrispondente. Tutti i tipi supportati da DynamicFormLayouts sono disponibili (es. 'text', 'date', 'selectremote', 'tiptap', ecc.).
Modalità inplace
Quando un campo ha inplace: true nello schema, FormSectionRow avvolge il componente in un componente Inplace di @pzeta/vue-components:
- L'utente vede il valore corrente come testo cliccabile
- Al click, appare il componente di editing con i pulsanti Conferma/Annulla
- Conferma: emette
fieldCommitcon il nuovo valore - Annulla: ripristina il valore originale tramite un secondo
fieldCommit
I valori temporanei durante l'editing inplace sono separati dai valori del form, evitando modifiche accidentali.
Visualizzazione testo in modalità inplace
Il metodo getInplaceDisplayText gestisce automaticamente diversi tipi di valore:
- Stringa/numero: visualizzazione diretta
- Array: elementi uniti da virgola (estrae
label/namedagli oggetti) - Booleano: tradotto in "Sì"/"No"
- Date: formattato con
toLocaleDateString() - Oggetto: estrae
label,nameovalue - Vuoto: mostra il
placeholderdel campo o "Click to edit"
Utilizzo (da DynamicFormLayouts)
<!-- Uso interno in DynamicFormLayouts -->
<FormSectionRow
:section="sezione"
:section-index="0"
:form-data="formData"
:dev-mode="false"
@field-commit="handleFieldCommit"
@section-validation-change="handleValidation"
/>
Anteprima — modalità inplace
Con inplace: true il campo mostra il valore corrente come testo cliccabile; al click appare il componente di editing con Conferma/Annulla.
Props
| Prop | Tipo | Default | Descrizione |
|---|---|---|---|
section | SectionDefinition | — | Definizione della sezione con righe e campi |
sectionIndex | number | — | Indice della sezione nel form (passato negli eventi e nello scope dei slot section-before/after del parent) |
formData | Record<string, unknown> | — | Dati correnti del form |
valid | boolean | true | Stato di validità iniziale |
devMode | boolean | false | Abilita informazioni di debug |
crossFieldErrors | Record<string, string> | {} | Mappa { fieldName → messaggio } di errori cross-field calcolati dal parent (chiavi i18n o testo custom). Sommati agli errori locali on-blur |
isEdit | boolean | false | Modalità modifica del form contenitore. Quando false (insert) la validazione on-blur dei campi è disattivata — UX più morbida durante la prima compilazione. Il pulsante save resta disabled grazie a isFormValid live calcolato dal parent |
Tipi correlati
Vedi DynamicFormLayouts → Schema FormSchema per la struttura completa di SectionDefinition, RowDefinition, FieldDefinition (incluse help reattivo, transform, onChange, disabled/visible come FieldVisibility).
Metodi esposti
| Metodo | Firma | Descrizione |
|---|---|---|
validateAll() | () => boolean | Valida tutti i campi visibili e non disabilitati; ritorna true se tutti validi |
fieldErrors | Ref<Record<string, string>> | Mappa degli errori di validazione correnti |
<FormSectionRow ref="sectionRowRef" ... />
// Validazione manuale prima del submit
const tuttoValido = sectionRowRef.value?.validateAll()
Eventi
| Evento | Payload | Descrizione |
|---|---|---|
fieldCommit | (fieldName: string, value: unknown) | Campo aggiornato (standard, conferma inplace, oppure singola chiave di una transform.write patch). Il parent persiste il valore in formData |
fieldChange | (fieldName: string, value: unknown, formData: Record<string, unknown>) | Emesso dopo fieldCommit con lo snapshot post-commit del formData. Il parent può forwardarlo come evento globale per logiche trasversali (telemetria, autosave) |
sectionValidationChange | (sectionIndex: number, isValid: boolean) | Cambio stato validazione della sezione (calcolata live sui valori correnti, non dipende da blur/validateAll) |
buttonClick | (fieldName: string, action: string, value: unknown) | Click su campo di tipo button |
Layout griglia
Quando almeno un campo della riga ha span esplicito, la riga usa una griglia a 12 colonne; altrimenti viene generata una grid con una colonna per ciascun campo (comportamento storico):
// Almeno un span esplicito → grid a 12 colonne
row.fields.some(f => typeof f.span === 'number')
? 'grid-template-columns: repeat(12, minmax(0, 1fr))'
: `grid-template-columns: repeat(${row.fields.length}, minmax(0, 1fr))`
Lo span è applicato come stile inline gridColumn: span N / span N (non come classe col-span-N) per evitare problemi di Tailwind purge sulle classi generate a runtime:
// Campo che occupa 6 colonne su 12
{ name: 'descrizione', type: 'text', span: 6 }
// Stile inline: grid-column: span 6 / span 6
Quando nessun campo ha span, la grid usa repeat(N, 1fr) con N = numero di campi, e i campi non ricevono alcuno stile gridColumn (occupano una cella ciascuno).
Per campi senza span in una riga dove altri lo hanno, lo span auto è floor(12 / N). Lo span è clampato in [1, 12].
Nota:
FormSectionRowè un componente di implementazione interna. Per configurare la struttura del form, modificare lo schema passato aDynamicFormLayoutsoDynamicFormDrawerWithTable.