Angular 7 virtual scroll table with support dynamic component, draggable, filtering, sorting, paginations, resizable and custom config for each column
npm i ng-virtual-table
yarn add ng-virtual-table
Make sure you have:
@angular/cdk
@angular/material
@angular/forms
import { NgVirtualTableModule } from 'ng-virtual-table';
imports: [NgVirtualTableModule],
<ng-virtual-table [dataSource]="dataSource"></ng-virtual-table>
📺 Demo
@Input() itemSize = 25;
@Input() dataSource: Observable<Array<VirtualTableItem | number | string | boolean>>;
@Input() filterPlaceholder = 'Filter';
@Input() dataSetEmptyPlaceholder = 'Data is empty';
@Input() config: VirtualTableConfig;
@Input() onRowClick: (item: VirtualTableItem) => void;
export type sortColumn = 'asc' | 'desc' | null | false;
export interface VirtualPageChange {
pageSize?: number; // pagination size
pageIndex?: number; // page index
}
export interface VirtualSortEffect {
sortColumn: string; // column for sort
sortType?: sortColumn; // type sort
}
export interface VirtualTableColumn {
name?: string; // Label for field, if absent will be use key
key: string; // Uniq key for filed,
func?: (item: VirtualTableItem) => any; // function for get value from dataSource item
comp?: (a: any, b: any) => number; // function for compare two item, depend from `func` function
sort?: 'asc' | 'desc' | null | false; // sort by default(support only one sort), false for disable
resizable?: boolean; // default true(if not set `true`)
draggable?: boolean; // default true (if not set `true`)
component?: VirtualTableColumnComponent | false; // default false (You class component must be part of entryComponents in yor Module!!!!!)
}
export interface VirtualTableColumnComponent {
componentConstructor: Type<any>;
inputs?: Object; // default {}
outputs?: Object;
}
export interface VirtualTablePaginator {
pageSize?: number; // default 10
pageSizeOptions?: Array<number>; // default [5, 10, 25, 100];
showFirstLastButtons?: boolean; //default false;
}
export interface ResponseStreamWithSize {
stream: Array<any>; // stream for Server Side strategy
totalSize: number; // total size of stream
}
export interface VirtualTableEffect {
filter?: string; // filter string
sort?: VirtualSortEffect; // sort effect
pagination?: VirtualPageChange; // pagination effect
}
export interface VirtualTableConfig {
column?: Array<VirtualTableColumn>; // if config not provide will be auto generate column
header?: boolean; // default false
filter?: boolean; // default true
pagination?: VirtualTablePaginator | boolean; // default false
serverSide?: boolean; // default false;
serverSideResolver?: (effects: VirtualTableEffect) => Observable<ResponseStreamWithSize>;
}
import { VirtualTableConfig } from 'ng-virtual-table';
clickToItem(item: any) {
console.log(item);
}
dataSource = of(
Array(1000).fill(0).map((e) => ({
name: Math.random().toString(36).substring(7),
age: Math.round(Math.random() * 1000),
})),
);
dataSource1 = of(
Array(1000).fill(0).map((e) => ({
name: Math.random().toString(36).substring(7),
age: Math.round(Math.random() * 1000),
age2: Math.round(Math.random() * 1000),
label: {
type: Math.random().toString(36).substring(7),
},
})),
);
config: VirtualTableConfig = {
column: [
{
key: 'name',
name: 'Full name',
sort: false // disable sort
},
{
key: 'age',
name: 'Full Age',
sort: 'desc', // pre defined sort
component: {
componentConstructor: InfoComponent,
inputs: {
title: (e) => e.age,
},
},
},
{
key: 'label',
name: 'Full Label',
func: (e) => e.label.type,
comp: (a, b) => a.indexOf('5') - b.indexOf('5'), // here a and b (e) => e.label.type
},
],
};
@Component({
selector: 'app-info',
templateUrl: './info.component.html',
styleUrls: ['./info.component.scss'],
})
export class InfoComponent {
@Input() title: string;
constructor() {}
}
<ng-virtual-table [dataSource]="dataSource"></ng-virtual-table>
<ng-virtual-table [dataSource]="dataSource1" [onRowClick]="clickToItem" [config]="config"></ng-virtual-table>