dynamic_data_table 1.0.6 copy "dynamic_data_table: ^1.0.6" to clipboard
dynamic_data_table: ^1.0.6 copied to clipboard

A production-grade, highly customizable Flutter data table widget with sorting, filtering, pagination, row selection, and pluggable export formats. pub.dev ready.

example/lib/main.dart

// Example: Using Enhanced DynamicDataTable with All Features

import 'package:flutter/material.dart';
import 'package:data_table_2/data_table_2.dart';
import 'package:dynamic_data_table/dynamic_data_table.dart';

class Item {
  final String id;
  final String name;
  final double price;
  final int quantity;
  final DateTime createdAt;
  final String status;

  Item({
    required this.id,
    required this.name,
    required this.price,
    required this.quantity,
    required this.createdAt,
    required this.status,
  });
}

class DynamicTableExample extends StatefulWidget {
  const DynamicTableExample({super.key});

  @override
  State<DynamicTableExample> createState() => _DynamicTableExampleState();
}

class _DynamicTableExampleState extends State<DynamicTableExample> {
  late List<Item> items;
  TableLoadingState loadingState = TableLoadingState.idle;
  String? errorMessage;
  List<Item> selectedItems = [];
  Pagination? pagination;
  int currentPage = 1;

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  void _loadData() {
    setState(() => loadingState = TableLoadingState.loading);

    // Simulate network request
    Future.delayed(const Duration(seconds: 2), () {
      if (mounted) {
        setState(() {
          items = [
            Item(
              id: '1',
              name: 'Widget A',
              price: 99.99,
              quantity: 50,
              createdAt: DateTime.now().subtract(const Duration(days: 5)),
              status: 'Active',
            ),
            Item(
              id: '2',
              name: 'Widget B',
              price: 149.99,
              quantity: 30,
              createdAt: DateTime.now().subtract(const Duration(days: 10)),
              status: 'Inactive',
            ),
            Item(
              id: '3',
              name: 'Widget C',
              price: 199.99,
              quantity: 100,
              createdAt: DateTime.now(),
              status: 'Active',
            ),
          ];
          pagination = Pagination(
            page: 1,
            limit: 25,
            totalRows: 3,
            totalPages: 1,
          );
          loadingState = TableLoadingState.idle;
        });
      }
    });
  }

  void _handleError() {
    setState(() {
      loadingState = TableLoadingState.error;
      errorMessage = 'Failed to fetch items. Please try again.';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dynamic Table Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // Show selected count if any
            if (selectedItems.isNotEmpty)
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Theme.of(context).colorScheme.primaryContainer,
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      '${selectedItems.length} item(s) selected',
                      style: Theme.of(context).textTheme.bodyMedium,
                    ),
                    TextButton(
                      onPressed: () {
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(
                            content: Text(
                              'Selected: ${selectedItems.map((e) => e.name).join(", ")}',
                            ),
                          ),
                        );
                      },
                      child: const Text('Perform Action'),
                    ),
                  ],
                ),
              ),
            const SizedBox(height: 16),
            // Main data table with all features
            Expanded(
              child: DynamicDataTable<Item>(
                // Core data
                data: items,
                tableName: 'Products Inventory',
                columns: _buildColumns(),

                // New features
                enableRowSelection: true,
                onRowSelectionChanged: (selected) {
                  setState(() => selectedItems = selected);
                },

                // Loading & error states
                loadingState: loadingState,
                errorMessage: errorMessage,

                // Configuration
                config: TableConfig(
                  searchHint: 'Search by name or ID...',
                  filterLabel: 'Filter by Status',
                  exportLabel: 'Download Excel',
                  selectAllLabel: 'Select All Items',
                  applyLabel: 'Apply Filters',
                  cancelLabel: 'Cancel',
                  enableRowSelection: true,
                  enableLoadingState: true,
                  enableSortIndicators: true,
                  canExport: () {
                    // Check permission
                    return true; // Replace with actual permission check
                  },
                ),

                // Search & filter
                onSearch: (searchTerm) {
                  // Handle remote search if needed
                  debugPrint('Searching: $searchTerm');
                },
                searchStringBuilder: (item) => '${item.name} ${item.id}',

                // Pagination
                pagination: pagination,
                onPageChanged: (newPage, pageSize) {
                  setState(() => currentPage = newPage);
                  _loadData(); // Reload with new page
                },

                // Row tap
                onRowTap: (item, rowIndex) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Tapped: ${item.name}')),
                  );
                },

                // Empty state
                emptyState: () => Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Icon(
                        Icons.inbox_outlined,
                        size: 48,
                        color: Theme.of(context).colorScheme.outline,
                      ),
                      const SizedBox(height: 16),
                      Text(
                        'No items found',
                        style: Theme.of(context).textTheme.titleMedium,
                      ),
                    ],
                  ),
                ),

                // Date filter
                enableDateFilter: true,
                onDateFilterChanged: (dateFilter) {
                  // Handle date filter
                  debugPrint('Date filter: $dateFilter');
                },
              ),
            ),
            const SizedBox(height: 16),
            // Debug controls
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton.icon(
                  onPressed: _loadData,
                  icon: const Icon(Icons.refresh),
                  label: const Text('Reload'),
                ),
                ElevatedButton.icon(
                  onPressed: _handleError,
                  icon: const Icon(Icons.error),
                  label: const Text('Trigger Error'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  List<ColumnDef<Item>> _buildColumns() {
    return [
      ColumnDef<Item>(
        id: 'name',
        label: 'Product Name',
        sortable: true,
        exportable: true,
        filterable: true,
        cellBuilder: (item) => DataCell(Text(item.name)),
        filterValueBuilder: (item) => item.name,
        exportValueBuilder: (item) => item.name,
        size: ColumnSize.L,
        onSort: (idx, asc) =>
            debugPrint('Sort by name: ${asc ? "ASC" : "DESC"}'),
      ),
      ColumnDef<Item>(
        id: 'price',
        label: 'Price',
        sortable: true,
        exportable: true,
        cellBuilder: (item) => DataCell(
          Text('\$${item.price.toStringAsFixed(2)}'),
        ),
        exportValueBuilder: (item) => item.price.toStringAsFixed(2),
        size: ColumnSize.M,
        onSort: (idx, asc) =>
            debugPrint('Sort by price: ${asc ? "ASC" : "DESC"}'),
      ),
      ColumnDef<Item>(
        id: 'quantity',
        label: 'Quantity',
        sortable: true,
        exportable: true,
        cellBuilder: (item) => DataCell(Text('${item.quantity}')),
        exportValueBuilder: (item) => '${item.quantity}',
        size: ColumnSize.S,
        onSort: (idx, asc) =>
            debugPrint('Sort by quantity: ${asc ? "ASC" : "DESC"}'),
      ),
      ColumnDef<Item>(
        id: 'status',
        label: 'Status',
        sortable: true,
        exportable: true,
        filterable: true,
        cellBuilder: (item) => DataCell(
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            decoration: BoxDecoration(
              color: item.status == 'Active'
                  ? Colors.green.withValues(alpha: 0.2)
                  : Colors.red.withValues(alpha: 0.2),
              borderRadius: BorderRadius.circular(4),
            ),
            child: Text(
              item.status,
              style: TextStyle(
                color: item.status == 'Active' ? Colors.green : Colors.red,
                fontSize: 12,
              ),
            ),
          ),
        ),
        filterValueBuilder: (item) => item.status,
        exportValueBuilder: (item) => item.status,
        size: ColumnSize.M,
        onSort: (idx, asc) =>
            debugPrint('Sort by status: ${asc ? "ASC" : "DESC"}'),
      ),
      ColumnDef<Item>(
        id: 'createdAt',
        label: 'Created',
        sortable: true,
        exportable: true,
        cellBuilder: (item) => DataCell(
          Text(
            '${item.createdAt.year}-${item.createdAt.month.toString().padLeft(2, "0")}-${item.createdAt.day.toString().padLeft(2, "0")}',
            style: const TextStyle(fontSize: 12),
          ),
        ),
        exportValueBuilder: (item) =>
            '${item.createdAt.year}-${item.createdAt.month}-${item.createdAt.day}',
        size: ColumnSize.M,
        onSort: (idx, asc) =>
            debugPrint('Sort by createdAt: ${asc ? "ASC" : "DESC"}'),
      ),
    ];
  }
}

// Key Features Demonstrated:

// 1. ROW SELECTION
//    - enableRowSelection: true
//    - onRowSelectionChanged callback
//    - Selected items displayed in badge

// 2. LOADING STATE
//    - loadingState: TableLoadingState.loading
//    - Shows spinner overlay

// 3. ERROR STATE
//    - loadingState: TableLoadingState.error
//    - errorMessage displayed with icon

// 4. SORT INDICATORS
//    - Column.sortable = true
//    - Visual up/down arrows in header
//    - Click to toggle ascending/descending

// 5. SEARCH & FILTER
//    - searchStringBuilder for local search
//    - filterable columns with dropdown
//    - onSearch for remote search

// 6. CUSTOM CONFIG
//    - TableConfig for all strings
//    - canExport callback for permissions
//    - Feature flags (enableLoadingState, etc.)

// 7. PAGINATION
//    - pagination object with page info
//    - onPageChanged callback
//    - Previous/Next/Page selector

// 8. ROW ACTIONS
//    - onRowTap for row click handling
//    - Custom emptyState widget

// 9. DATE FILTER
//    - enableDateFilter: true
//    - onDateFilterChanged callback
//    - Calendar picker UI

// 10. COLUMN CUSTOMIZATION
//     - sortable, filterable, exportable flags
//     - Custom cell builders
//     - Filter/export value builders
//     - Total row support via totalCellBuilder
1
likes
0
points
263
downloads

Publisher

verified publishersubashkc.info.np

Weekly Downloads

A production-grade, highly customizable Flutter data table widget with sorting, filtering, pagination, row selection, and pluggable export formats. pub.dev ready.

Repository (GitHub)
View/report issues

Topics

#data-table #table #widget #flutter #data-grid

License

unknown (license)

Dependencies

data_table_2, file_saver, flutter, intl, open_file, path_provider, syncfusion_flutter_xlsio, web

More

Packages that depend on dynamic_data_table