add table actions to datatable, client page, start writing db method for clients
This commit is contained in:
parent
a67e86af44
commit
df1df3f882
9 changed files with 1844 additions and 194 deletions
|
|
@ -11,6 +11,7 @@ A feature-rich data table component built with PrimeVue's DataTable. This compon
|
|||
<DataTable
|
||||
:columns="tableColumns"
|
||||
:data="tableData"
|
||||
:tableActions="tableActions"
|
||||
table-name="my-table"
|
||||
@row-click="handleRowClick"
|
||||
/>
|
||||
|
|
@ -41,6 +42,32 @@ const tableData = ref([
|
|||
{ id: 2, name: "Jane Smith", status: "in progress" },
|
||||
]);
|
||||
|
||||
const tableActions = ref([
|
||||
{
|
||||
label: "Add Item",
|
||||
action: () => console.log("Add clicked"),
|
||||
icon: "pi pi-plus",
|
||||
style: "primary",
|
||||
// Global action - always available
|
||||
},
|
||||
{
|
||||
label: "View Details",
|
||||
action: (rowData) => console.log("View:", rowData),
|
||||
icon: "pi pi-eye",
|
||||
style: "info",
|
||||
requiresSelection: true,
|
||||
// Single selection action - enabled when exactly one row selected
|
||||
},
|
||||
{
|
||||
label: "Edit",
|
||||
action: (rowData) => console.log("Edit:", rowData),
|
||||
icon: "pi pi-pencil",
|
||||
style: "secondary",
|
||||
rowAction: true,
|
||||
// Row action - appears in each row's actions column
|
||||
},
|
||||
]);
|
||||
|
||||
const handleRowClick = (event) => {
|
||||
console.log("Row clicked:", event.data);
|
||||
};
|
||||
|
|
@ -85,6 +112,12 @@ const handleRowClick = (event) => {
|
|||
- **Type:** `Object`
|
||||
- **Default:** `{ global: { value: null, matchMode: FilterMatchMode.CONTAINS } }`
|
||||
|
||||
### `tableActions` (Array)
|
||||
|
||||
- **Description:** Array of action objects that define interactive buttons for the table. Actions can be global (always available), single-selection (enabled when exactly one row is selected), row-specific (displayed per row), or bulk (for multiple selected rows).
|
||||
- **Type:** `Array<Object>`
|
||||
- **Default:** `[]`
|
||||
|
||||
## Server-Side Pagination & Lazy Loading
|
||||
|
||||
When `lazy` is set to `true`, the DataTable operates in server-side mode with the following features:
|
||||
|
|
@ -159,6 +192,179 @@ Renders values as clickable buttons:
|
|||
}
|
||||
```
|
||||
|
||||
## Table Actions Configuration
|
||||
|
||||
Table actions allow you to add interactive buttons to your DataTable. Actions can be either global (displayed above the table) or row-specific (displayed in an actions column).
|
||||
|
||||
### Action Object Properties
|
||||
|
||||
Each action object in the `tableActions` array supports the following properties:
|
||||
|
||||
#### Basic Properties
|
||||
|
||||
- **`label`** (String, required) - Display text for the button
|
||||
- **`action`** (Function, required) - Function to execute when button is clicked
|
||||
- **`icon`** (String, optional) - PrimeVue icon class (e.g., 'pi pi-plus')
|
||||
- **`style`** (String, optional) - Button severity: 'primary', 'secondary', 'success', 'info', 'warning', 'danger'
|
||||
- **`size`** (String, optional) - Button size: 'small', 'normal', 'large'
|
||||
- **`requiresSelection`** (Boolean, default: false) - When true, action appears above table but is only enabled when exactly one row is selected
|
||||
- **`requiresMultipleSelection`** (Boolean, default: false) - Determines if action is for bulk operations on selected rows
|
||||
- **`rowAction`** (Boolean, default: false) - When true, action appears in each row's actions column
|
||||
- **`layout`** (Object, optional) - Layout configuration for action positioning and styling
|
||||
|
||||
#### Layout Configuration
|
||||
|
||||
The `layout` property allows you to control where and how actions are displayed:
|
||||
|
||||
##### For Top-Level Actions (Global and Single Selection)
|
||||
|
||||
```javascript
|
||||
layout: {
|
||||
position: "left" | "center" | "right", // Where to position in action bar
|
||||
variant: "filled" | "outlined" | "text" // Visual style variant
|
||||
}
|
||||
```
|
||||
|
||||
##### For Row Actions
|
||||
|
||||
```javascript
|
||||
layout: {
|
||||
priority: "primary" | "secondary" | "dropdown", // Display priority in row
|
||||
variant: "outlined" | "text" | "compact" | "icon-only" // Visual style
|
||||
}
|
||||
```
|
||||
|
||||
##### For Bulk Actions
|
||||
|
||||
```javascript
|
||||
layout: {
|
||||
position: "left" | "center" | "right", // Where to position in bulk action bar
|
||||
variant: "filled" | "outlined" | "text" // Visual style variant
|
||||
}
|
||||
```
|
||||
|
||||
#### Action Types
|
||||
|
||||
##### Global Actions (default behavior)
|
||||
|
||||
Global actions are displayed above the table and are always available:
|
||||
|
||||
```javascript
|
||||
{
|
||||
label: "Add New Item",
|
||||
action: () => {
|
||||
// Global action - no row data
|
||||
console.log("Opening create modal");
|
||||
},
|
||||
icon: "pi pi-plus",
|
||||
style: "primary"
|
||||
// No requiresSelection, requiresMultipleSelection, or rowAction properties
|
||||
}
|
||||
```
|
||||
|
||||
##### Single Selection Actions (`requiresSelection: true`)
|
||||
|
||||
Single selection actions are displayed above the table but are only enabled when exactly one row is selected. They receive the selected row data as a parameter:
|
||||
|
||||
```javascript
|
||||
{
|
||||
label: "View Details",
|
||||
action: (rowData) => {
|
||||
// Single selection action - receives selected row data
|
||||
console.log("Viewing:", rowData.name);
|
||||
router.push(`/items/${rowData.id}`);
|
||||
},
|
||||
icon: "pi pi-eye",
|
||||
style: "info",
|
||||
requiresSelection: true
|
||||
}
|
||||
```
|
||||
|
||||
##### Row Actions (`rowAction: true`)
|
||||
|
||||
Row actions are displayed in an "Actions" column for each row and receive that row's data as a parameter:
|
||||
|
||||
```javascript
|
||||
{
|
||||
label: "Edit",
|
||||
action: (rowData) => {
|
||||
// Row action - receives individual row data
|
||||
console.log("Editing:", rowData.name);
|
||||
openEditModal(rowData);
|
||||
},
|
||||
icon: "pi pi-pencil",
|
||||
style: "secondary",
|
||||
rowAction: true
|
||||
}
|
||||
```
|
||||
|
||||
##### Bulk Actions (`requiresMultipleSelection: true`)
|
||||
|
||||
Bulk actions are displayed above the table when rows are selected and receive an array of selected row data:
|
||||
|
||||
```javascript
|
||||
{
|
||||
label: "Delete Selected",
|
||||
action: (selectedRows) => {
|
||||
// Bulk action - receives array of selected row data
|
||||
console.log("Deleting:", selectedRows.length, "items");
|
||||
selectedRows.forEach(row => deleteItem(row.id));
|
||||
},
|
||||
icon: "pi pi-trash",
|
||||
style: "danger",
|
||||
requiresMultipleSelection: true
|
||||
}
|
||||
```
|
||||
|
||||
### Example Table Actions Configuration
|
||||
|
||||
```javascript
|
||||
const tableActions = [
|
||||
// Global action - shows above table, always available
|
||||
{
|
||||
label: "Add Client",
|
||||
action: () => modalStore.openModal("createClient"),
|
||||
icon: "pi pi-plus",
|
||||
style: "primary",
|
||||
},
|
||||
// Single selection action - shows above table, enabled when exactly one row selected
|
||||
{
|
||||
label: "View Details",
|
||||
action: (rowData) => router.push(`/clients/${rowData.id}`),
|
||||
icon: "pi pi-eye",
|
||||
style: "info",
|
||||
requiresSelection: true,
|
||||
},
|
||||
// Bulk action - shows when rows selected
|
||||
{
|
||||
label: "Delete Selected",
|
||||
action: (selectedRows) => {
|
||||
if (confirm(`Delete ${selectedRows.length} clients?`)) {
|
||||
selectedRows.forEach((row) => deleteClient(row.id));
|
||||
}
|
||||
},
|
||||
icon: "pi pi-trash",
|
||||
style: "danger",
|
||||
requiresMultipleSelection: true,
|
||||
},
|
||||
// Row actions - show in each row's actions column
|
||||
{
|
||||
label: "Edit",
|
||||
action: (rowData) => editClient(rowData),
|
||||
icon: "pi pi-pencil",
|
||||
style: "secondary",
|
||||
rowAction: true,
|
||||
},
|
||||
{
|
||||
label: "Quick View",
|
||||
action: (rowData) => showQuickPreview(rowData),
|
||||
icon: "pi pi-search",
|
||||
style: "info",
|
||||
rowAction: true,
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
### `rowClick`
|
||||
|
|
@ -253,6 +459,17 @@ const handleLazyLoad = async (event) => {
|
|||
- **Automatic filter initialization** on component mount
|
||||
- **Cross-component filter synchronization**
|
||||
|
||||
### Table Actions
|
||||
|
||||
- **Global actions** displayed above the table for general operations
|
||||
- **Row-specific actions** in dedicated actions column with row data access
|
||||
- **Bulk actions** for selected rows with multi-selection support
|
||||
- **Customizable button styles** with PrimeVue severity levels
|
||||
- **Icon support** using PrimeVue icons
|
||||
- **Automatic action handling** with error catching
|
||||
- **Disabled state** during loading operations
|
||||
- **Dynamic bulk action visibility** based on row selection
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Server-Side Paginated Table (Recommended for Large Datasets)
|
||||
|
|
@ -324,6 +541,126 @@ const handleLazyLoad = async (event) => {
|
|||
</template>
|
||||
```
|
||||
|
||||
### Interactive Table with Actions
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { useRouter } from "vue-router";
|
||||
import { useModalStore } from "./stores/modal";
|
||||
|
||||
const router = useRouter();
|
||||
const modalStore = useModalStore();
|
||||
|
||||
const columns = [
|
||||
{ fieldName: "name", label: "Name", sortable: true, filterable: true },
|
||||
{ fieldName: "status", label: "Status", type: "status", sortable: true },
|
||||
{ fieldName: "email", label: "Email", filterable: true },
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ id: 1, name: "John Doe", status: "completed", email: "john@example.com" },
|
||||
{
|
||||
id: 2,
|
||||
name: "Jane Smith",
|
||||
status: "in progress",
|
||||
email: "jane@example.com",
|
||||
},
|
||||
];
|
||||
|
||||
const tableActions = [
|
||||
// Global action
|
||||
{
|
||||
label: "Add User",
|
||||
action: () => {
|
||||
modalStore.openModal("createUser");
|
||||
},
|
||||
icon: "pi pi-plus",
|
||||
style: "primary",
|
||||
},
|
||||
// Single selection action
|
||||
{
|
||||
label: "View Details",
|
||||
action: (rowData) => {
|
||||
router.push(`/users/${rowData.id}`);
|
||||
},
|
||||
icon: "pi pi-eye",
|
||||
style: "info",
|
||||
requiresSelection: true,
|
||||
},
|
||||
// Bulk actions
|
||||
{
|
||||
label: "Export Selected",
|
||||
action: (selectedRows) => {
|
||||
exportUsers(selectedRows);
|
||||
},
|
||||
icon: "pi pi-download",
|
||||
style: "success",
|
||||
requiresMultipleSelection: true,
|
||||
},
|
||||
{
|
||||
label: "Delete Selected",
|
||||
action: (selectedRows) => {
|
||||
if (confirm(`Delete ${selectedRows.length} users?`)) {
|
||||
bulkDeleteUsers(selectedRows.map((row) => row.id));
|
||||
}
|
||||
},
|
||||
icon: "pi pi-trash",
|
||||
style: "danger",
|
||||
requiresMultipleSelection: true,
|
||||
},
|
||||
// Row actions
|
||||
{
|
||||
label: "Edit",
|
||||
action: (rowData) => {
|
||||
modalStore.openModal("editUser", rowData);
|
||||
},
|
||||
icon: "pi pi-pencil",
|
||||
style: "secondary",
|
||||
rowAction: true,
|
||||
},
|
||||
{
|
||||
label: "Quick Actions",
|
||||
action: (rowData) => {
|
||||
showQuickActionsMenu(rowData);
|
||||
},
|
||||
icon: "pi pi-ellipsis-v",
|
||||
style: "info",
|
||||
rowAction: true,
|
||||
},
|
||||
];
|
||||
|
||||
const deleteUser = async (userId) => {
|
||||
// API call to delete user
|
||||
await Api.deleteUser(userId);
|
||||
};
|
||||
|
||||
const bulkDeleteUsers = async (userIds) => {
|
||||
// API call to delete multiple users
|
||||
await Api.bulkDeleteUsers(userIds);
|
||||
};
|
||||
|
||||
const exportUsers = (users) => {
|
||||
// Export selected users to CSV/Excel
|
||||
const csv = generateCSV(users);
|
||||
downloadFile(csv, "users.csv");
|
||||
};
|
||||
|
||||
const refreshData = () => {
|
||||
// Refresh table data
|
||||
location.reload();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DataTable
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:tableActions="tableActions"
|
||||
table-name="users-table"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Basic Client-Side Table
|
||||
|
||||
```vue
|
||||
|
|
@ -427,6 +764,118 @@ const customFilters = {
|
|||
</template>
|
||||
```
|
||||
|
||||
### Layout-Aware Actions Example
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useModalStore } from '@/stores/modal'
|
||||
|
||||
const router = useRouter()
|
||||
const modalStore = useModalStore()
|
||||
|
||||
const columns = [
|
||||
{ fieldName: 'name', label: 'Client Name', sortable: true, filterable: true },
|
||||
{ fieldName: 'email', label: 'Email', filterable: true },
|
||||
{ fieldName: 'status', label: 'Status', type: 'status', sortable: true }
|
||||
]
|
||||
|
||||
const data = ref([
|
||||
{ id: 1, name: 'Acme Corp', email: 'contact@acme.com', status: 'completed' },
|
||||
{ id: 2, name: 'Tech Solutions', email: 'info@tech.com', status: 'in progress' }
|
||||
])
|
||||
|
||||
const tableActions = [
|
||||
// Left-positioned action with filled style
|
||||
{
|
||||
label: 'Quick Export',
|
||||
icon: 'pi pi-download',
|
||||
action: () => exportAllClients(),
|
||||
severity: 'success',
|
||||
layout: { position: 'left', variant: 'outlined' }
|
||||
},
|
||||
// Center-positioned bulk action
|
||||
{
|
||||
label: 'Archive Selected',
|
||||
icon: 'pi pi-archive',
|
||||
action: (selectedRows) => archiveClients(selectedRows),
|
||||
severity: 'warning',
|
||||
requiresMultipleSelection: true,
|
||||
layout: { position: 'center', variant: 'outlined' }
|
||||
},
|
||||
// Right-positioned main action
|
||||
{
|
||||
label: 'Create Client',
|
||||
icon: 'pi pi-plus',
|
||||
action: () => modalStore.openModal('createClient'),
|
||||
severity: 'info',
|
||||
layout: { position: 'right', variant: 'filled' }
|
||||
},
|
||||
// Single selection action
|
||||
{
|
||||
label: 'Edit Details',
|
||||
icon: 'pi pi-pencil',
|
||||
action: (rowData) => router.push(`/clients/${rowData.id}/edit`),
|
||||
severity: 'secondary',
|
||||
requiresSelection: true,
|
||||
layout: { position: 'left', variant: 'text' }
|
||||
},
|
||||
// Primary row action - most important
|
||||
{
|
||||
label: 'View',
|
||||
icon: 'pi pi-eye',
|
||||
action: (rowData) => router.push(`/clients/${rowData.id}`),
|
||||
severity: 'info',
|
||||
rowAction: true,
|
||||
layout: { priority: 'primary', variant: 'outlined' }
|
||||
},
|
||||
// Secondary row action - less important
|
||||
{
|
||||
label: 'Contact',
|
||||
icon: 'pi pi-phone',
|
||||
action: (rowData) => initiateContact(rowData),
|
||||
severity: 'success',
|
||||
rowAction: true,
|
||||
layout: { priority: 'secondary', variant: 'text' }
|
||||
},
|
||||
// Dropdown row action - additional options
|
||||
{
|
||||
label: 'More',
|
||||
icon: 'pi pi-ellipsis-v',
|
||||
action: (rowData) => showMoreOptions(rowData),
|
||||
rowAction: true,
|
||||
layout: { priority: 'dropdown', variant: 'icon-only' }
|
||||
}
|
||||
]
|
||||
|
||||
const exportAllClients = () => {
|
||||
// Export logic
|
||||
}
|
||||
|
||||
const archiveClients = (clients) => {
|
||||
// Archive logic
|
||||
}
|
||||
|
||||
const initiateContact = (client) => {
|
||||
// Contact logic
|
||||
}
|
||||
|
||||
const showMoreOptions = (client) => {
|
||||
// More options logic
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DataTable
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
:tableActions="tableActions"
|
||||
table-name="clients-with-layout"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Store Integration
|
||||
|
||||
The component integrates with a Pinia store (`useFiltersStore`) for persistent filter state:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue