data-table-list 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,572 +1,651 @@
1
- # Guida all'Utilizzo e all'Implementazione di `DataTableList`
2
-
3
- `DataTableList` è un componente riutilizzabile sviluppato in **Vue 3** (con TypeScript e Composition API). Offre una tabella dati flessibile con supporto nativo per paginazione, ordinamento, filtraggio, azioni di riga, esportazione dati, e selezione multipla tramite checkbox.
4
-
5
- ---
6
-
7
-
8
- [![downloads](https://img.shields.io/github/stars/badges/shields)](https://github.com/mssalvo/data-table-list-vue3) [npm version](https://npmjs.com)
9
-
10
- ---
11
-
12
- ## Project Setup
13
-
14
- ```sh
15
- npm install data-table-list@latest
16
- ```
17
-
18
- ---
19
-
20
- ## usage
21
-
22
-
23
- ```ts
24
- import { DataTableList, Avatar } from 'data-table-list';
25
- import type { DataTableConf } from 'data-table-list';
26
- import 'data-table-list/dist/data-table-list.css'; // This imports the new stable CSS
27
-
28
- ```
29
-
30
-
31
- ---
32
-
33
- ## 1. Strutture Dati e Interfacce (Modelli)
34
-
35
- Il componente utilizza le seguenti interfacce TypeScript definite in [Models.ts](file:///c:/Users/UTENTE/Desktop/progettoIA/data-table-list/src/model/Models.ts):
36
-
37
- ```ts
38
- export interface DataTableConf {
39
- columns: ColumnTable[]; // Configurazione delle colonne
40
- actionsRow?: ActionRow; // Azioni di default abilitate per riga
41
- viewActions: boolean; // Se mostrare o meno la colonna delle azioni
42
- viewDownload?: boolean; // Se visualizzare il pulsante per il download/esportazione
43
- paginator?: boolean; // Abilita la paginazione
44
- paginatorPosition?: PaginatorPosition; // Posizione e allineamento del paginatore
45
- isserver?: boolean; // Se la paginazione e il filtraggio sono gestiti lato server
46
- serverPaging?: ServerPaging; // Metadati per la paginazione server-side
47
- dimensionePagina: number; // Numero di righe per pagina
48
- messageNotRecords?: string; // Messaggio mostrato se la tabella è vuota
49
- }
50
-
51
- export interface ColumnTable {
52
- title: string; // Intestazione della colonna
53
- property: string; // Nome della chiave nell'oggetto riga
54
- style?: string | null; // Stile CSS inline da applicare alla cella (es: "width: 150px")
55
- callFormatt?: Function | null; // Funzione custom per formattare il valore della cella
56
- hidden?: boolean; // Nasconde la colonna se impostato a true
57
- order?: boolean; // Abilita l'ordinamento client-side per questa colonna
58
- }
59
-
60
- export interface ActionRow {
61
- view: boolean; // Mostra l'icona Visualizza (it-password-visible)
62
- update: boolean; // Mostra l'icona Modifica (it-pencil)
63
- delete: boolean; // Mostra l'icona Elimina (it-delete)
64
- }
65
-
66
- export interface PaginatorPosition {
67
- top: boolean; // Mostra il paginatore sopra la tabella
68
- bottom: boolean; // Mostra il paginatore sotto la tabella
69
- class: string | 'center' | 'left' | 'right'; // Allineamento del paginatore ('left', 'center', 'right')
70
- }
71
-
72
- export interface ServerPaging {
73
- serverTotaleElementi: number; // Numero totale di elementi sul server
74
- serverTotalePagine: number; // Numero totale di pagine sul server
75
- }
76
- ```
77
-
78
- ---
79
-
80
- ## 2. API del Componente (Props ed Emits)
81
-
82
- ### Props (Proprietà)
83
-
84
- | Nome Prop | Tipo | Obbligatorio | Descrizione |
85
- | :--- | :--- | :--- | :--- |
86
- | `dataTableConf` | `DataTableConf` | **Sì** | Configurazione della struttura e del comportamento della tabella. |
87
- | `dataItems` | `any[]` | **Sì** | Array di dati (righe) da visualizzare. Se `isserver` è `false`, contiene tutti i record. Se `isserver` è `true`, contiene solo i record della pagina corrente. |
88
- | `filter` | `string` | No | Stringa di ricerca globale. Se specificata e `isserver` è `false`, la tabella esegue un filtro client-side su tutte le colonne visibili. |
89
- | `showCheckbox` | `boolean` | No | Se impostato a `true`, aggiunge una prima colonna con checkbox per la selezione multipla delle righe. |
90
-
91
- ### Emits (Eventi)
92
-
93
- | Nome Evento | Parametri | Descrizione |
94
- | :--- | :--- | :--- |
95
- | `@onview` | `(obj: object)` | Emesso al click sul pulsante "Visualizza" della riga (default action). Riceve l'oggetto riga. |
96
- | `@onupdate` | `(obj: object)` | Emesso al click sul pulsante "Modifica" della riga (default action). Riceve l'oggetto riga. |
97
- | `@ondelete` | `(obj: object)` | Emesso al click sul pulsante "Elimina" della riga (default action). Riceve l'oggetto riga. |
98
- | `@onavanti` | `(current: number, size: number)` | Emesso quando si va alla pagina successiva **solo se** `isserver` è `true`. `current` è l'indice di pagina (0-indexed), `size` è la dimensione della pagina. |
99
- | `@onindietro` | `(current: number, size: number)` | Emesso quando si va alla pagina precedente **solo se** `isserver` è `true`. `current` è l'indice di pagina (0-indexed), `size` è la dimensione della pagina. |
100
- | `@ondownload` | `(call: any[])` | Emesso al click sul pulsante di download. Riceve la lista corrente dei dati filtrati. |
101
- | `@onchecked` | `(obj: any[])` | Emesso ogni volta che cambia la selezione delle righe tramite checkbox. Riceve l'array delle righe attualmente selezionate. |
102
-
103
- ---
104
-
105
- ## 3. Slot di Personalizzazione
106
-
107
- `DataTableList` offre diversi slot con scoped-slots per personalizzare profondamente il markup:
108
-
109
- * **`#columnTd`**: Permette di personalizzare il rendering del contenuto di ogni cella. Riceve `{ row, column }` come parametri dello slot.
110
- * **`#iconTd`**: Consente di posizionare un'icona o un elemento decorativo a fianco del valore della cella. Riceve `{ row, column }`.
111
- * **`#actions`**: Sostituisce i pulsanti di default (Visualizza, Modifica, Elimina) con pulsanti personalizzati o menu dropdown. Riceve `{ row }`.
112
- * **`#checkbox`**: Sostituisce il checkbox di default delle righe. Riceve `{ row }`.
113
- * **`#download`**: Personalizza l'aspetto del pulsante di download. Riceve l'evento `{ ondownload: { oncall: Function } }`.
114
-
115
- ---
116
-
117
- ## 4. Scenari d'Uso ed Esempi di Implementazione
118
-
119
- ### Scenario A: Tabella Semplice Client-Side con Paginazione e Ordinamento
120
- In questo scenario, i dati sono interamente caricati in memoria. Il componente gestisce la paginazione, la ricerca globale e l'ordinamento in modo autonomo.
121
-
122
- ```html
123
- <script setup lang="ts">
124
- import { ref } from 'vue';
125
- import { DataTableList, Avatar } from 'data-table-list';
126
- import type { DataTableConf } from 'data-table-list';
127
- import 'data-table-list/dist/data-table-list.css';
128
-
129
- const searchFilter = ref('');
130
-
131
- const tableConfig = ref<DataTableConf>({
132
- columns: [
133
- { title: 'ID', property: 'id', order: true },
134
- { title: 'Nome', property: 'name', order: true },
135
- { title: 'Email', property: 'email', order: true }
136
- ],
137
- isserver: false,
138
- paginator: true,
139
- paginatorPosition: { top: true, bottom: true, class: 'right' },
140
- viewActions: true,
141
- actionsRow: { view: true, update: true, delete: true },
142
- dimensionePagina: 5,
143
- messageNotRecords: 'Nessun utente trovato.'
144
- });
145
-
146
- const items = ref([
147
- { id: 1, name: 'Mario Rossi', email: 'mario.rossi@example.com' },
148
- { id: 2, name: 'Giuseppe Verdi', email: 'giuseppe.verdi@example.com' },
149
- { id: 3, name: 'Luca Bianchi', email: 'luca.bianchi@example.com' },
150
- { id: 4, name: 'Anna Neri', email: 'anna.neri@example.com' },
151
- { id: 5, name: 'Sofia Gialli', email: 'sofia.gialli@example.com' },
152
- { id: 6, name: 'Elena Rosa', email: 'elena.rosa@example.com' }
153
- ]);
154
-
155
- const handleView = (item: any) => console.log('Visualizza:', item);
156
- const handleUpdate = (item: any) => console.log('Modifica:', item);
157
- const handleDelete = (item: any) => console.log('Elimina:', item);
158
- </script>
159
-
160
- <template>
161
- <div class="container my-4">
162
- <!-- Input di ricerca collegato alla prop :filter -->
163
- <div class="form-group mb-3">
164
- <label for="search">Cerca Utente</label>
165
- <input id="search" v-model="searchFilter" type="text" class="form-control" placeholder="Cerca...">
166
- </div>
167
-
168
- <DataTableList
169
- :data-items="items"
170
- :data-table-conf="tableConfig"
171
- :filter="searchFilter"
172
- @onview="handleView"
173
- @onupdate="handleUpdate"
174
- @ondelete="handleDelete"
175
- />
176
- </div>
177
- </template>
178
- ```
179
-
180
- ---
181
-
182
- ### Scenario B: Formattazione Personalizzata di Colonne (`callFormatt`)
183
- Quando si desidera applicare una formattazione al volo su una colonna (es. date, valute, o composizione stringhe) senza alterare i dati di origine, si può definire la funzione `callFormatt` nel modello `ColumnTable`.
184
-
185
- ```ts
186
- const tableConfig = ref<DataTableConf>({
187
- columns: [
188
- { title: 'ID', property: 'id' },
189
- {
190
- title: 'Nome Completo',
191
- property: 'name',
192
- // callFormatt riceve il valore del campo specificato in property e l'intera riga
193
- callFormatt: (value: any, row: any) => {
194
- return `${row.name.toUpperCase()} (${row.role})`;
195
- }
196
- },
197
- {
198
- title: 'Data Creazione',
199
- property: 'createdAt',
200
- callFormatt: (value: string) => {
201
- return new Date(value).toLocaleDateString('it-IT');
202
- }
203
- }
204
- ],
205
- isserver: false,
206
- viewActions: false,
207
- dimensionePagina: 10
208
- });
209
-
210
- const items = ref([
211
- { id: 1, name: 'Mario Rossi', role: 'Admin', createdAt: '2026-06-01T10:00:00Z' },
212
- { id: 2, name: 'Giuseppe Verdi', role: 'User', createdAt: '2026-06-03T15:30:00Z' }
213
- ]);
214
- ```
215
-
216
- ---
217
-
218
- ### Scenario C: Personalizzazione Celle con Slot (`#columnTd` & Componenti Custom)
219
- Se si necessita di inserire markup HTML complesso (es. Badge di stato, icone, o componenti esterni come `Avatar.vue`), si utilizza lo slot `#columnTd`.
220
-
221
- ```html
222
- <script setup lang="ts">
223
- import { ref } from 'vue';
224
- import { DataTableList, Avatar } from 'data-table-list';
225
- import type { DataTableConf } from 'data-table-list';
226
- import 'data-table-list/dist/data-table-list.css';
227
-
228
- const tableConfig = ref<DataTableConf>({
229
- columns: [
230
- { title: 'Avatar', property: 'avatar', style: 'width: 80px;' },
231
- { title: 'Dettagli Utente', property: 'details' },
232
- { title: 'Stato', property: 'status' }
233
- ],
234
- isserver: false,
235
- viewActions: false,
236
- dimensionePagina: 5
237
- });
238
-
239
- const items = ref([
240
- { id: 1, name: 'Mario Rossi', email: 'mario.rossi@example.com', status: 'Attivo', statusColor: 'bg-success' },
241
- { id: 2, name: 'Giuseppe Verdi', email: 'giuseppe.verdi@example.com', status: 'Sospeso', statusColor: 'bg-warning' }
242
- ]);
243
- </script>
244
-
245
- <template>
246
- <DataTableList :data-items="items" :data-table-conf="tableConfig">
247
- <!-- Utilizzo dello scoped slot per le celle -->
248
- <template #columnTd="{ row, column }">
249
-
250
- <!-- Cella Avatar -->
251
- <div v-if="column.property === 'avatar'">
252
- <Avatar
253
- :label="row.name.charAt(0) + row.name.split(' ')[1]?.charAt(0)"
254
- :background-dynamics="true"
255
- />
256
- </div>
257
-
258
- <!-- Cella Dettagli Utente -->
259
- <div v-else-if="column.property === 'details'">
260
- <strong>{{ row.name }}</strong><br>
261
- <small class="text-secondary">{{ row.email }}</small>
262
- </div>
263
-
264
- <!-- Cella Stato -->
265
- <div v-else-if="column.property === 'status'">
266
- <span class="badge rounded-pill text-white" :class="row.statusColor">
267
- {{ row.status }}
268
- </span>
269
- </div>
270
-
271
- </template>
272
- </DataTableList>
273
- </template>
274
- ```
275
-
276
- ---
277
-
278
- ### Scenario D: Selezione Multipla con Checkbox e Evento `@onchecked`
279
- Il componente supporta la selezione di elementi tramite una colonna di checkbox abilitata tramite la prop `:show-checkbox="true"`.
280
-
281
- ```html
282
- <script setup lang="ts">
283
- import { ref } from 'vue';
284
- import { DataTableList, Avatar } from 'data-table-list';
285
- import type { DataTableConf } from 'data-table-list';
286
- import 'data-table-list/dist/data-table-list.css';
287
-
288
- const tableConfig = ref<DataTableConf>({
289
- columns: [
290
- { title: 'ID', property: 'id' },
291
- { title: 'Prodotto', property: 'product' }
292
- ],
293
- isserver: false,
294
- viewActions: false,
295
- dimensionePagina: 10
296
- });
297
-
298
- const items = ref([
299
- { id: 101, product: 'Computer Laptop' },
300
- { id: 102, product: 'Monitor 4K' },
301
- { id: 103, product: 'Tastiera Meccanica' }
302
- ]);
303
-
304
- const selectedItems = ref<any[]>([]);
305
-
306
- // Salva gli elementi selezionati nello stato locale
307
- const handleChecked = (checkedRows: any[]) => {
308
- selectedItems.value = checkedRows;
309
- console.log('Prodotti selezionati:', selectedItems.value);
310
- };
311
- </script>
312
-
313
- <template>
314
- <div class="my-3">
315
- <DataTableList
316
- :data-items="items"
317
- :data-table-conf="tableConfig"
318
- :show-checkbox="true"
319
- @onchecked="handleChecked"
320
- />
321
-
322
- <div class="mt-3">
323
- <h5>Elementi selezionati: {{ selectedItems.length }}</h5>
324
- <ul>
325
- <li v-for="item in selectedItems" :key="item.id">{{ item.product }}</li>
326
- </ul>
327
- </div>
328
- </div>
329
- </template>
330
- ```
331
-
332
- ---
333
-
334
- ### Scenario E: Menu Azioni Personalizzato (Dropdown Bootstrap Italia)
335
- Invece di mostrare i tre pulsanti standard in linea (view, update, delete), è possibile personalizzare la colonna delle azioni inserendo un menu a comparsa (dropdown) in perfetto stile Bootstrap Italia utilizzando lo slot `#actions`.
336
-
337
- ```html
338
- <script setup lang="ts">
339
- import { ref } from 'vue';
340
- import { DataTableList, Avatar } from 'data-table-list';
341
- import type { DataTableConf } from 'data-table-list';
342
- import 'data-table-list/dist/data-table-list.css';
343
-
344
- const tableConfig = ref<DataTableConf>({
345
- columns: [
346
- { title: 'ID', property: 'id' },
347
- { title: 'Documento', property: 'docName' }
348
- ],
349
- isserver: false,
350
- viewActions: true, // Deve essere true per abilitare la colonna azioni
351
- dimensionePagina: 10
352
- });
353
-
354
- const items = ref([
355
- { id: 1, docName: 'Fattura_2026_01.pdf' },
356
- { id: 2, docName: 'Contratto_Firmato.pdf' }
357
- ]);
358
-
359
- const scaricaDocumento = (row: any) => console.log('Download', row.docName);
360
- const archiviaDocumento = (row: any) => console.log('Archivia', row.id);
361
- </script>
362
-
363
- <template>
364
- <DataTableList :data-items="items" :data-table-conf="tableConfig">
365
- <!-- Personalizzazione colonna azioni tramite slot -->
366
- <template #actions="{ row }">
367
- <div class="dropdown dropstart text-center">
368
- <a class="btn btn-dropdown dropdown-toggle" href="#" role="button" id="dropdownActions" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
369
- <!-- Icona a tre pallini di Bootstrap Italia -->
370
- <svg class="icon-expand icon icon-sm icon-secondary">
371
- <use href="@/assets/svg/sprites.svg#it-more-items"></use>
372
- </svg>
373
- </a>
374
- <div class="dropdown-menu" aria-labelledby="dropdownActions">
375
- <div class="link-list-wrapper">
376
- <ul class="link-list">
377
- <li>
378
- <a class="dropdown-item list-item" @click.prevent="scaricaDocumento(row)">
379
- <span>
380
- <svg class="icon icon-primary" aria-hidden="true">
381
- <use href="@/assets/svg/sprites.svg#it-download"></use>
382
- </svg> Scarica
383
- </span>
384
- </a>
385
- </li>
386
- <li>
387
- <a class="dropdown-item list-item" @click.prevent="archiviaDocumento(row)">
388
- <span>
389
- <svg class="icon icon-primary" aria-hidden="true">
390
- <use href="@/assets/svg/sprites.svg#it-box"></use>
391
- </svg> Archivia
392
- </span>
393
- </a>
394
- </li>
395
- </ul>
396
- </div>
397
- </div>
398
- </div>
399
- </template>
400
- </DataTableList>
401
- </template>
402
- ```
403
-
404
- ---
405
-
406
- ### Scenario F: Paginazione Server-Side (`isserver: true`)
407
- Se la sorgente dati ha molti elementi, la paginazione deve avvenire sul server.
408
- * `isserver` deve essere impostato a `true`.
409
- * È necessario compilare `serverPaging` con i totali di elementi e pagine forniti dalle API.
410
- * Bisogna ascoltare gli eventi `@onavanti` e `@onindietro` per richiedere la pagina corretta al server e aggiornare l'array `dataItems`.
411
-
412
- ```html
413
- <script setup lang="ts">
414
- import { ref, onMounted } from 'vue';
415
- import { DataTableList, Avatar } from 'data-table-list';
416
- import type { DataTableConf } from 'data-table-list';
417
- import 'data-table-list/dist/data-table-list.css';
418
-
419
- // Stato locale per i dati e il caricamento
420
- const items = ref<any[]>([]);
421
- const loading = ref(false);
422
-
423
- const tableConfig = ref<DataTableConf>({
424
- columns: [
425
- { title: 'ID', property: 'id' },
426
- { title: 'Descrizione', property: 'description' }
427
- ],
428
- isserver: true, // Indica che paginazione e ricerca avvengono sul server
429
- paginator: true,
430
- paginatorPosition: { top: false, bottom: true, class: 'center' },
431
- viewActions: false,
432
- dimensionePagina: 10,
433
- serverPaging: {
434
- serverTotaleElementi: 0, // Inizializzato a 0, popolato in seguito
435
- serverTotalePagine: 0
436
- }
437
- });
438
-
439
- // Funzione simulata per caricare i dati dalle API
440
- const fetchApiData = async (page: number, size: number) => {
441
- loading.value = true;
442
- try {
443
- // Es. const res = await axios.get(`/api/items?page=${page}&size=${size}`);
444
- await new Promise((resolve) => setTimeout(resolve, 400));
445
-
446
- const mockTotalElements = 50;
447
- const mockTotalPages = Math.ceil(mockTotalElements / size);
448
-
449
- // Creazione dati simulati per la pagina corrente (es. pagina 0 -> ID 1-10)
450
- const rows = [];
451
- const start = page * size;
452
- for (let i = 0; i < size; i++) {
453
- const id = start + i + 1;
454
- if (id <= mockTotalElements) {
455
- rows.push({ id, description: `Elemento server ${id}` });
456
- }
457
- }
458
-
459
- items.value = rows;
460
-
461
- // Aggiornamento dei metadati di paginazione server-side
462
- tableConfig.value.serverPaging = {
463
- serverTotaleElementi: mockTotalElements,
464
- serverTotalePagine: mockTotalPages
465
- };
466
- } finally {
467
- loading.value = false;
468
- }
469
- };
470
-
471
- // Gestione del cambio pagina in avanti
472
- const handleAvanti = async (currentPage: number, size: number) => {
473
- await fetchApiData(currentPage, size);
474
- };
475
-
476
- // Gestione del cambio pagina all'indietro
477
- const handleIndietro = async (currentPage: number, size: number) => {
478
- await fetchApiData(currentPage, size);
479
- };
480
-
481
- onMounted(async () => {
482
- // Caricamento iniziale
483
- await fetchApiData(0, tableConfig.value.dimensionePagina);
484
- });
485
- </script>
486
-
487
- <template>
488
- <div class="container my-4">
489
- <h3>Paginazione Server-Side</h3>
490
- <div v-if="loading" class="alert alert-info">Caricamento...</div>
491
-
492
- <DataTableList
493
- :data-items="items"
494
- :data-table-conf="tableConfig"
495
- @onavanti="handleAvanti"
496
- @onindietro="handleIndietro"
497
- />
498
- </div>
499
- </template>
500
- ```
501
-
502
- ---
503
-
504
- ### Scenario G: Esportazione e Download dei Dati Filtrati
505
- Il componente offre la possibilità di abilitare un pulsante per il download dei dati.
506
- * Impostare `viewDownload: true` nella configurazione `DataTableConf`.
507
- * Ascoltare l'evento `@ondownload`, che riceve la lista dei record attualmente filtrati dalla ricerca globale (`filterComputer`).
508
-
509
- ```html
510
- <script setup lang="ts">
511
- import { ref } from 'vue';
512
- import { DataTableList, Avatar } from 'data-table-list';
513
- import type { DataTableConf } from 'data-table-list';
514
- import 'data-table-list/dist/data-table-list.css';
515
-
516
- const searchFilter = ref('');
517
-
518
- const tableConfig = ref<DataTableConf>({
519
- columns: [
520
- { title: 'ID', property: 'id' },
521
- { title: 'Nome', property: 'name' }
522
- ],
523
- isserver: false,
524
- viewActions: false,
525
- viewDownload: true, // Mostra l'icona per il download in alto a destra
526
- dimensionePagina: 10
527
- });
528
-
529
- const items = ref([
530
- { id: 1, name: 'Mario Rossi' },
531
- { id: 2, name: 'Giuseppe Verdi' },
532
- { id: 3, name: 'Luca Bianchi' }
533
- ]);
534
-
535
- // Funzione di esportazione CSV client-side al click sul download
536
- const handleDownload = (filteredData: any[]) => {
537
- const csvHeaders = 'ID,Nome\n';
538
- const csvRows = filteredData.map(item => `${item.id},"${item.name}"`).join('\n');
539
- const csvContent = 'data:text/csv;charset=utf-8,' + csvHeaders + csvRows;
540
-
541
- const encodedUri = encodeURI(csvContent);
542
- const link = document.createElement('a');
543
- link.setAttribute('href', encodedUri);
544
- link.setAttribute('download', 'esportazione_tabella.csv');
545
- document.body.appendChild(link);
546
- link.click();
547
- document.body.removeChild(link);
548
- };
549
- </script>
550
-
551
- <template>
552
- <div class="container my-4">
553
- <div class="form-group mb-3">
554
- <input v-model="searchFilter" type="text" class="form-control" placeholder="Cerca...">
555
- </div>
556
-
557
- <DataTableList
558
- :data-items="items"
559
- :data-table-conf="tableConfig"
560
- :filter="searchFilter"
561
- @ondownload="handleDownload"
562
- />
563
- </div>
564
- </template>
565
- ```
566
-
567
- ---
568
-
569
- ## 5. Dettagli Implementativi Importanti
570
-
571
- 1. **Identificativi Checkbox (`checkId`)**: Quando viene attivata la funzionalità checkbox (`showCheckbox = true`), il componente genera temporaneamente la chiave `checkId` all'interno dei record dell'array `dataItems` per identificare univocamente le righe selezionate. L'array restituito dall'evento `@onchecked` conterrà questi campi aggiuntivi.
572
- 2. **Reset dell'Ordinamento al cambio pagina**: Ad ogni navigazione di pagina (avanti o indietro) o reset del filtro di ricerca, viene richiamata la funzione `resetClassOrder()` che rimuove la classe CSS `.icon-primaryOrder` dall'header della colonna ordinata, indicando che la nuova pagina mostra i dati nel loro stato originario.
1
+ # 📊 DataTableList
2
+
3
+ ![Vue](https://img.shields.io/badge/Vue-3.x-42b883?logo=vue.js)
4
+ ![TypeScript](https://img.shields.io/badge/TypeScript-✔-3178c6?logo=typescript)
5
+ ![Version](https://img.shields.io/badge/version-1.0.3-blue) ![License](https://img.shields.io/badge/license-MIT-green)
6
+
7
+ ✨ Flessibile e completamente personalizzabile per la gestione di tabelle dati.
8
+
9
+ ---
10
+
11
+
12
+ ## 🚀 Features
13
+
14
+ - 🔍 **Filtro globale**
15
+ - 📄 **Paginazione** client & server
16
+ - ⬆️⬇️ **Ordinamento colonne**
17
+ - ✅ **Selezione multipla righe**
18
+ - ⚙️ **Azioni CRUD (View / Update / Delete)**
19
+ - 📥 **Download dati filtrati**
20
+ - 🎨 **Altamente customizzabile tramite slot**
21
+ - 🔄 **Supporto modalità server-side**
22
+
23
+ ---
24
+
25
+
26
+
27
+ # Guida all'Utilizzo e all'Implementazione di `DataTableList`
28
+
29
+ `DataTableList` è un componente riutilizzabile sviluppato in **Vue 3** (con TypeScript e Composition API). Offre una tabella dati flessibile con supporto nativo per paginazione, ordinamento, filtraggio, azioni di riga, esportazione dati, e selezione multipla tramite checkbox.
30
+
31
+ ---
32
+
33
+ [![downloads](https://img.shields.io/github/stars/badges/shields)](https://github.com/mssalvo/data-table-list-vue3) [npm version](https://npmjs.com)
34
+
35
+
36
+ ---
37
+
38
+ ## 📦 Setup
39
+
40
+ ```sh
41
+ npm install data-table-list@latest
42
+ ```
43
+
44
+ ---
45
+
46
+ ## 🎬 Demo
47
+
48
+ ![Preview](https://raw.githubusercontent.com/mssalvo/data-table-list-vue3/refs/heads/main/src/docs/datalist1.png)
49
+
50
+ ---
51
+
52
+ ![Preview](https://raw.githubusercontent.com/mssalvo/data-table-list-vue3/refs/heads/main/src/docs/datalist2.png)
53
+
54
+ ---
55
+
56
+ ![Preview](https://raw.githubusercontent.com/mssalvo/data-table-list-vue3/refs/heads/main/src/docs/datalist3.png)
57
+
58
+
59
+ ---
60
+
61
+
62
+ ## Offrimi un caffè
63
+
64
+ Se questo progetto ti è utile nel tuo lavoro, considera di supportarlo con un caffè ☕
65
+
66
+ 👉 [[paypal.me/msalvonet](https://paypal.me/msalvonet)]
67
+
68
+ 👉 [[buymeacoffee.com/mssalvo](https://buymeacoffee.com/mssalvo)]
69
+
70
+
71
+ Ogni supporto aiuta a mantenere e migliorare il progetto 🚀
72
+ ``
73
+
74
+
75
+
76
+ ---
77
+
78
+ ## usage
79
+
80
+
81
+ ```ts
82
+ import { DataTableList, Avatar } from 'data-table-list';
83
+ import type { DataTableConf } from 'data-table-list';
84
+ import 'data-table-list/dist/data-table-list.css'; // This imports the new stable CSS
85
+
86
+ ```
87
+
88
+
89
+ ---
90
+
91
+ ## 1. Strutture Dati e Interfacce (Modelli)
92
+
93
+ Il componente utilizza le seguenti interfacce TypeScript definite in [Models.ts](file://data-table-list/src/model/Models.ts):
94
+
95
+ ```ts
96
+ export interface DataTableConf {
97
+ columns: ColumnTable[]; // Configurazione delle colonne
98
+ actionsRow?: ActionRow; // Azioni di default abilitate per riga
99
+ viewActions: boolean; // Se mostrare o meno la colonna delle azioni
100
+ viewDownload?: boolean; // Se visualizzare il pulsante per il download/esportazione
101
+ paginator?: boolean; // Abilita la paginazione
102
+ paginatorPosition?: PaginatorPosition; // Posizione e allineamento del paginatore
103
+ isserver?: boolean; // Se la paginazione e il filtraggio sono gestiti lato server
104
+ serverPaging?: ServerPaging; // Metadati per la paginazione server-side
105
+ dimensionePagina: number; // Numero di righe per pagina
106
+ messageNotRecords?: string; // Messaggio mostrato se la tabella è vuota
107
+ }
108
+
109
+ export interface ColumnTable {
110
+ title: string; // Intestazione della colonna
111
+ property: string; // Nome della chiave nell'oggetto riga
112
+ style?: string; // Stile CSS inline da applicare alla cella (es: "width: 150px")
113
+ callFormatt?: Function; // Funzione custom per formattare il valore della cella
114
+ hidden?: boolean; // Nasconde la colonna se impostato a true
115
+ order?: boolean; // Abilita l'ordinamento client-side per questa colonna
116
+ }
117
+
118
+ export interface ActionRow {
119
+ view: boolean; // Mostra l'icona Visualizza (it-password-visible)
120
+ update: boolean; // Mostra l'icona Modifica (it-pencil)
121
+ delete: boolean; // Mostra l'icona Elimina (it-delete)
122
+ }
123
+
124
+ export interface PaginatorPosition {
125
+ top: boolean; // Mostra il paginatore sopra la tabella
126
+ bottom: boolean; // Mostra il paginatore sotto la tabella
127
+ class: 'center' | 'left' | 'right'; // Allineamento del paginatore ('left', 'center', 'right')
128
+ }
129
+
130
+ export interface ServerPaging {
131
+ serverTotaleElementi: number; // Numero totale di elementi sul server
132
+ serverTotalePagine: number; // Numero totale di pagine sul server
133
+ }
134
+ ```
135
+
136
+ ---
137
+
138
+ ## 2. API del Componente (Props ed Emits)
139
+
140
+ ### Props (Proprietà)
141
+
142
+ | Nome Prop | Tipo | Obbligatorio | Descrizione |
143
+ | :--- | :--- | :--- | :--- |
144
+ | `dataTableConf` | `DataTableConf` | **Sì** | Configurazione della struttura e del comportamento della tabella. |
145
+ | `dataItems` | `any[]` | **Sì** | Array di dati (righe) da visualizzare. Se `isserver` è `false`, contiene tutti i record. Se `isserver` è `true`, contiene solo i record della pagina corrente. |
146
+ | `filter` | `string` | No | Stringa di ricerca globale. Se specificata e `isserver` è `false`, la tabella esegue un filtro client-side su tutte le colonne visibili. |
147
+ | `showCheckbox` | `boolean` | No | Se impostato a `true`, aggiunge una prima colonna con checkbox per la selezione multipla delle righe. |
148
+
149
+ ### Emits (Eventi)
150
+
151
+ | Nome Evento | Parametri | Descrizione |
152
+ | :--- | :--- | :--- |
153
+ | `@onview` | `(obj: object)` | Emesso al click sul pulsante "Visualizza" della riga (default action). Riceve l'oggetto riga. |
154
+ | `@onupdate` | `(obj: object)` | Emesso al click sul pulsante "Modifica" della riga (default action). Riceve l'oggetto riga. |
155
+ | `@ondelete` | `(obj: object)` | Emesso al click sul pulsante "Elimina" della riga (default action). Riceve l'oggetto riga. |
156
+ | `@onavanti` | `(current: number, size: number)` | Emesso quando si va alla pagina successiva **solo se** `isserver` è `true`. `current` è l'indice di pagina (0-indexed), `size` è la dimensione della pagina. |
157
+ | `@onindietro` | `(current: number, size: number)` | Emesso quando si va alla pagina precedente **solo se** `isserver` è `true`. `current` è l'indice di pagina (0-indexed), `size` è la dimensione della pagina. |
158
+ | `@ondownload` | `(call: any[])` | Emesso al click sul pulsante di download. Riceve la lista corrente dei dati filtrati. |
159
+ | `@onchecked` | `(obj: any[])` | Emesso ogni volta che cambia la selezione delle righe tramite checkbox. Riceve l'array delle righe attualmente selezionate. |
160
+
161
+ ---
162
+
163
+ ## 3. Slot di Personalizzazione
164
+
165
+ `DataTableList` offre diversi slot con scoped-slots per personalizzare profondamente il markup:
166
+
167
+ * **`#columnTd`**: Permette di personalizzare il rendering del contenuto di ogni cella. Riceve `{ row, column }` come parametri dello slot.
168
+ * **`#iconTd`**: Consente di posizionare un'icona o un elemento decorativo a fianco del valore della cella. Riceve `{ row, column }`.
169
+ * **`#actions`**: Sostituisce i pulsanti di default (Visualizza, Modifica, Elimina) con pulsanti personalizzati o menu dropdown. Riceve `{ row }`.
170
+ * **`#checkbox`**: Sostituisce il checkbox di default delle righe. Riceve `{ row }`.
171
+ * **`#download`**: Personalizza l'aspetto del pulsante di download. Riceve l'evento `{ ondownload: { oncall: Function } }`.
172
+ * **`#iconView`**: Consente di sostituire l'icona menu view.
173
+ * **`#iconUpdate`**: Consente di sostituire l'icona menu update.
174
+ * **`#iconDelete`**: Consente di sostituire l'icona menu delete.
175
+ * **`#iconAvantiBottom`**: Consente di sostituire l'icona navigatore avanti con posizione bottom.
176
+ * **`#iconIndietroBottom`**: Consente di sostituire l'icona navigatore indietro con posizione bottom.
177
+ * **`#iconAvantiTop`**: Consente di sostituire l'icona navigatore avanti con posizione top.
178
+ * **`#iconIndietroTop`**: Consente di sostituire l'icona navigatore indietro con posizione top.
179
+
180
+ ---
181
+
182
+ ## 4. Scenari d'Uso ed Esempi di Implementazione
183
+
184
+ ### Scenario A: Tabella Semplice Client-Side con Paginazione e Ordinamento
185
+ In questo scenario, i dati sono interamente caricati in memoria. Il componente gestisce la paginazione, la ricerca globale e l'ordinamento in modo autonomo.
186
+
187
+ ```html
188
+ <script setup lang="ts">
189
+ import { ref } from 'vue';
190
+ import { DataTableList, Avatar } from 'data-table-list';
191
+ import type { DataTableConf } from 'data-table-list';
192
+ import 'data-table-list/dist/data-table-list.css';
193
+
194
+ const searchFilter = ref('');
195
+
196
+ const tableConfig = ref<DataTableConf>({
197
+ columns: [
198
+ { title: 'ID', property: 'id', order: true },
199
+ { title: 'Nome', property: 'name', order: true },
200
+ { title: 'Email', property: 'email', order: true }
201
+ ],
202
+ isserver: false,
203
+ paginator: true,
204
+ paginatorPosition: { top: true, bottom: true, class: 'right' },
205
+ viewActions: true,
206
+ actionsRow: { view: true, update: true, delete: true },
207
+ dimensionePagina: 5,
208
+ messageNotRecords: 'Nessun utente trovato.'
209
+ });
210
+
211
+ const items = ref([
212
+ { id: 1, name: 'Mario Rossi', email: 'mario.rossi@example.com' },
213
+ { id: 2, name: 'Giuseppe Verdi', email: 'giuseppe.verdi@example.com' },
214
+ { id: 3, name: 'Luca Bianchi', email: 'luca.bianchi@example.com' },
215
+ { id: 4, name: 'Anna Neri', email: 'anna.neri@example.com' },
216
+ { id: 5, name: 'Sofia Gialli', email: 'sofia.gialli@example.com' },
217
+ { id: 6, name: 'Elena Rosa', email: 'elena.rosa@example.com' }
218
+ ]);
219
+
220
+ const handleView = (item: any) => console.log('Visualizza:', item);
221
+ const handleUpdate = (item: any) => console.log('Modifica:', item);
222
+ const handleDelete = (item: any) => console.log('Elimina:', item);
223
+ </script>
224
+
225
+ <template>
226
+ <div class="container my-4">
227
+ <!-- Input di ricerca collegato alla prop :filter -->
228
+ <div class="form-group mb-3">
229
+ <label for="search">Cerca Utente</label>
230
+ <input id="search" v-model="searchFilter" type="text" class="form-control" placeholder="Cerca...">
231
+ </div>
232
+
233
+ <DataTableList
234
+ :data-items="items"
235
+ :data-table-conf="tableConfig"
236
+ :filter="searchFilter"
237
+ @onview="handleView"
238
+ @onupdate="handleUpdate"
239
+ @ondelete="handleDelete"
240
+ />
241
+ </div>
242
+ </template>
243
+ ```
244
+
245
+ ---
246
+
247
+ ### Scenario B: Formattazione Personalizzata di Colonne (`callFormatt`)
248
+ Quando si desidera applicare una formattazione al volo su una colonna (es. date, valute, o composizione stringhe) senza alterare i dati di origine, si può definire la funzione `callFormatt` nel modello `ColumnTable`.
249
+
250
+ ```ts
251
+ const tableConfig = ref<DataTableConf>({
252
+ columns: [
253
+ { title: 'ID', property: 'id' },
254
+ {
255
+ title: 'Nome Completo',
256
+ property: 'name',
257
+ // callFormatt riceve il valore del campo specificato in property e l'intera riga
258
+ callFormatt: (value: any, row: any) => {
259
+ return `${row.name.toUpperCase()} (${row.role})`;
260
+ }
261
+ },
262
+ {
263
+ title: 'Data Creazione',
264
+ property: 'createdAt',
265
+ callFormatt: (value: string) => {
266
+ return new Date(value).toLocaleDateString('it-IT');
267
+ }
268
+ }
269
+ ],
270
+ isserver: false,
271
+ viewActions: false,
272
+ dimensionePagina: 10
273
+ });
274
+
275
+ const items = ref([
276
+ { id: 1, name: 'Mario Rossi', role: 'Admin', createdAt: '2026-06-01T10:00:00Z' },
277
+ { id: 2, name: 'Giuseppe Verdi', role: 'User', createdAt: '2026-06-03T15:30:00Z' }
278
+ ]);
279
+ ```
280
+
281
+ ---
282
+
283
+ ### Scenario C: Personalizzazione Celle con Slot (`#columnTd` & Componenti Custom)
284
+ Se si necessita di inserire markup HTML complesso (es. Badge di stato, icone, o componenti esterni come `Avatar.vue`), si utilizza lo slot `#columnTd`.
285
+
286
+ ```html
287
+ <script setup lang="ts">
288
+ import { ref } from 'vue';
289
+ import { DataTableList, Avatar } from 'data-table-list';
290
+ import type { DataTableConf } from 'data-table-list';
291
+ import 'data-table-list/dist/data-table-list.css';
292
+
293
+ const tableConfig = ref<DataTableConf>({
294
+ columns: [
295
+ { title: 'Avatar', property: 'avatar', style: 'width: 80px;' },
296
+ { title: 'Dettagli Utente', property: 'details' },
297
+ { title: 'Stato', property: 'status' }
298
+ ],
299
+ isserver: false,
300
+ viewActions: false,
301
+ dimensionePagina: 5
302
+ });
303
+
304
+ const items = ref([
305
+ { id: 1, name: 'Mario Rossi', email: 'mario.rossi@example.com', status: 'Attivo', statusColor: 'bg-success' },
306
+ { id: 2, name: 'Giuseppe Verdi', email: 'giuseppe.verdi@example.com', status: 'Sospeso', statusColor: 'bg-warning' }
307
+ ]);
308
+ </script>
309
+
310
+ <template>
311
+ <DataTableList :data-items="items" :data-table-conf="tableConfig">
312
+ <!-- Utilizzo dello scoped slot per le celle -->
313
+ <template #columnTd="{ row, column }">
314
+
315
+ <!-- Cella Avatar -->
316
+ <div v-if="column.property === 'avatar'">
317
+ <Avatar
318
+ :label="row.name.charAt(0) + row.name.split(' ')[1]?.charAt(0)"
319
+ :background-dynamics="true"
320
+ />
321
+ </div>
322
+
323
+ <!-- Cella Dettagli Utente -->
324
+ <div v-else-if="column.property === 'details'">
325
+ <strong>{{ row.name }}</strong><br>
326
+ <small class="text-secondary">{{ row.email }}</small>
327
+ </div>
328
+
329
+ <!-- Cella Stato -->
330
+ <div v-else-if="column.property === 'status'">
331
+ <span class="badge rounded-pill text-white" :class="row.statusColor">
332
+ {{ row.status }}
333
+ </span>
334
+ </div>
335
+
336
+ </template>
337
+ </DataTableList>
338
+ </template>
339
+ ```
340
+
341
+ ---
342
+
343
+ ### Scenario D: Selezione Multipla con Checkbox e Evento `@onchecked`
344
+ Il componente supporta la selezione di elementi tramite una colonna di checkbox abilitata tramite la prop `:show-checkbox="true"`.
345
+
346
+ ```html
347
+ <script setup lang="ts">
348
+ import { ref } from 'vue';
349
+ import { DataTableList, Avatar } from 'data-table-list';
350
+ import type { DataTableConf } from 'data-table-list';
351
+ import 'data-table-list/dist/data-table-list.css';
352
+
353
+ const tableConfig = ref<DataTableConf>({
354
+ columns: [
355
+ { title: 'ID', property: 'id' },
356
+ { title: 'Prodotto', property: 'product' }
357
+ ],
358
+ isserver: false,
359
+ viewActions: false,
360
+ dimensionePagina: 10
361
+ });
362
+
363
+ const items = ref([
364
+ { id: 101, product: 'Computer Laptop' },
365
+ { id: 102, product: 'Monitor 4K' },
366
+ { id: 103, product: 'Tastiera Meccanica' }
367
+ ]);
368
+
369
+ const selectedItems = ref<any[]>([]);
370
+
371
+ // Salva gli elementi selezionati nello stato locale
372
+ const handleChecked = (checkedRows: any[]) => {
373
+ selectedItems.value = checkedRows;
374
+ console.log('Prodotti selezionati:', selectedItems.value);
375
+ };
376
+ </script>
377
+
378
+ <template>
379
+ <div class="my-3">
380
+ <DataTableList
381
+ :data-items="items"
382
+ :data-table-conf="tableConfig"
383
+ :show-checkbox="true"
384
+ @onchecked="handleChecked"
385
+ />
386
+
387
+ <div class="mt-3">
388
+ <h5>Elementi selezionati: {{ selectedItems.length }}</h5>
389
+ <ul>
390
+ <li v-for="item in selectedItems" :key="item.id">{{ item.product }}</li>
391
+ </ul>
392
+ </div>
393
+ </div>
394
+ </template>
395
+ ```
396
+
397
+ ---
398
+
399
+ ### Scenario E: Menu Azioni Personalizzato (Dropdown Bootstrap Italia)
400
+ Invece di mostrare i tre pulsanti standard in linea (view, update, delete), è possibile personalizzare la colonna delle azioni inserendo un menu a comparsa (dropdown) in perfetto stile Bootstrap Italia utilizzando lo slot `#actions`.
401
+
402
+ ```html
403
+ <script setup lang="ts">
404
+ import { ref } from 'vue';
405
+ import { DataTableList, Avatar } from 'data-table-list';
406
+ import type { DataTableConf } from 'data-table-list';
407
+ import 'data-table-list/dist/data-table-list.css';
408
+
409
+ const tableConfig = ref<DataTableConf>({
410
+ columns: [
411
+ { title: 'ID', property: 'id' },
412
+ { title: 'Documento', property: 'docName' }
413
+ ],
414
+ isserver: false,
415
+ viewActions: true, // Deve essere true per abilitare la colonna azioni
416
+ dimensionePagina: 10
417
+ });
418
+
419
+ const items = ref([
420
+ { id: 1, docName: 'Fattura_2026_01.pdf' },
421
+ { id: 2, docName: 'Contratto_Firmato.pdf' }
422
+ ]);
423
+
424
+ const scaricaDocumento = (row: any) => console.log('Download', row.docName);
425
+ const archiviaDocumento = (row: any) => console.log('Archivia', row.id);
426
+ </script>
427
+
428
+ <template>
429
+ <DataTableList :data-items="items" :data-table-conf="tableConfig">
430
+ <!-- Personalizzazione colonna azioni tramite slot -->
431
+ <template #actions="{ row }">
432
+ <div class="dropdown dropstart text-center">
433
+ <a class="btn btn-dropdown dropdown-toggle" href="#" role="button" id="dropdownActions" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
434
+ <!-- Icona a tre pallini di Bootstrap Italia -->
435
+ <svg class="icon-expand icon icon-sm icon-secondary">
436
+ <use href="@/assets/svg/sprites.svg#it-more-items"></use>
437
+ </svg>
438
+ </a>
439
+ <div class="dropdown-menu" aria-labelledby="dropdownActions">
440
+ <div class="link-list-wrapper">
441
+ <ul class="link-list">
442
+ <li>
443
+ <a class="dropdown-item list-item" @click.prevent="scaricaDocumento(row)">
444
+ <span>
445
+ <svg class="icon icon-primary" aria-hidden="true">
446
+ <use href="@/assets/svg/sprites.svg#it-download"></use>
447
+ </svg> Scarica
448
+ </span>
449
+ </a>
450
+ </li>
451
+ <li>
452
+ <a class="dropdown-item list-item" @click.prevent="archiviaDocumento(row)">
453
+ <span>
454
+ <svg class="icon icon-primary" aria-hidden="true">
455
+ <use href="@/assets/svg/sprites.svg#it-box"></use>
456
+ </svg> Archivia
457
+ </span>
458
+ </a>
459
+ </li>
460
+ </ul>
461
+ </div>
462
+ </div>
463
+ </div>
464
+ </template>
465
+ </DataTableList>
466
+ </template>
467
+ ```
468
+
469
+ ---
470
+
471
+ ### Scenario F: Paginazione Server-Side (`isserver: true`)
472
+ Se la sorgente dati ha molti elementi, la paginazione deve avvenire sul server.
473
+ * `isserver` deve essere impostato a `true`.
474
+ * È necessario compilare `serverPaging` con i totali di elementi e pagine forniti dalle API.
475
+ * Bisogna ascoltare gli eventi `@onavanti` e `@onindietro` per richiedere la pagina corretta al server e aggiornare l'array `dataItems`.
476
+
477
+ ```html
478
+ <script setup lang="ts">
479
+ import { ref, onMounted } from 'vue';
480
+ import { DataTableList, Avatar } from 'data-table-list';
481
+ import type { DataTableConf } from 'data-table-list';
482
+ import 'data-table-list/dist/data-table-list.css';
483
+
484
+ // Stato locale per i dati e il caricamento
485
+ const items = ref<any[]>([]);
486
+ const loading = ref(false);
487
+
488
+ const tableConfig = ref<DataTableConf>({
489
+ columns: [
490
+ { title: 'ID', property: 'id' },
491
+ { title: 'Descrizione', property: 'description' }
492
+ ],
493
+ isserver: true, // Indica che paginazione e ricerca avvengono sul server
494
+ paginator: true,
495
+ paginatorPosition: { top: false, bottom: true, class: 'center' },
496
+ viewActions: false,
497
+ dimensionePagina: 10,
498
+ serverPaging: {
499
+ serverTotaleElementi: 0, // Inizializzato a 0, popolato in seguito
500
+ serverTotalePagine: 0
501
+ }
502
+ });
503
+
504
+ // Funzione simulata per caricare i dati dalle API
505
+ const fetchApiData = async (page: number, size: number) => {
506
+ loading.value = true;
507
+ try {
508
+ // Es. const res = await axios.get(`/api/items?page=${page}&size=${size}`);
509
+ await new Promise((resolve) => setTimeout(resolve, 400));
510
+
511
+ const mockTotalElements = 50;
512
+ const mockTotalPages = Math.ceil(mockTotalElements / size);
513
+
514
+ // Creazione dati simulati per la pagina corrente (es. pagina 0 -> ID 1-10)
515
+ const rows = [];
516
+ const start = page * size;
517
+ for (let i = 0; i < size; i++) {
518
+ const id = start + i + 1;
519
+ if (id <= mockTotalElements) {
520
+ rows.push({ id, description: `Elemento server ${id}` });
521
+ }
522
+ }
523
+
524
+ items.value = rows;
525
+
526
+ // Aggiornamento dei metadati di paginazione server-side
527
+ tableConfig.value.serverPaging = {
528
+ serverTotaleElementi: mockTotalElements,
529
+ serverTotalePagine: mockTotalPages
530
+ };
531
+ } finally {
532
+ loading.value = false;
533
+ }
534
+ };
535
+
536
+ // Gestione del cambio pagina in avanti
537
+ const handleAvanti = async (currentPage: number, size: number) => {
538
+ await fetchApiData(currentPage, size);
539
+ };
540
+
541
+ // Gestione del cambio pagina all'indietro
542
+ const handleIndietro = async (currentPage: number, size: number) => {
543
+ await fetchApiData(currentPage, size);
544
+ };
545
+
546
+ onMounted(async () => {
547
+ // Caricamento iniziale
548
+ await fetchApiData(0, tableConfig.value.dimensionePagina);
549
+ });
550
+ </script>
551
+
552
+ <template>
553
+ <div class="container my-4">
554
+ <h3>Paginazione Server-Side</h3>
555
+ <div v-if="loading" class="alert alert-info">Caricamento...</div>
556
+
557
+ <DataTableList
558
+ :data-items="items"
559
+ :data-table-conf="tableConfig"
560
+ @onavanti="handleAvanti"
561
+ @onindietro="handleIndietro"
562
+ />
563
+ </div>
564
+ </template>
565
+ ```
566
+
567
+ ---
568
+
569
+ ### Scenario G: Esportazione e Download dei Dati Filtrati
570
+ Il componente offre la possibilità di abilitare un pulsante per il download dei dati.
571
+ * Impostare `viewDownload: true` nella configurazione `DataTableConf`.
572
+ * Ascoltare l'evento `@ondownload`, che riceve la lista dei record attualmente filtrati dalla ricerca globale (`filterComputer`).
573
+
574
+ ```html
575
+ <script setup lang="ts">
576
+ import { ref } from 'vue';
577
+ import { DataTableList, Avatar } from 'data-table-list';
578
+ import type { DataTableConf } from 'data-table-list';
579
+ import 'data-table-list/dist/data-table-list.css';
580
+
581
+ const searchFilter = ref('');
582
+
583
+ const tableConfig = ref<DataTableConf>({
584
+ columns: [
585
+ { title: 'ID', property: 'id' },
586
+ { title: 'Nome', property: 'name' }
587
+ ],
588
+ isserver: false,
589
+ viewActions: false,
590
+ viewDownload: true, // Mostra l'icona per il download in alto a destra
591
+ dimensionePagina: 10
592
+ });
593
+
594
+ const items = ref([
595
+ { id: 1, name: 'Mario Rossi' },
596
+ { id: 2, name: 'Giuseppe Verdi' },
597
+ { id: 3, name: 'Luca Bianchi' }
598
+ ]);
599
+
600
+ // Funzione di esportazione CSV client-side al click sul download
601
+ const handleDownload = (filteredData: any[]) => {
602
+ const csvHeaders = 'ID,Nome\n';
603
+ const csvRows = filteredData.map(item => `${item.id},"${item.name}"`).join('\n');
604
+ const csvContent = 'data:text/csv;charset=utf-8,' + csvHeaders + csvRows;
605
+
606
+ const encodedUri = encodeURI(csvContent);
607
+ const link = document.createElement('a');
608
+ link.setAttribute('href', encodedUri);
609
+ link.setAttribute('download', 'esportazione_tabella.csv');
610
+ document.body.appendChild(link);
611
+ link.click();
612
+ document.body.removeChild(link);
613
+ };
614
+ </script>
615
+
616
+ <template>
617
+ <div class="container my-4">
618
+ <div class="form-group mb-3">
619
+ <input v-model="searchFilter" type="text" class="form-control" placeholder="Cerca...">
620
+ </div>
621
+
622
+ <DataTableList
623
+ :data-items="items"
624
+ :data-table-conf="tableConfig"
625
+ :filter="searchFilter"
626
+ @ondownload="handleDownload"
627
+ />
628
+ </div>
629
+ </template>
630
+ ```
631
+
632
+ ---
633
+
634
+ ## 5. Dettagli Implementativi Importanti
635
+
636
+ 1. **Identificativi Checkbox (`checkId`)**: Quando viene attivata la funzionalità checkbox (`showCheckbox = true`), il componente genera temporaneamente la chiave `checkId` all'interno dei record dell'array `dataItems` per identificare univocamente le righe selezionate. L'array restituito dall'evento `@onchecked` conterrà questi campi aggiuntivi.
637
+ 2. **Reset dell'Ordinamento al cambio pagina**: Ad ogni navigazione di pagina (avanti o indietro) o reset del filtro di ricerca, viene richiamata la funzione `resetClassOrder()` che rimuove la classe CSS `.icon-primaryOrder` dall'header della colonna ordinata, indicando che la nuova pagina mostra i dati nel loro stato originario.
638
+
639
+ ---
640
+
641
+ ## 🧑‍💻 Autore
642
+
643
+ **MSalvo**
644
+ 🔗 https://github.com/mssalvo
645
+
646
+ ---
647
+
648
+ ## 📄 Licenza
649
+
650
+ Distribuito sotto licenza MIT.
651
+ Vedi file LICENSE per dettagli.