npm package: @ng-vui/ng-vui-grid
Description: Advanced Angular Data Grid Component with Templates, Sorting, Filtering, and Export features
Author: Varun Singh
Latest version: 1.0.2

# @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

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

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

```typescript
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

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

```typescript
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

```html
<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

```typescript
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

```typescript
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

```html
<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

```html
<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>
```

```typescript
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

```html
<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

```html
<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

```typescript
// 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:

```typescript
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

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

```typescript
@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

```typescript
@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

```typescript
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 ✅
- Fixed `ng build` issues 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](https://github.com/ultimatevarun/ng-vui-examples)

## 📚 Comprehensive Documentation

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

### Core Documentation
- **[Complete Grid Documentation](./NG-VUI-GRID.md)** - Comprehensive API reference and examples
- **[Template System Guide](./TEMPLATES.md)** - Advanced template usage and customization
- **[Comprehensive Feature Guide](./COMPREHENSIVE.md)** - In-depth feature documentation

### Performance & Optimization
- **[Performance Guide](./PERFORMANCE.md)** - Performance optimization techniques and best practices
- **[Virtual Scrolling Guide](./VIRTUAL_SCROLLING.md)** - Virtual scrolling implementation and configuration

### Security & Best Practices
- **[Security Documentation](./SECURITY.md)** - 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