// @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 }}
{{ getSortIcon(col.key) }}
|
|
{{ row[col.key] }}
{{ row[col.key] }}
|
|
No records match the active filters.
|
`,
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);
}
}