13 KiB

DataTable Component Documentation

Overview

A feature-rich data table component built with PrimeVue's DataTable. This component provides advanced functionality including server-side pagination, sorting, manual filtering with apply buttons, row selection, page data caching, and customizable column types with persistent state management.

Basic Usage

<template>
  <DataTable
    :columns="tableColumns"
    :data="tableData"
    table-name="my-table"
    @row-click="handleRowClick"
  />
</template>

<script setup>
import { ref } from "vue";
import DataTable from "./components/common/DataTable.vue";

const tableColumns = ref([
  {
    fieldName: "name",
    label: "Name",
    sortable: true,
    filterable: true,
  },
  {
    fieldName: "status",
    label: "Status",
    type: "status",
    sortable: true,
    filterable: true,
  },
]);

const tableData = ref([
  { id: 1, name: "John Doe", status: "completed" },
  { id: 2, name: "Jane Smith", status: "in progress" },
]);

const handleRowClick = (event) => {
  console.log("Row clicked:", event.data);
};
</script>

Props

columns (Array) - Required

  • Description: Array of column configuration objects that define the table structure
  • Type: Array<Object>
  • Required: true

data (Array) - Required

  • Description: Array of data objects to display in the table
  • Type: Array<Object>
  • Required: true

tableName (String) - Required

  • Description: Unique identifier for the table, used for persistent filter state management
  • Type: String
  • Required: true

totalRecords (Number)

  • Description: Total number of records available on the server (for lazy loading)
  • Type: Number
  • Default: 0

onLazyLoad (Function)

  • Description: Custom pagination event handler for server-side data loading
  • Type: Function
  • Default: null

filters (Object)

  • Description: Initial filter configuration object (used for non-lazy tables)
  • Type: Object
  • Default: { global: { value: null, matchMode: FilterMatchMode.CONTAINS } }

Server-Side Pagination & Lazy Loading

When lazy is set to true, the DataTable operates in server-side mode with the following features:

Automatic Caching

  • Page Data Caching: Previously loaded pages are cached to prevent unnecessary API calls
  • Cache Duration: 5 minutes default expiration time
  • Cache Size: Maximum 50 pages per table with automatic cleanup
  • Smart Cache Keys: Based on page, sorting, and filter combinations

Manual Filter Controls

  • Apply Button: Filters are applied manually via button click to prevent excessive API calls
  • Clear Button: Quick reset of all active filters
  • Enter Key Support: Apply filters by pressing Enter in any filter field
  • Visual Feedback: Shows active filters and pending changes

Quick Page Navigation

  • Page Dropdown: Jump directly to any page number
  • Page Info Display: Shows current record range and totals
  • Persistent State: Page selection survives component re-mounts

Column Configuration

Each column object in the columns array supports the following properties:

Basic Properties

  • fieldName (String, required) - The field name in the data object
  • label (String, required) - Display label for the column header
  • sortable (Boolean, default: false) - Enables sorting for this column
  • filterable (Boolean, default: false) - Enables row-level filtering for this column

Column Types

  • type (String) - Defines special rendering behavior for the column

Available Types:

'status' Type

Renders values as colored tags/badges:

{
  fieldName: 'status',
  label: 'Status',
  type: 'status',
  sortable: true,
  filterable: true
}

Status Colors:

  • 'completed' → Success (green)
  • 'in progress' → Warning (yellow/orange)
  • 'not started' → Danger (red)
  • Other values → Info (blue)
'button' Type

Renders values as clickable buttons:

{
  fieldName: 'action',
  label: 'Action',
  type: 'button'
}

Events

rowClick

  • Description: Emitted when a button-type column is clicked
  • Payload: PrimeVue slot properties object containing row data
  • Usage: @row-click="handleRowClick"

lazy-load

  • Description: Emitted when lazy loading is triggered (pagination, sorting, filtering)
  • Payload: Event object with page, sorting, and filter information
  • Usage: @lazy-load="handleLazyLoad"

page-change

  • Description: Emitted when page changes
  • Payload: PrimeVue page event object

sort-change

  • Description: Emitted when sorting changes
  • Payload: PrimeVue sort event object

filter-change

  • Description: Emitted when filters are applied
  • Payload: PrimeVue filter event object
const handleRowClick = (slotProps) => {
  console.log("Clicked row data:", slotProps.data);
  console.log("Row index:", slotProps.index);
};

const handleLazyLoad = async (event) => {
  // event contains: page, rows, sortField, sortOrder, filters
  console.log("Lazy load event:", event);

  // Load data from API based on event parameters
  const result = await Api.getData({
    page: event.page,
    pageSize: event.rows,
    sortField: event.sortField,
    sortOrder: event.sortOrder,
    filters: event.filters,
  });

  // Update component data
  tableData.value = result.data;
  totalRecords.value = result.totalRecords;
};

Features

Pagination

  • Rows per page options: 5, 10, 20, 50
  • Default rows per page: 10
  • Built-in pagination controls

Sorting

  • Multiple column sorting support
  • Removable sort - click to remove sort from a column
  • Sort indicators in column headers

Filtering

  • Manual filter application with Apply/Clear buttons
  • Text-based search for filterable columns
  • Persistent filter state across component re-renders and page navigation
  • Visual filter feedback showing active filters and pending changes
  • Enter key support for quick filter application

Selection

  • Multiple row selection with checkboxes
  • Meta key selection (Ctrl/Cmd + click for individual selection)
  • Unique row identification using dataKey="id"

Scrolling

  • Vertical scrolling with fixed height (70vh)
  • Horizontal scrolling for wide tables
  • Fixed headers during scroll

State Management

  • Persistent filters using Pinia store (useFiltersStore)
  • Automatic filter initialization on component mount
  • Cross-component filter synchronization

Usage Examples

<script setup>
import { ref } from "vue";
import DataTable from "./components/common/DataTable.vue";
import Api from "./api.js";

const columns = [
  { fieldName: "id", label: "ID", sortable: true },
  { fieldName: "name", label: "Name", sortable: true, filterable: true },
  { fieldName: "email", label: "Email", filterable: true },
];

const tableData = ref([]);
const totalRecords = ref(0);
const isLoading = ref(false);

const handleLazyLoad = async (event) => {
  try {
    isLoading.value = true;

    // Convert PrimeVue event to API parameters
    const params = {
      page: event.page,
      pageSize: event.rows,
      sortField: event.sortField,
      sortOrder: event.sortOrder,
    };

    // Convert filters
    const filters = {};
    if (event.filters) {
      Object.keys(event.filters).forEach((key) => {
        if (event.filters[key]?.value) {
          filters[key] = event.filters[key];
        }
      });
    }

    // API call with caching support
    const result = await Api.getPaginatedData(params, filters);

    tableData.value = result.data;
    totalRecords.value = result.totalRecords;
  } catch (error) {
    console.error("Error loading data:", error);
    tableData.value = [];
    totalRecords.value = 0;
  } finally {
    isLoading.value = false;
  }
};
</script>

<template>
  <DataTable
    :data="tableData"
    :columns="columns"
    tableName="myTable"
    :lazy="true"
    :totalRecords="totalRecords"
    :loading="isLoading"
    :onLazyLoad="handleLazyLoad"
    @lazy-load="handleLazyLoad"
  />
</template>

Basic Client-Side Table

<script setup>
const columns = [
  { fieldName: "id", label: "ID", sortable: true },
  { fieldName: "name", label: "Name", sortable: true, filterable: true },
  { fieldName: "email", label: "Email", filterable: true },
];

const data = [
  { id: 1, name: "John Doe", email: "john@example.com" },
  { id: 2, name: "Jane Smith", email: "jane@example.com" },
];
</script>

<template>
  <DataTable :data="data" :columns="columns" tableName="basicTable" />
</template>

Status Table

<script setup>
const columns = [
  { fieldName: "task", label: "Task", sortable: true, filterable: true },
  {
    fieldName: "status",
    label: "Status",
    type: "status",
    sortable: true,
    filterable: true,
  },
  { fieldName: "assignee", label: "Assignee", filterable: true },
];

const data = [
  { id: 1, task: "Setup project", status: "completed", assignee: "John" },
  { id: 2, task: "Write tests", status: "in progress", assignee: "Jane" },
  { id: 3, task: "Deploy app", status: "not started", assignee: "Bob" },
];
</script>

<template>
  <DataTable :columns="columns" :data="data" table-name="tasks-table" />
</template>

Interactive Table with Buttons

<script setup>
const columns = [
  { fieldName: "name", label: "Name", sortable: true, filterable: true },
  { fieldName: "status", label: "Status", type: "status", sortable: true },
  { fieldName: "action", label: "Action", type: "button" },
];

const data = [
  { id: 1, name: "Project A", status: "completed", action: "View Details" },
  { id: 2, name: "Project B", status: "in progress", action: "Edit" },
];

const handleRowClick = (slotProps) => {
  const { data, index } = slotProps;
  console.log(`Action clicked for ${data.name} at row ${index}`);
  // Handle the action (navigate, open modal, etc.)
};
</script>

<template>
  <DataTable
    :columns="columns"
    :data="data"
    table-name="projects-table"
    @row-click="handleRowClick"
  />
</template>

Custom Filters

<script setup>
import { FilterMatchMode } from "@primevue/core";

const customFilters = {
  global: { value: null, matchMode: FilterMatchMode.CONTAINS },
  name: { value: "John", matchMode: FilterMatchMode.STARTS_WITH },
};
</script>

<template>
  <DataTable
    :columns="columns"
    :data="data"
    :filters="customFilters"
    table-name="filtered-table"
  />
</template>

Store Integration

The component integrates with a Pinia store (useFiltersStore) for persistent filter state:

Store Methods Used

  • initializeTableFilters(tableName, columns) - Initialize filters for a table
  • getTableFilters(tableName) - Get current filters for a table
  • updateTableFilter(tableName, fieldName, value, matchMode) - Update a specific filter

Filter Persistence

  • Filters are automatically saved when changed
  • Filters persist across component re-mounts
  • Each table maintains separate filter state based on tableName

Styling

The component uses PrimeVue's default DataTable styling with:

  • Scrollable layout with fixed 70vh height
  • Responsive design that adapts to container width
  • Consistent spacing and typography
  • Accessible color schemes for status badges

Performance Considerations

Large Datasets

  • Virtual scrolling is not implemented - consider for datasets > 1000 rows
  • Client-side pagination may impact performance with very large datasets
  • Debounced filtering helps with real-time search performance

Memory Management

  • Filter state persistence may accumulate over time
  • Consider implementing filter cleanup for unused tables
  • Component re-rendering is optimized through computed properties

Best Practices

  1. Use unique tableName for each table instance to avoid filter conflicts
  2. Define clear column labels for better user experience
  3. Enable sorting and filtering on searchable/comparable columns
  4. Use appropriate column types (status, button) for better UX
  5. Handle rowClick events for interactive functionality
  6. Consider data structure - ensure id field exists for selection
  7. Test with various data sizes to ensure performance
  8. Use consistent status values for proper badge coloring

Accessibility

The component includes:

  • Keyboard navigation support via PrimeVue
  • Screen reader compatibility with proper ARIA labels
  • High contrast status badges for visibility
  • Focus management for interactive elements
  • Semantic HTML structure for assistive technologies

Browser Support

Compatible with all modern browsers that support:

  • Vue 3 Composition API
  • ES6+ features
  • CSS Grid and Flexbox
  • PrimeVue components

Dependencies

  • Vue 3 with Composition API
  • PrimeVue DataTable, Column, Tag, Button, InputText components
  • @primevue/core for FilterMatchMode
  • Pinia store for state management (useFiltersStore)