DynamicFormDrawerWithTable
Panoramica
DynamicFormDrawerWithTable combina in un unico componente:
- Un Drawer laterale (default: lato destro, dimensione
large) - Una DataTable con paginazione e selezione singola
- Una toolbar con pulsanti Nuovo/Modifica/Elimina
- Un dialog form (via
DynamicFormDialog) per creazione/modifica record
Gestisce autonomamente il ciclo CRUD completo: carica i dati, consente la selezione di un record, apre il form precompilato per la modifica, e salva le modifiche chiamando le funzioni fornite.
Caratteristiche principali:
- Caricamento dati all'apertura del drawer e al cambiamento dei filtri
- Toolbar configurabile (pulsanti abilitabili/disabilitabili singolarmente)
- Pulsanti Modifica/Elimina abilitati solo con una riga selezionata
- Gestione errori con evento
error - Columne tabella configurabili con template slot
Casi d'uso tipici: gestione anagrafica, configurazione categorie, assegnazione ruoli, qualsiasi entità CRUD con lista + form.
Anteprima live (con CRUD mockato)
Utilizzo
<!-- Codice reale con API -->
<script setup lang="ts">
const showDrawer = ref(false)
// Definizione colonne tabella
const colonne = [
{ field: 'id', header: 'ID', sortable: true, width: '80px' },
{ field: 'nome', header: 'Nome', sortable: true },
{ field: 'email', header: 'Email', sortable: true },
{ field: 'stato', header: 'Stato', template: 'colStato' }, // Slot personalizzato
]
// Schema del form (stessa struttura di DynamicForm)
const schemaForm = [{
name: 'nome',
type: 'text',
label: 'Nome',
props: { required: true }
}, {
name: 'email',
type: 'text',
label: 'Email',
props: { required: true }
}]
// Funzioni CRUD
const fetchUtenti = async (filters?: FilterCriteria) => {
return api.getUtenti(filters)
}
const createUtente = async (data: Record<string, unknown>) => {
return api.createUtente(data)
}
const updateUtente = async (id: string | number, data: Record<string, unknown>) => {
return api.updateUtente(id, data)
}
const deleteUtente = async (id: string | number) => {
return api.deleteUtente(id)
}
</script>
<template>
<Button label="Gestisci utenti" @click="showDrawer = true" />
<DynamicFormDrawerWithTable
v-model:visible="showDrawer"
:schema="schemaForm"
:columns="colonne"
id-field="id"
:fetch-all-fn="fetchUtenti"
:create-fn="createUtente"
:update-fn="updateUtente"
:delete-fn="deleteUtente"
header="Gestione Utenti"
@after-save="handleSave"
@after-delete="handleDelete"
@error="handleError"
>
<!-- Slot per colonna con template personalizzato -->
<template #colStato="slotProps">
<Tag
:value="slotProps.data.stato"
:severity="slotProps.data.stato === 'attivo' ? 'success' : 'danger'"
/>
</template>
</DynamicFormDrawerWithTable>
</template>
Con filtri statici
<!-- Codice reale con API -->
<DynamicFormDrawerWithTable
v-model:visible="show"
:schema="schema"
:columns="colonne"
id-field="id"
:fetch-all-fn="fetchUtenti"
:filters="{ ruolo: 'operatore', attivo: true }"
:create-fn="create"
:update-fn="update"
:delete-fn="del"
header="Operatori attivi"
/>
Solo lettura (senza modifica/elimina)
<!-- Codice reale con API -->
<DynamicFormDrawerWithTable
v-model:visible="show"
:schema="schema"
:columns="colonne"
id-field="id"
:fetch-all-fn="fetch"
:toolbar-buttons="{ insert: true, modify: false, delete: false }"
header="Visualizza record"
/>
Props
| Prop | Tipo | Default | Descrizione |
|---|---|---|---|
visible | boolean | — | Visibilità del drawer (v-model:visible) |
schema | FormSchema | — | Schema del form (vedi DynamicFormLayouts → FormSchema) |
columns | ColumnDefinition[] | — | Configurazione colonne della DataTable |
idField | string | — | Nome del campo identificativo (chiave primaria) |
fetchAllFn | (filters?: FilterCriteria) => Promise<Record<string, unknown>[]> | — | Funzione per caricare tutti i record |
createFn | (data: Record<string, unknown>) => Promise<unknown> | — | Funzione per creare un nuovo record |
updateFn | (id: string | number, data: Record<string, unknown>) => Promise<unknown> | — | Funzione per aggiornare un record |
deleteFn | (id: string | number) => Promise<unknown> | — | Funzione per eliminare un record |
filters | FilterCriteria | — | Filtri statici passati a fetchAllFn |
header | string | '' | Titolo del drawer |
position | 'left' | 'right' | 'top' | 'bottom' | 'right' | Posizione del drawer |
size | 'small' | 'medium' | 'large' | 'full' | 'large' | Dimensione del drawer (mappa alla prop size del Drawer di @pzeta/vue-components) |
toolbarButtons | { insert?: boolean, modify?: boolean, delete?: boolean } | Tutti true | Configura quali pulsanti mostrare |
drawerClass | string | — | Deprecata e non funzionante: il Drawer di @pzeta/vue-components usa <Teleport> e non eredita l'attributo class. Usare size. Verrà rimossa in una major successiva |
Struttura ColumnDefinition
interface ColumnDefinition {
field: string // Nome proprietà nell'oggetto dati
header?: string // Intestazione colonna (default: field)
sortable?: boolean // Abilita ordinamento
hidden?: boolean // Nasconde la colonna
width?: string // Larghezza CSS (es. '120px', '10%')
class?: string // Classe CSS aggiuntiva
template?: string // Nome slot per template personalizzato
}
Slot
I template per le colonne con template specificato vengono passati come slot con il nome corrispondente:
<!-- Column: { field: 'stato', template: 'colStato' } -->
<template #colStato="slotProps">
<!-- slotProps.data = riga dati corrente -->
<!-- slotProps.field = nome campo -->
<Tag :value="slotProps.data.stato" />
</template>
Comportamento CRUD
| Azione | Trigger | Comportamento |
|---|---|---|
| Carica | Apertura drawer, cambio filtri | Chiama fetchAllFn con filters correnti |
| Nuovo | Click "Nuovo" | Apre dialog form vuoto; al save chiama createFn |
| Modifica | Click "Modifica" (riga selezionata) | Apre dialog precompilato; al save chiama updateFn(id, data) |
| Elimina | Click "Elimina" (riga selezionata) | Chiama deleteFn(id) senza conferma; ricarica la griglia |
Nota: L'eliminazione non mostra dialogo di conferma. Aggiungere conferma lato applicazione se necessario, intercettando l'evento
erroro avvolgendodeleteFncon una logica di conferma personalizzata.
Dialog form
Il dialog usa DynamicFormDialog (componente interno) e riceve:
- Lo
schemafornito al componente initialData= riga selezionata (in modalità modifica) o oggetto vuoto (in modalità creazione)- La callback
saveche eseguecreateFnoupdateFne ricarica la griglia
Eventi
| Evento | Payload | Descrizione |
|---|---|---|
update:visible | boolean | Cambio visibilità drawer |
rowSelected | Record<string, unknown> | Riga selezionata nella tabella |
afterSave | Record<string, unknown> | Dopo salvataggio riuscito (create o update) |
afterDelete | Record<string, unknown> | Dopo eliminazione riuscita |
error | Error | Errore in qualsiasi operazione CRUD |