0.0.1 โ€ข Published 1 year ago

@fivexlabs/ng-headless-datagrid v0.0.1

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

@fivexlabs/ng-headless-datagrid

npm version License: MIT TypeScript

๐Ÿ’ก Why ng-headless-datagrid?

๐Ÿšจ The Problem

Developers often find styling existing Angular UI libraries "tricky" and difficult because:

  • ๐ŸŽจ Styling Conflicts: Angular's component selector and view encapsulation interfere with global or utility-first CSS frameworks
  • ๐Ÿ”’ Design Lock-in: Default styles lock you into specific design aesthetics, hindering unique UI creation
  • ๐Ÿคผ Fighting Defaults: Must constantly override library styles instead of building from scratch
  • ๐Ÿšซ Limited Customization: Existing libraries don't provide the flexibility needed for complex, custom data grids
  • ๐Ÿงฉ Framework Friction: Difficult integration with modern CSS frameworks like Tailwind CSS

โœ… The Solution

ng-headless-datagrid eliminates these issues by providing:

  • ๐ŸŽฏ Complete Styling Freedom: No default UI components or styles - you control 100% of the markup and styling
  • ๐Ÿš€ Seamless Integration: Perfect compatibility with utility-first CSS frameworks like Tailwind CSS
  • โšก Core Logic Only: Provides sorting, filtering, pagination, selection, and virtualization logic without any UI constraints
  • ๐Ÿ›ก๏ธ Type Safety: Full TypeScript support with comprehensive type definitions
  • ๐Ÿ—๏ธ Flexible Architecture: Use with any Angular template structure - tables, divs, cards, or custom components

โœจ Features

๐ŸŽฏ Core Features

  • ๐Ÿ“Š Data Processing: Advanced sorting (single/multi-column), filtering (global/per-column), and pagination
  • ๐Ÿง  State Management: Centralized state service with Angular signals for reactive updates
  • ๐ŸŽ›๏ธ Selection Logic: Single and multi-row selection with full keyboard accessibility
  • โšก Virtualization: Built-in virtualization for efficiently rendering massive datasets
  • ๐Ÿ’พ State Persistence: Export/import grid state as JSON for bookmarkable URLs and user preferences
  • โ™ฟ Accessibility: Complete ARIA support and keyboard navigation patterns

๐Ÿ”ฅ Enhanced Features

  • ๐Ÿ”„ Real-time Updates: Reactive state management using Angular signals
  • ๐ŸŽจ Headless Design: Zero UI constraints - build any design you can imagine
  • ๐Ÿ“ฑ Responsive Ready: Works with any responsive design approach
  • ๐Ÿ” Advanced Filtering: Custom filter operators and functions per column
  • ๐Ÿ“ˆ Performance Optimized: Efficient algorithms for large datasets with minimal re-renders
  • ๐Ÿงช Testing Friendly: Easy to test with injectable services and pure logic

๐Ÿ”ง Advanced Features

NEW: 7 Powerful Advanced Features Added!

1. ๐Ÿ—๏ธ Advanced Column Management

  • Dynamic column operations (add, remove, reorder, resize)
  • Column locking (freeze left/right) and grouping
  • Auto-sizing and responsive column visibility

2. ๐Ÿ” Smart Filtering System

  • Advanced operators (contains, between, regex, etc.)
  • Global search and filter presets
  • Real-time filter suggestions with AND/OR logic

3. โšก Intelligent Virtualization

  • Variable height rows and horizontal virtualization
  • Predictive loading for 100k+ rows
  • Performance-optimized scrolling

4. ๐Ÿ”Œ Data Source Adapters

  • Remote HTTP data with intelligent caching
  • WebSocket real-time updates
  • Infinite scrolling with progressive loading

5. ๐Ÿ“ค Export & Import System

  • Multiple formats (CSV, Excel, PDF, JSON, XML)
  • Import validation and error reporting
  • Custom export processors

6. ๐Ÿ“ฑ Mobile-First Features

  • Touch gestures (swipe actions, pinch-to-zoom)
  • Responsive column management
  • Mobile-optimized pagination

7. ๐Ÿ”’ Data Security Features

  • Field-level permissions and role-based access
  • Data masking for sensitive information
  • Comprehensive audit logging

Legacy Features:

  • ๐Ÿ”„ Batch Operations: Support for batch editing and operations on multiple rows
  • ๐ŸŽฏ Custom Accessors: Flexible data access with custom accessor functions
  • ๐Ÿ” Debug Tools: Built-in debugging utilities for development
  • โš™๏ธ Configurable: Extensive configuration options for every aspect of grid behavior

๐Ÿ“ฆ Installation

npm install @fivexlabs/ng-headless-datagrid
# or
yarn add @fivexlabs/ng-headless-datagrid

Note: This library requires Angular 19+ and works best with modern CSS frameworks like Tailwind CSS.

๐Ÿš€ Advanced Features Quick Start

import { 
  ColumnManagementService, 
  SmartFilteringService, 
  ExportImportService,
  MobileTouchService, 
  SecurityService 
} from '@fivexlabs/ng-headless-datagrid';

@Component({
  providers: [
    ColumnManagementService,
    SmartFilteringService, 
    ExportImportService,
    MobileTouchService,
    SecurityService
  ]
})
export class AdvancedGridComponent {
  columnService = inject(ColumnManagementService);
  filterService = inject(SmartFilteringService);
  exportService = inject(ExportImportService);
  mobileService = inject(MobileTouchService);
  securityService = inject(SecurityService);

  ngOnInit() {
    // Advanced column management
    this.columnService.lockColumn('name', 'left');
    this.columnService.addSwipeAction({
      id: 'edit',
      direction: 'right',
      action: (row) => this.editRow(row)
    });

    // Smart filtering with presets
    this.filterService.addFilter({
      columnId: 'salary',
      operator: 'between',
      value: 50000,
      value2: 100000
    });

    // Export data in multiple formats
    this.exportService.export(this.data, {
      format: 'excel',
      filename: 'report.xlsx'
    });

    // Security with field-level permissions
    this.securityService.initialize({
      fieldPermissions: [{
        columnId: 'salary',
        roles: ['manager'],
        permissions: ['read', 'export']
      }]
    });
  }
}

๐Ÿ“– See Advanced Features Documentation for complete guides and examples.

๐Ÿš€ Quick Start

Basic Usage

Transform your data into a fully functional grid with complete styling control:

import { Component } from '@angular/core';
import { NgGridDirective } from '@fivexlabs/ng-headless-datagrid';

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
  createdAt: Date;
}

@Component({
  selector: 'app-user-table',
  standalone: true,
  imports: [NgGridDirective],
  template: `
    <div *ngGrid="let grid of users; columns: columnDefs; options: gridOptions">
      <!-- Your custom table markup with full styling control -->
      <table class="w-full text-sm text-left text-gray-500">
        <thead class="text-xs text-gray-700 uppercase bg-gray-50">
          <tr>
            <th *ngFor="let col of grid.columns"
                scope="col"
                class="px-6 py-3 cursor-pointer hover:bg-gray-100"
                (click)="grid.sortBy(col.id)">
              {{ col.header }}
              
              <!-- Custom sort indicator -->
              <span class="ml-1">
                <ng-container [ngSwitch]="grid.getSortDirection(col.id)">
                  <span *ngSwitchCase="'asc'" class="text-blue-500">โ†‘</span>
                  <span *ngSwitchCase="'desc'" class="text-blue-500">โ†“</span>
                  <span *ngSwitchDefault class="text-gray-300">โ†•</span>
                </ng-container>
              </span>
            </th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let row of grid.rows" 
              class="bg-white border-b hover:bg-gray-50"
              [class.bg-blue-50]="row.selected">
            <td *ngFor="let col of grid.columns" class="px-6 py-4">
              {{ getValue(row.data, col) }}
            </td>
          </tr>
        </tbody>
      </table>

      <!-- Custom pagination with your styling -->
      <div class="flex items-center justify-between mt-4">
        <div class="text-sm text-gray-700">
          Showing {{ (grid.pagination.currentPage - 1) * grid.pagination.pageSize + 1 }} 
          to {{ Math.min(grid.pagination.currentPage * grid.pagination.pageSize, grid.pagination.totalItems) }} 
          of {{ grid.pagination.totalItems }} results
        </div>
        
        <div class="flex space-x-1">
          <button (click)="grid.setPage(grid.pagination.currentPage - 1)"
                  [disabled]="grid.pagination.currentPage === 1"
                  class="px-3 py-1 text-sm bg-white border rounded hover:bg-gray-50 disabled:opacity-50">
            Previous
          </button>
          
          <button *ngFor="let page of getPageNumbers(grid.pagination)"
                  (click)="grid.setPage(page)"
                  [class.bg-blue-500]="page === grid.pagination.currentPage"
                  [class.text-white]="page === grid.pagination.currentPage"
                  class="px-3 py-1 text-sm bg-white border rounded hover:bg-gray-50">
            {{ page }}
          </button>
          
          <button (click)="grid.setPage(grid.pagination.currentPage + 1)"
                  [disabled]="grid.pagination.currentPage === grid.pagination.totalPages"
                  class="px-3 py-1 text-sm bg-white border rounded hover:bg-gray-50 disabled:opacity-50">
            Next
          </button>
        </div>
      </div>
    </div>
  `
})
export class UserTableComponent {
  users: User[] = [
    { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', createdAt: new Date() },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', createdAt: new Date() },
    // ... more users
  ];

  columnDefs = [
    { id: 'name', header: 'Full Name', sortable: true, filterable: true },
    { id: 'email', header: 'Email Address', sortable: true, filterable: true },
    { id: 'role', header: 'Role', sortable: true },
    { 
      id: 'createdAt', 
      header: 'Created', 
      sortable: true,
      formatter: (value: Date) => value.toLocaleDateString()
    }
  ];

  gridOptions = {
    enableSorting: true,
    enableFiltering: true,
    enablePagination: true,
    pageSize: 10,
    multiSort: false
  };

  getValue(data: User, column: any): any {
    const value = data[column.id as keyof User];
    return column.formatter ? column.formatter(value, data) : value;
  }

  getPageNumbers(pagination: any): number[] {
    // Custom pagination logic
    const pages = [];
    for (let i = 1; i <= pagination.totalPages; i++) {
      pages.push(i);
    }
    return pages;
  }
}

๐Ÿ”ฅ Enhanced Features

๐ŸŽ›๏ธ Advanced Filtering

Create powerful filtering interfaces with complete control:

@Component({
  template: `
    <div *ngGrid="let grid of data; columns: columns; options: options">
      <!-- Custom filter controls -->
      <div class="mb-4 grid grid-cols-3 gap-4">
        <div *ngFor="let col of grid.columns">
          <label class="block text-sm font-medium text-gray-700">
            {{ col.header }}
          </label>
          <input type="text"
                 [value]="grid.getFilterValue(col.id)"
                 (input)="grid.setFilter(col.id, $event.target.value)"
                 class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"
                 [placeholder]="'Filter ' + col.header">
        </div>
      </div>
      
      <!-- Your grid markup here -->
    </div>
  `
})
export class AdvancedFilteringComponent {
  options = {
    enableFiltering: true,
    debounceMs: 300, // Debounce filter input
  };
}

๐ŸŽฏ Selection Management

Implement complex selection patterns:

@Component({
  template: `
    <div *ngGrid="let grid of data; columns: columns; options: selectionOptions">
      <table class="w-full">
        <thead>
          <tr>
            <!-- Select all checkbox -->
            <th class="w-12">
              <input type="checkbox"
                     [checked]="grid.state.selection.selectAll"
                     [indeterminate]="grid.state.selection.indeterminate"
                     (change)="grid.selectAllRows($event.target.checked)"
                     class="rounded border-gray-300">
            </th>
            <th *ngFor="let col of grid.columns">{{ col.header }}</th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let row of grid.rows" 
              [class.bg-blue-50]="row.selected">
            <!-- Row selection checkbox -->
            <td>
              <input type="checkbox"
                     [checked]="row.selected"
                     (change)="grid.selectRow(row.id, $event.target.checked)"
                     class="rounded border-gray-300">
            </td>
            <td *ngFor="let col of grid.columns">
              {{ getValue(row.data, col) }}
            </td>
          </tr>
        </tbody>
      </table>
      
      <!-- Selection summary -->
      <div class="mt-4 text-sm text-gray-600">
        {{ grid.state.selection.selectedIds.length }} of {{ grid.rows.length }} items selected
      </div>
    </div>
  `
})
export class SelectableGridComponent {
  selectionOptions = {
    enableSelection: true,
    selectionMode: 'multiple' as const
  };
}

โšก Virtualization for Large Datasets

Handle thousands of rows efficiently:

import { VirtualizationService } from '@fivexlabs/ng-headless-datagrid';

@Component({
  template: `
    <div *ngGrid="let grid of largeDataset; columns: columns; options: virtualOptions">
      <div class="virtual-container"
           [style.height.px]="400"
           (scroll)="onScroll($event)">
        <div class="virtual-content" [style.height.px]="totalHeight">
          <div class="virtual-items" [style.transform]="'translateY(' + offsetY + 'px)'">
            <div *ngFor="let row of visibleRows; trackBy: trackByRowId"
                 class="virtual-row h-10 flex items-center border-b">
              <div *ngFor="let col of grid.columns" class="flex-1 px-4">
                {{ getValue(row.data, col) }}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  `,
  providers: [VirtualizationService]
})
export class VirtualizedGridComponent {
  largeDataset = Array.from({ length: 100000 }, (_, i) => ({
    id: i,
    name: `Item ${i}`,
    value: Math.random() * 1000
  }));

  virtualOptions = {
    enableVirtualization: true,
    virtualItemHeight: 40,
    virtualOverscan: 5
  };

  constructor(private virtualizationService: VirtualizationService) {}

  onScroll(event: Event) {
    const target = event.target as HTMLElement;
    this.virtualizationService.handleScroll(target.scrollTop);
  }

  get visibleRows() {
    return this.virtualizationService.getVisibleItems(this.grid.rows);
  }

  get totalHeight() {
    return this.virtualizationService.state().totalHeight;
  }

  get offsetY() {
    return this.virtualizationService.state().offsetY;
  }

  trackByRowId(index: number, row: any) {
    return row.id;
  }
}

๐Ÿ’พ State Persistence

Save and restore grid state:

@Component({
  template: `
    <div *ngGrid="let grid of data; columns: columns; options: persistentOptions">
      <!-- State management controls -->
      <div class="mb-4 flex space-x-2">
        <button (click)="saveState(grid)" 
                class="px-4 py-2 bg-blue-500 text-white rounded">
          Save State
        </button>
        <button (click)="loadState(grid)" 
                class="px-4 py-2 bg-green-500 text-white rounded">
          Load State
        </button>
        <button (click)="resetState(grid)" 
                class="px-4 py-2 bg-gray-500 text-white rounded">
          Reset
        </button>
      </div>
      
      <!-- Grid content -->
    </div>
  `
})
export class PersistentGridComponent {
  persistentOptions = {
    persistState: true,
    stateKey: 'my-grid-state'
  };

  saveState(grid: any) {
    const state = grid.exportState();
    localStorage.setItem('manual-grid-state', state);
    console.log('State saved:', state);
  }

  loadState(grid: any) {
    const state = localStorage.getItem('manual-grid-state');
    if (state) {
      grid.importState(state);
    }
  }

  resetState(grid: any) {
    localStorage.removeItem('manual-grid-state');
    window.location.reload();
  }
}

๐ŸŽจ Utility Directives

Use helper directives for common patterns:

import { 
  HdSortableDirective, 
  HdSelectableDirective, 
  HdFilterableDirective,
  HdPaginationDirective
} from '@fivexlabs/ng-headless-datagrid';

@Component({
  imports: [
    NgGridDirective,
    HdSortableDirective,
    HdSelectableDirective,
    HdFilterableDirective,
    HdPaginationDirective
  ],
  template: `
    <div *ngGrid="let grid of data; columns: columns; options: options">
      <table>
        <thead>
          <tr>
            <th *ngFor="let col of grid.columns"
                [hdSortable]="col.id"
                class="cursor-pointer hover:bg-gray-100">
              {{ col.header }}
              <!-- Sorting handled automatically with accessibility -->
            </th>
          </tr>
          <tr>
            <th *ngFor="let col of grid.columns">
              <input [hdFilterable]="col.id"
                     hdFilterOperator="contains"
                     hdFilterDebounce="500"
                     class="w-full p-1 border rounded">
              <!-- Filtering handled automatically -->
            </th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let row of grid.rows">
            <td [hdSelectable]="row.id" class="cursor-pointer">
              <!-- Row selection handled automatically -->
              {{ row.data.name }}
            </td>
          </tr>
        </tbody>
      </table>
      
      <!-- Pagination with helper directives -->
      <div class="flex space-x-2">
        <button hdPagination="first">First</button>
        <button hdPagination="prev">Previous</button>
        <button hdPagination="next">Next</button>
        <button hdPagination="last">Last</button>
      </div>
    </div>
  `
})
export class DirectiveExampleComponent {
  // Component implementation
}

๐Ÿ“š Complete API Reference

Core Interfaces

InterfaceDescription
GridColumn<T>Column definition with sorting, filtering, and formatting options
GridRow<T>Row wrapper with selection and expansion state
GridState<T>Complete grid state including data, sorting, filtering, pagination
GridOptions<T>Configuration options for grid behavior
GridContext<T>Template context exposed by the ngGrid directive

Services

ServiceKey MethodsDescription
GridStateService<T>sortBy(), setFilter(), setPage(), selectRow()Core state management service
VirtualizationService<T>handleScroll(), getVisibleItems()Virtualization for large datasets

Directives

DirectiveSelectorDescription
NgGridDirective[ngGrid]Main structural directive providing grid context
HdSortableDirective[hdSortable]Makes elements sortable with accessibility
HdSelectableDirective[hdSelectable]Makes rows selectable with keyboard support
HdFilterableDirective[hdFilterable]Adds filtering to input elements
HdPaginationDirective[hdPagination]Pagination button functionality

Grid Options

OptionTypeDefaultDescription
enableSortingbooleantrueEnable/disable sorting functionality
enableFilteringbooleantrueEnable/disable filtering functionality
enablePaginationbooleantrueEnable/disable pagination
enableSelectionbooleanfalseEnable/disable row selection
selectionMode'single' \| 'multiple' \| 'none''none'Row selection mode
multiSortbooleanfalseAllow sorting by multiple columns
pageSizenumber10Number of items per page
persistStatebooleanfalseAuto-save state to localStorage
debounceMsnumber300Debounce time for filter inputs

๐Ÿงช Testing

npm test

The library includes comprehensive testing utilities and examples for testing headless grid implementations.

๐Ÿ“– Examples

Check out the /examples directory for complete implementations showing:

  • Basic table with Tailwind CSS
  • Advanced filtering and sorting
  • Virtualized grids for large datasets
  • Selection and batch operations
  • State persistence and URL synchronization
  • Integration with Angular Material
  • Custom cell renderers and formatters

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿข About Fivex Labs

Fivex Labs is a technology company focused on building innovative tools and libraries for modern web development. We believe in creating solutions that are both powerful and developer-friendly.

Other Libraries by Fivex Labs

Visit us at fivexlabs.com to learn more about our work and other open-source projects.