Teren-app/resources/js/Components/DataTable
2025-11-23 21:33:01 +01:00
..
ActionMenuItem.vue Dev branch 2025-11-02 12:31:01 +01:00
ColumnFilter.vue Dev branch 2025-11-02 12:31:01 +01:00
columns-example.js Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTable.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTableClient.vue Dev branch 2025-11-02 12:31:01 +01:00
DataTableColumnHeader.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTableNew.vue Dashboard final version, TODO: update main sidebar menu 2025-11-23 21:33:01 +01:00
DataTableNew2.vue Dashboard final version, TODO: update main sidebar menu 2025-11-23 21:33:01 +01:00
DataTableOld.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTablePagination.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTableServer.vue Merge branch 'master' into Development 2025-11-20 18:53:49 +01:00
DataTableToolbar.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTableToolbarExample.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
DataTableViewOptions.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
MIGRATION.md Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
README.md Changes to UI and other stuff 2025-11-20 18:11:43 +01:00
StatusBadge.vue Dev branch 2025-11-02 12:31:01 +01:00
TableActions.vue Changes to UI and other stuff 2025-11-20 18:11:43 +01:00

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

<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)

<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

<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

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

<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

<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

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:

<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:

<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

<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

<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)

<DataTable
  :rows="clients.data"
  :columns="columns"
  :meta="clients.meta"
/>

After (New API)

<DataTableNew2
  :data="clients.data"
  :columns="columns"
  :meta="clients.meta"
  route-name="clients.index"
/>

Main changes:

  • rowsdata
  • 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