@ng-vui/ng-vui-grid
v1.0.2
Published
Advanced Angular Data Grid Component with Templates, Sorting, Filtering, and Export features
Downloads
312
Maintainers
Readme
@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
- ✅ Standalone Components - Modern Angular 20+ standalone architecture
- ✅ Custom Cell Templates - Full Angular template syntax support
- ✅ Action Columns - Buttons, dropdowns, and interactive elements
- ✅ Advanced Sorting - Multi-column sorting with custom comparators
- ✅ Flexible Filtering - Built-in and custom filter types
- ✅ Server-Side Operations - Server-side pagination, filtering, and sorting
- ✅ Data Streaming - Real-time data streaming support
- ✅ Virtual Scrolling - Handle large datasets efficiently (100k+ rows)
- ✅ Security Features - Input validation and XSS protection
- ✅ Data Export - CSV, Excel, and PDF export
- ✅ Column Management - Show/hide, resize, reorder columns
- ✅ Row Selection - Single and multi-select with checkboxes
- ✅ Responsive Design - Mobile-friendly with Tailwind CSS
- ✅ TypeScript Support - Full type safety and IntelliSense
- ✅ State Management - Grid state persistence and restoration
📦 Installation
npm install @ng-vui/ng-vui-gridPeer Dependencies:
- Angular 17+ (
@angular/core,@angular/common,@angular/forms) - RxJS 6.5+ or 7+
🏗️ 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: '[email protected]', status: 'Active' },
{ id: 2, name: 'Jane Smith', email: '[email protected]', 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 ngGridColumn="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 ngGridColumn="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 ngGridColumn="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 ngGridColumn="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 ngGridColumn="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 ngGridColumn="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
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit changes:
git commit -am 'Add my feature' - Push to branch:
git push origin feature/my-feature - Submit a pull request
🚨 Recent Updates & Fixes
Angular 20+ Compatibility ✅
- Fixed
ng buildissues with ng-packagr - Resolved cross-library import dependencies
- Updated peer dependencies to support Angular 17-20+
- Improved TypeScript compilation with strict mode
Build & Architecture Improvements ✅
- Standalone Components: Full migration to modern Angular architecture
- Signal-based State: Reactive state management implementation
- Fixed Import Issues: Resolved relative import problems causing build failures
- Enhanced Type Safety: Complete TypeScript interface coverage
Performance & Security ✅
- Virtual Scrolling: Handle 10M+ records efficiently
- XSS Protection: Enhanced security with input validation
- Memory Optimization: Improved garbage collection and state management
- Bundle Size: Reduced bundle size with standalone components
📄 License
MIT © VUI
📚 Comprehensive Documentation
For detailed information about specific features, see these comprehensive guides:
Core Documentation
- Complete Grid Documentation - Comprehensive API reference and examples
- Template System Guide - Advanced template usage and customization
- Comprehensive Feature Guide - In-depth feature documentation
Performance & Optimization
- Performance Guide - Performance optimization techniques and best practices
- Virtual Scrolling Guide - Virtual scrolling implementation and configuration
Security & Best Practices
- Security Documentation - Security features, XSS protection, and input validation
🔗 Related Packages
@ng-vui/multi-select- Multi-select dropdown component@ng-vui/date-picker- Date picker component@ng-vui/select-input- Single select dropdown@ng-vui/text-input- Text input component@ng-vui/textarea- Textarea component@ng-vui/auto-complete- Auto complete component
