391 lines
9.4 KiB
Markdown
391 lines
9.4 KiB
Markdown
# DataTable Component - Usage Guide
|
|
|
|
This DataTable component follows the shadcn-vue architecture and uses TanStack Table v8 for powerful table functionality.
|
|
|
|
## Features
|
|
|
|
- ✅ Client-side and server-side pagination
|
|
- ✅ Sorting (single column)
|
|
- ✅ Filtering/Search
|
|
- ✅ Row selection
|
|
- ✅ Column visibility toggle
|
|
- ✅ Customizable column definitions
|
|
- ✅ Loading states
|
|
- ✅ Empty states
|
|
- ✅ Flexible toolbar
|
|
- ✅ Cell-level customization via slots
|
|
- ✅ Responsive design
|
|
- ✅ Laravel Inertia integration
|
|
|
|
## Basic Usage
|
|
|
|
### Simple Format (Recommended for basic tables)
|
|
|
|
```vue
|
|
<script setup>
|
|
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
|
|
|
|
const columns = [
|
|
{ key: 'id', label: 'ID', sortable: true },
|
|
{ key: 'name', label: 'Name', sortable: true },
|
|
{ key: 'email', label: 'Email', sortable: true },
|
|
{ key: 'status', label: 'Status' },
|
|
];
|
|
|
|
const data = ref([
|
|
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'Active' },
|
|
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'Inactive' },
|
|
]);
|
|
</script>
|
|
|
|
<template>
|
|
<DataTable :columns="columns" :data="data" />
|
|
</template>
|
|
```
|
|
|
|
### Advanced Format (Full TanStack Table power)
|
|
|
|
```vue
|
|
<script setup>
|
|
import { h } from 'vue';
|
|
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
|
|
import { Badge } from '@/Components/ui/badge';
|
|
import { columns } from './columns'; // Import from separate file
|
|
|
|
const data = ref([...]);
|
|
</script>
|
|
|
|
<template>
|
|
<DataTable :columns="columns" :data="data" />
|
|
</template>
|
|
```
|
|
|
|
See `columns-example.js` for comprehensive column definition examples.
|
|
|
|
## Props
|
|
|
|
### Data Props
|
|
- `columns` (Array, required) - Column definitions (simple or TanStack format)
|
|
- `data` (Array, default: []) - Array of data objects
|
|
- `meta` (Object, default: null) - Laravel pagination meta for server-side
|
|
- `loading` (Boolean, default: false) - Loading state
|
|
|
|
### Server-side Props
|
|
- `routeName` (String) - Laravel route name for server-side requests
|
|
- `routeParams` (Object) - Additional route parameters
|
|
- `pageParamName` (String, default: 'page') - Custom page parameter name
|
|
- `onlyProps` (Array) - Inertia.js only props
|
|
- `preserveState` (Boolean, default: true)
|
|
- `preserveScroll` (Boolean, default: true)
|
|
|
|
### Sorting & Filtering
|
|
- `sort` (Object, default: {key: null, direction: null})
|
|
- `search` (String, default: '')
|
|
- `filterColumn` (String) - Column to filter on
|
|
- `filterPlaceholder` (String, default: 'Filter...')
|
|
|
|
### Pagination
|
|
- `showPagination` (Boolean, default: true)
|
|
- `pageSize` (Number, default: 10)
|
|
- `pageSizeOptions` (Array, default: [10, 25, 50, 100])
|
|
|
|
### Features
|
|
- `enableRowSelection` (Boolean, default: false)
|
|
- `showToolbar` (Boolean, default: true)
|
|
- `striped` (Boolean, default: false)
|
|
- `hoverable` (Boolean, default: true)
|
|
- `rowKey` (String|Function, default: 'id')
|
|
|
|
### Empty State
|
|
- `emptyText` (String, default: 'No results.')
|
|
- `emptyIcon` (String|Object|Array)
|
|
- `emptyDescription` (String)
|
|
|
|
## Events
|
|
|
|
- `@update:search` - Emitted when search changes
|
|
- `@update:sort` - Emitted when sort changes
|
|
- `@update:page` - Emitted when page changes
|
|
- `@update:pageSize` - Emitted when page size changes
|
|
- `@row:click` - Emitted when row is clicked
|
|
- `@selection:change` - Emitted when selection changes
|
|
|
|
## Client-side Example
|
|
|
|
```vue
|
|
<script setup>
|
|
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
|
|
|
|
const columns = [
|
|
{ key: 'id', label: 'ID', sortable: true },
|
|
{ key: 'name', label: 'Name', sortable: true },
|
|
{ key: 'email', label: 'Email', sortable: true },
|
|
];
|
|
|
|
const data = ref([
|
|
// Your data here
|
|
]);
|
|
</script>
|
|
|
|
<template>
|
|
<DataTable
|
|
:columns="columns"
|
|
:data="data"
|
|
:page-size="10"
|
|
filter-column="email"
|
|
filter-placeholder="Filter emails..."
|
|
enable-row-selection
|
|
/>
|
|
</template>
|
|
```
|
|
|
|
## Server-side Example (Laravel Inertia)
|
|
|
|
### Controller
|
|
```php
|
|
public function index(Request $request)
|
|
{
|
|
$query = Client::query();
|
|
|
|
// Search
|
|
if ($request->search) {
|
|
$query->where('name', 'like', "%{$request->search}%")
|
|
->orWhere('email', 'like', "%{$request->search}%");
|
|
}
|
|
|
|
// Sort
|
|
if ($request->sort && $request->direction) {
|
|
$query->orderBy($request->sort, $request->direction);
|
|
}
|
|
|
|
$clients = $query->paginate($request->per_page ?? 10);
|
|
|
|
return Inertia::render('Clients/Index', [
|
|
'clients' => $clients,
|
|
'filters' => $request->only(['search', 'sort', 'direction']),
|
|
]);
|
|
}
|
|
```
|
|
|
|
### Vue Component
|
|
```vue
|
|
<script setup>
|
|
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
|
|
|
|
const props = defineProps({
|
|
clients: Object,
|
|
filters: Object,
|
|
});
|
|
|
|
const columns = [
|
|
{ key: 'id', label: 'ID', sortable: true },
|
|
{ key: 'name', label: 'Name', sortable: true },
|
|
{ key: 'email', label: 'Email', sortable: true },
|
|
];
|
|
</script>
|
|
|
|
<template>
|
|
<DataTable
|
|
:columns="columns"
|
|
:data="clients.data"
|
|
:meta="clients.meta"
|
|
:search="filters.search"
|
|
:sort="{ key: filters.sort, direction: filters.direction }"
|
|
route-name="clients.index"
|
|
filter-column="email"
|
|
filter-placeholder="Search clients..."
|
|
:only-props="['clients']"
|
|
/>
|
|
</template>
|
|
```
|
|
|
|
## Custom Cell Rendering
|
|
|
|
### Using Slots
|
|
```vue
|
|
<template>
|
|
<DataTable :columns="columns" :data="data">
|
|
<!-- Custom cell for status column -->
|
|
<template #cell-status="{ value, row }">
|
|
<Badge :variant="value === 'active' ? 'default' : 'secondary'">
|
|
{{ value }}
|
|
</Badge>
|
|
</template>
|
|
|
|
<!-- Custom cell for actions -->
|
|
<template #cell-actions="{ row }">
|
|
<Button @click="editRow(row)">Edit</Button>
|
|
</template>
|
|
</DataTable>
|
|
</template>
|
|
```
|
|
|
|
### Using Column Definitions
|
|
```javascript
|
|
import { h } from 'vue';
|
|
import { Badge } from '@/Components/ui/badge';
|
|
|
|
export const columns = [
|
|
{
|
|
accessorKey: 'status',
|
|
header: 'Status',
|
|
cell: ({ row }) => {
|
|
const status = row.getValue('status');
|
|
return h(Badge, {
|
|
variant: status === 'active' ? 'default' : 'secondary'
|
|
}, () => status);
|
|
},
|
|
},
|
|
];
|
|
```
|
|
|
|
## Custom Toolbar
|
|
|
|
The new toolbar is simplified and follows shadcn-vue patterns:
|
|
|
|
```vue
|
|
<template>
|
|
<DataTable
|
|
:columns="columns"
|
|
:data="data"
|
|
filter-column="email"
|
|
filter-placeholder="Search emails..."
|
|
>
|
|
<!-- Add custom filter controls -->
|
|
<template #toolbar-filters="{ table }">
|
|
<select
|
|
@change="table.getColumn('status')?.setFilterValue($event.target.value)"
|
|
class="h-8 rounded-md border px-3"
|
|
>
|
|
<option value="">All Status</option>
|
|
<option value="active">Active</option>
|
|
<option value="inactive">Inactive</option>
|
|
</select>
|
|
</template>
|
|
|
|
<!-- Add custom action buttons -->
|
|
<template #toolbar-actions="{ table }">
|
|
<Button @click="exportData">Export</Button>
|
|
<Button @click="addNew">Add New</Button>
|
|
</template>
|
|
</DataTable>
|
|
</template>
|
|
```
|
|
|
|
Or completely replace the toolbar:
|
|
|
|
```vue
|
|
<template>
|
|
<DataTable :columns="columns" :data="data" :show-toolbar="false">
|
|
<template #toolbar="{ table }">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<Input
|
|
:model-value="table.getColumn('email')?.getFilterValue()"
|
|
@update:model-value="table.getColumn('email')?.setFilterValue($event)"
|
|
placeholder="Filter emails..."
|
|
class="max-w-sm"
|
|
/>
|
|
<div class="flex gap-2">
|
|
<Button @click="exportData">Export</Button>
|
|
<DataTableViewOptions :table="table" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</DataTable>
|
|
</template>
|
|
```
|
|
|
|
## Row Selection
|
|
|
|
```vue
|
|
<script setup>
|
|
import { ref } from 'vue';
|
|
import DataTable from '@/Components/DataTable/DataTableNew2.vue';
|
|
|
|
const selectedRows = ref([]);
|
|
|
|
function handleSelectionChange(keys) {
|
|
selectedRows.value = keys;
|
|
console.log('Selected rows:', keys);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<DataTable
|
|
:columns="columns"
|
|
:data="data"
|
|
enable-row-selection
|
|
@selection:change="handleSelectionChange"
|
|
/>
|
|
|
|
<div v-if="selectedRows.length">
|
|
Selected {{ selectedRows.length }} row(s)
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## Row Click Handler
|
|
|
|
```vue
|
|
<script setup>
|
|
function handleRowClick(row, index) {
|
|
console.log('Clicked row:', row);
|
|
// Navigate or perform action
|
|
router.visit(route('clients.show', row.id));
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<DataTable
|
|
:columns="columns"
|
|
:data="data"
|
|
@row:click="handleRowClick"
|
|
/>
|
|
</template>
|
|
```
|
|
|
|
## Tips
|
|
|
|
1. **Column Keys**: Always use consistent keys/accessorKeys across your data
|
|
2. **Server-side**: Always provide `meta` and `routeName` props together
|
|
3. **Performance**: For large datasets, use server-side pagination
|
|
4. **Styling**: Use column `class` property for custom styling
|
|
5. **Slots**: Prefer slots for complex cell rendering over h() functions
|
|
|
|
## Migration from Old DataTable
|
|
|
|
### Before (Old API)
|
|
```vue
|
|
<DataTable
|
|
:rows="clients.data"
|
|
:columns="columns"
|
|
:meta="clients.meta"
|
|
/>
|
|
```
|
|
|
|
### After (New API)
|
|
```vue
|
|
<DataTableNew2
|
|
:data="clients.data"
|
|
:columns="columns"
|
|
:meta="clients.meta"
|
|
route-name="clients.index"
|
|
/>
|
|
```
|
|
|
|
Main changes:
|
|
- `rows` → `data`
|
|
- Added `route-name` prop for server-side
|
|
- More consistent prop naming
|
|
- Better TypeScript support
|
|
- More flexible column definitions
|
|
|
|
## Component Files
|
|
|
|
- `DataTableNew2.vue` - Main table component
|
|
- `DataTableColumnHeader.vue` - Sortable column header
|
|
- `DataTablePagination.vue` - Pagination controls
|
|
- `DataTableViewOptions.vue` - Column visibility toggle
|
|
- `DataTableToolbar.vue` - Toolbar component
|
|
- `columns-example.js` - Column definition examples
|