// @ts-nocheck import { Component, Input, OnInit } from "@angular/core"; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; export interface DataGridColumn { key: string; label: string; type: "number" | "string" | "date"; sortable: boolean; } /** * Angular Component Wrapper for Mayvio UI Data Grid. * Usage: `` */ @Component({ selector: "mayvio-data-grid", standalone: true, imports: [CommonModule, FormsModule], template: `
{{ col.label }}
{{ row[col.key] }} {{ row[col.key] }}
No records match the active filters.
Showing {{ startRecord }}-{{ endRecord }} of {{ totalRecords }}
`, styles: [] }) export class DataGridComponent implements OnInit { @Input() initialData: any[] = []; @Input() columns: DataGridColumn[] = []; searchQuery = ""; currentPage = 1; pageSize = 10; sortCol: string | null = null; sortDir: "asc" | "desc" = "asc"; visibleCols: string[] = []; isColMenuOpen = false; filteredData: any[] = []; paginatedData: any[] = []; totalPages = 1; startRecord = 0; endRecord = 0; totalRecords = 0; pageNumbers: number[] = []; ngOnInit() { this.visibleCols = this.columns.map((c) => c.key); this.updateGrid(); // Add close listener for columns dropdown document.addEventListener("click", this.onOutsideClick.bind(this)); } onOutsideClick(event: Event) { if (this.isColMenuOpen) { const dropdown = document.querySelector(".dg-dropdown"); if (dropdown && !dropdown.contains(event.target as Node)) { this.isColMenuOpen = false; } } } toggleColMenu(event: Event) { event.stopPropagation(); this.isColMenuOpen = !this.isColMenuOpen; } isColumnVisible(key: string): boolean { return this.visibleCols.includes(key); } toggleColumnVisibility(key: string) { if (this.visibleCols.includes(key)) { this.visibleCols = this.visibleCols.filter((k) => k !== key); } else { this.visibleCols = [...this.visibleCols, key]; } } getVisibleColumnsCount(): number { return this.visibleCols.length; } getSortAttr(col: DataGridColumn): string { if (this.sortCol !== col.key) return "none"; return this.sortDir === "asc" ? "ascending" : "descending"; } getSortIcon(key: string): string { if (this.sortCol !== key) return "⇅"; return this.sortDir === "asc" ? "▲" : "▼"; } handleSort(key: string) { if (this.sortCol === key) { this.sortDir = this.sortDir === "asc" ? "desc" : "asc"; } else { this.sortCol = key; this.sortDir = "asc"; } this.currentPage = 1; this.updateGrid(); } onSearchChange() { this.currentPage = 1; this.updateGrid(); } onPageSizeChange(size: any) { this.pageSize = parseInt(size, 10) || 10; this.currentPage = 1; this.updateGrid(); } goToPage(page: number) { this.currentPage = page; this.updatePagination(); } updateGrid() { // 1. Search Query Filter const q = this.searchQuery.trim().toLowerCase(); if (q) { this.filteredData = this.initialData.filter((row) => Object.values(row).some((val) => String(val).toLowerCase().includes(q)) ); } else { this.filteredData = [...this.initialData]; } // 2. Sorting if (this.sortCol) { const colDef = this.columns.find((c) => c.key === this.sortCol); const isAsc = this.sortDir === "asc"; const factor = isAsc ? 1 : -1; this.filteredData.sort((a, b) => { const valA = a[this.sortCol!]; const valB = b[this.sortCol!]; if (colDef?.type === "number") { return (valA - valB) * factor; } else if (colDef?.type === "date") { return (new Date(valA).getTime() - new Date(valB).getTime()) * factor; } else { return String(valA).localeCompare(String(valB)) * factor; } }); } this.updatePagination(); } updatePagination() { this.totalRecords = this.filteredData.length; this.totalPages = Math.ceil(this.totalRecords / this.pageSize) || 1; if (this.currentPage > this.totalPages) { this.currentPage = this.totalPages; } this.startRecord = this.totalRecords === 0 ? 0 : (this.currentPage - 1) * this.pageSize + 1; this.endRecord = Math.min(this.currentPage * this.pageSize, this.totalRecords); const startIdx = (this.currentPage - 1) * this.pageSize; this.paginatedData = this.filteredData.slice(startIdx, startIdx + this.pageSize); this.pageNumbers = Array.from({ length: this.totalPages }, (_, i) => i + 1); } }