@ng-vui/ng-vui-grid

A powerful, feature-rich Angular 20+ data grid component with advanced template support, action columns, sorting, filtering, pagination, virtual scrolling, and export capabilities. Built with standalone components and modern Angular architecture.

๐Ÿš€Features

๐Ÿ“ฆInstallation

npm install @ng-vui/ng-vui-grid

Peer Dependencies:

๐Ÿ—๏ธArchitecture

Built with modern Angular patterns:

Standalone Components

No NgModules required

Signal-based State

Reactive state management

Feature Modules

Modular filtering, editing, export capabilities

Service Architecture

Dedicated services for different concerns

Type Safety

Full TypeScript interfaces and types

๐ŸŽฏBasic Usage

Template-Based Approach (Recommended)

import {
  NgVuiGridComponent,
  NgVuiGridColumnDirective,
  GridOptions,
  DEFAULT_GRID_OPTIONS
} from '@ng-vui/ng-vui-grid';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [NgVuiGridComponent, NgVuiGridColumnDirective],
  template: `
    <ng-vui-grid
      [rowData]="data"
      [gridOptions]="gridOptions"
      (gridReady)="onGridReady($event)"
    >
      <!-- Regular column -->
      <ng-template ngVuiGridColumn="name" headerName="Full Name" [width]="200" let-value>
        <span class="font-medium">{{ value }}</span>
      </ng-template>

      <!-- Action column -->
      <ng-template ngVuiGridColumn="actions" headerName="Actions" [width]="150" [sortable]="false" let-row="row">
        <button (click)="edit(row)" class="btn btn-sm btn-primary mr-2">Edit</button>
        <button (click)="delete(row)" class="btn btn-sm btn-danger">Delete</button>
      </ng-template>
    </ng-vui-grid>
  `
})
export class ExampleComponent {
  data = [
    { id: 1, name: 'John Doe', email: 'john@example.com', status: 'Active' },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'Inactive' }
  ];

  gridOptions: GridOptions = {
    ...DEFAULT_GRID_OPTIONS,
    pagination: true,
    paginationPageSize: 20,
    enableSorting: true,
    enableFiltering: true,
    enableSelection: true,
    header: {
      showTitle: true,
      title: 'User Management',
      showControls: true,
      showColumnChooser: true,
      showExport: true
    }
  };

  onGridReady(event: GridReadyEvent) {
    console.log('Grid is ready:', event);
  }

  edit(row: any) {
    console.log('Edit:', row);
  }

  delete(row: any) {
    console.log('Delete:', row);
  }
}

Programmatic Approach

import { NgGridComponent, ColumnDefinition } from '@ertpl-ui/ang-grid';

@Component({
  template: `
    <ng-grid
      [columnDefs]="columns"
      [rowData]="data"
      [gridOptions]="gridOptions"
    ></ng-grid>
  `
})
export class ProgrammaticExample {
  columns: ColumnDefinition[] = [
    { field: 'name', headerName: 'Full Name', width: 200, sortable: true },
    { field: 'email', headerName: 'Email', width: 250, filterable: true },
    { field: 'status', headerName: 'Status', width: 120 }
  ];

  data = [...]; // Your data array
  gridOptions = {...}; // Your grid options
}

๐ŸŽจTemplate Context

Templates receive the following context variables:

interface TemplateContext {
  $implicit: any;        // The cell value
  value: any;            // The cell value (same as $implicit)
  row: RowData;          // The entire row data
  column: ColumnDefinition; // Column definition
  rowIndex: number;      // Row index
}

Usage in Templates

<ng-template ngVuiGridColumn="user" headerName="User Info" let-value let-row="row" let-rowIndex="rowIndex">
  <div class="flex items-center">
    <img [src]="row.avatar" class="w-8 h-8 rounded-full mr-3">
    <div>
      <div class="font-medium">{{ value }}</div>
      <div class="text-sm text-gray-500">Row #{{ rowIndex + 1 }}</div>
    </div>
  </div>
</ng-template>

๐Ÿ”งAPI Reference

NgGridComponent

Inputs

Property Type Default Description
rowData RowData[] [] Array of data objects
columnDefs ColumnDefinition[] [] Column definitions (programmatic)
gridOptions GridOptions {} Grid configuration options
loading boolean false Show loading indicator
loadingTemplate TemplateRef - Custom loading template
noDataTemplate TemplateRef - Custom no data template

Outputs

Event Type Description
gridReady GridReadyEvent Fired when grid is initialized
cellClicked CellClickedEvent Fired when cell is clicked
rowSelected RowSelectedEvent Fired when row selection changes
sortChanged SortEvent[] Fired when sorting changes
filterChanged FilterEvent Fired when filtering changes

ColumnDefinition

interface ColumnDefinition {
  field: string;                    // Data field name
  headerName?: string;              // Column header text
  width?: number;                   // Fixed width in pixels
  minWidth?: number;                // Minimum width
  maxWidth?: number;                // Maximum width
  sortable?: boolean;               // Enable sorting
  filterable?: boolean;             // Enable filtering
  resizable?: boolean;              // Allow column resizing
  visible?: boolean;                // Show/hide column
  pinned?: 'left' | 'right';       // Pin column to left/right
  cellTemplate?: TemplateRef<any>;  // Custom cell template
  headerTemplate?: TemplateRef<any>; // Custom header template
  valueFormatter?: (params: any) => string; // Format cell value
  cellClass?: string | string[];    // CSS classes for cell
  headerClass?: string | string[];  // CSS classes for header
}

GridOptions

interface GridOptions {
  // Pagination
  pagination?: boolean;             // Enable pagination
  paginationPageSize?: number;      // Rows per page
  paginationPageSizes?: number[];   // Available page sizes

  // Sorting & Filtering
  enableSorting?: boolean;          // Enable sorting
  enableFiltering?: boolean;        // Enable filtering
  multiSort?: boolean;              // Allow multi-column sorting

  // Selection
  enableSelection?: boolean;        // Enable row selection
  selectionMode?: 'single' | 'multiple'; // Selection mode
  showSelectionCheckbox?: boolean;  // Show selection checkboxes

  // Virtual Scrolling
  virtualScrolling?: boolean;       // Enable virtual scrolling
  rowHeight?: number;               // Fixed row height

  // Header Options
  header?: {
    showTitle?: boolean;            // Show grid title
    title?: string;                 // Grid title text
    showControls?: boolean;         // Show header controls
    exportControls?: {              // Export options
      enabled?: boolean;
      showCsv?: boolean;
      showExcel?: boolean;
      showPdf?: boolean;
    };
    columnControls?: {              // Column options
      enabled?: boolean;
      showColumnSelector?: boolean;
    };
  };

  // Styling
  cssClasses?: {
    root?: string;                  // Grid container classes
    header?: string;                // Header classes
    body?: string;                  // Body classes
    row?: string;                   // Row classes
    cell?: string;                  // Cell classes
  };
}

๐ŸŽฏAdvanced Examples

Action Column with Dropdown

<ng-template ngVuiGridColumn="actions" headerName="Actions" [sortable]="false" let-row="row" let-rowIndex="rowIndex">
  <div class="relative">
    <button (click)="toggleMenu(rowIndex)" class="btn btn-sm">
      <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5v.01M12 12v.01M12 19v.01"/>
      </svg>
    </button>

    @if (openMenuIndex === rowIndex) {
      <div class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg z-10">
        <button (click)="edit(row)" class="block w-full text-left px-4 py-2 hover:bg-gray-100">Edit</button>
        <button (click)="duplicate(row)" class="block w-full text-left px-4 py-2 hover:bg-gray-100">Duplicate</button>
        <button (click)="delete(row)" class="block w-full text-left px-4 py-2 hover:bg-gray-100 text-red-600">Delete</button>
      </div>
    }
  </div>
</ng-template>

Status Badge Column

<ng-template ngVuiGridColumn="status" headerName="Status" let-value>
  <span [class]="getStatusClass(value)" class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium">
    {{ value }}
  </span>
</ng-template>
getStatusClass(status: string): string {
  const classes = {
    'Active': 'bg-green-100 text-green-800',
    'Pending': 'bg-yellow-100 text-yellow-800',
    'Inactive': 'bg-red-100 text-red-800'
  };
  return classes[status] || 'bg-gray-100 text-gray-800';
}

Progress Bar Column

<ng-template ngVuiGridColumn="progress" headerName="Progress" let-value>
  <div class="flex items-center space-x-2">
    <div class="flex-1 bg-gray-200 rounded-full h-2">
      <div class="bg-violet-600 h-2 rounded-full transition-all" [style.width.%]="value"></div>
    </div>
    <span class="text-sm text-gray-600">{{ value }}%</span>
  </div>
</ng-template>

Image with Text Column

<ng-template ngVuiGridColumn="user" headerName="User" let-row="row">
  <div class="flex items-center space-x-3">
    <img [src]="row.avatar || '/default-avatar.png'" [alt]="row.name" class="w-10 h-10 rounded-full">
    <div>
      <div class="font-medium text-gray-900">{{ row.name }}</div>
      <div class="text-sm text-gray-500">{{ row.email }}</div>
    </div>
  </div>
</ng-template>

๐Ÿ“คData Export

// Component method
export() {
  this.gridApi?.exportDataAsCsv({
    fileName: 'data-export.csv',
    columnKeys: ['name', 'email', 'status'],
    skipHeaders: false
  });
}

// Excel export
exportExcel() {
  this.gridApi?.exportDataAsExcel({
    fileName: 'data-export.xlsx',
    sheetName: 'Data'
  });
}

// PDF export
exportPdf() {
  this.gridApi?.exportDataAsPdf({
    fileName: 'data-export.pdf',
    title: 'Data Report'
  });
}

๐ŸŽจStyling & Theming

Default Tailwind Classes

The component uses Tailwind CSS by default. You can customize the appearance:

gridOptions: GridOptions = {
  cssClasses: {
    root: 'rounded-lg border border-gray-200',
    header: 'bg-gray-50 border-b',
    body: 'bg-white',
    row: 'hover:bg-gray-50 border-b border-gray-100',
    cell: 'px-4 py-3'
  }
};

Custom CSS

/* Custom grid styling */
.my-grid {
  --grid-border-color: #e5e7eb;
  --grid-header-bg: #f9fafb;
  --grid-row-hover: #f3f4f6;
}

.my-grid .grid-header {
  background: var(--grid-header-bg);
}

.my-grid .grid-row:hover {
  background: var(--grid-row-hover);
}

๐Ÿ”ŒIntegration Examples

With Angular Reactive Forms

@Component({
  template: `
    <ng-grid [rowData]="formData" [gridOptions]="options">
      <ng-template ngVuiGridColumn="isActive" headerName="Active" let-value let-row="row">
        <input type="checkbox" [checked]="value" (change)="updateField(row, 'isActive', $event.target.checked)">
      </ng-template>
    </ng-grid>
  `
})
export class FormGridExample {
  updateField(row: any, field: string, value: any) {
    const index = this.formData.indexOf(row);
    this.formData[index][field] = value;
    // Update your reactive form here
  }
}

With HTTP Service

@Component({
  template: `
    <ng-grid
      [rowData]="data$ | async"
      [loading]="loading"
      [gridOptions]="options"
      (sortChanged)="onSort($event)"
      (filterChanged)="onFilter($event)"
    ></ng-grid>
  `
})
export class ServerDataExample {
  data$ = this.dataService.getData();
  loading = false;

  onSort(sorts: SortEvent[]) {
    this.loading = true;
    this.data$ = this.dataService.getData({ sort: sorts }).pipe(
      finalize(() => this.loading = false)
    );
  }

  onFilter(filter: FilterEvent) {
    this.loading = true;
    this.data$ = this.dataService.getData({ filter }).pipe(
      finalize(() => this.loading = false)
    );
  }
}

๐ŸงชTesting

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NgGridComponent } from '@ertpl-ui/ang-grid';

describe('NgGridComponent', () => {
  let component: NgGridComponent;
  let fixture: ComponentFixture<NgGridComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [NgGridComponent]
    });
    fixture = TestBed.createComponent(NgGridComponent);
    component = fixture.componentInstance;
  });

  it('should render data correctly', () => {
    component.rowData = [{ id: 1, name: 'Test' }];
    fixture.detectChanges();

    expect(fixture.nativeElement.textContent).toContain('Test');
  });
});

๐ŸคContributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Commit changes: git commit -am 'Add my feature'
  4. Push to branch: git push origin feature/my-feature
  5. Submit a pull request

๐ŸšจRecent Updates & Fixes

Angular 20+ Compatibility โœ…

Build & Architecture Improvements โœ…

Performance & Security โœ…

๐Ÿ“„License

MIT ยฉ VUI

๐Ÿ“šComprehensive Documentation

For detailed information about specific features, see these comprehensive guides:

Core Documentation

Performance & Optimization

Security & Best Practices

๐Ÿ”—Related Packages