import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
computed,
effect,
inject,
input,
signal,
viewChild,
} from '@angular/core';
import { Skeleton } from 'primeng/skeleton';
import { Table, TableLazyLoadEvent, TableModule } from 'primeng/table';
import { Column, DuckdbService } from '../duckdb.service';
@Component({
selector: 'app-file-viewer',
standalone: true,
imports: [TableModule, Skeleton],
template: `
@if (file() && columns().length > 0) {
@for (col of columns; track $index) {
|
{{ col.name }}
|
}
@for (col of columns; track $index) {
|
{{ rowData[col.name] }}
|
}
@for (col of columns; track $index) {
|
|
}
}
`,
styleUrl: './file-viewer.component.css',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FileViewerComponent {
file = input();
private duckdbService = inject(DuckdbService);
private cdr = inject(ChangeDetectorRef);
// Can't be computed since effect has to run first so file exists in duckdb
protected columns = signal([]);
protected numRows = 200;
protected currentValue = signal([]);
constructor() {
effect(async () => {
const file = this.file();
if (file) {
await this.duckdbService.addFile(file);
this.columns.set(await this.duckdbService.getColumns(file));
const rows = await this.duckdbService.getRows(
file,
0,
this.numRows,
this.columns(),
[],
[],
);
const newValue = Array.from({ length: Number(rows.totalRows) });
this.currentValue.set(newValue);
}
});
}
protected async onLazyLoad(event: TableLazyLoadEvent) {
const file = this.file();
if (file) {
const rows = await this.duckdbService.getRows(
file,
event.first ?? 0,
event.rows ?? 0,
this.columns(),
[],
[],
);
// First clear out existing data, don't want to risk loading entire file into memory
// Keep data in previous/next page so when user scrolls between 2 pages they don't see missing data
for (let i = 0; i < this.currentValue().length; i++) {
if (
i < event.first! - this.numRows ||
i > event.first! + event.rows! + this.numRows
) {
this.currentValue()[i] = undefined;
}
}
// Can't update the current value, otherwise we get an infinite loop
this.currentValue().splice(event.first!, event.rows!, ...rows.rows);
this.cdr.markForCheck();
}
}
}