UNPKG

@pascalhonegger/ng-datatable

Version:
458 lines (449 loc) 20.6 kB
import * as i0 from '@angular/core'; import { EventEmitter, inject, IterableDiffers, Input, Output, Directive, input, Component, computed, NgModule } from '@angular/core'; import { ReplaySubject } from 'rxjs'; class DataTable { diff; inputData = []; sortBy = ""; sortOrder = "asc"; sortByChange = new EventEmitter(); sortOrderChange = new EventEmitter(); rowsOnPage = 1000; activePage = 1; mustRecalculateData = false; data; onSortChange = new ReplaySubject(1); onPageChange = new EventEmitter(); constructor() { const differs = inject(IterableDiffers); this.diff = differs.find([]).create(); } getSort() { return { sortBy: this.sortBy, sortOrder: this.sortOrder }; } setSort(sortBy, sortOrder) { if (this.sortBy !== sortBy || this.sortOrder !== sortOrder) { this.sortBy = sortBy; this.sortOrder = ["asc", "desc"].indexOf(sortOrder) >= 0 ? sortOrder : "asc"; this.mustRecalculateData = true; this.onSortChange.next({ sortBy: this.sortBy, sortOrder: this.sortOrder }); this.sortByChange.emit(this.sortBy); this.sortOrderChange.emit(this.sortOrder); } } getPage() { return { activePage: this.activePage, rowsOnPage: this.rowsOnPage, dataLength: this.inputData.length }; } setPage(activePage, rowsOnPage) { if (this.rowsOnPage !== rowsOnPage || this.activePage !== activePage) { this.activePage = this.activePage !== activePage ? activePage : this.calculateNewActivePage(this.rowsOnPage, rowsOnPage); this.rowsOnPage = rowsOnPage; this.mustRecalculateData = true; this.onPageChange.emit({ activePage: this.activePage, rowsOnPage: this.rowsOnPage, dataLength: this.inputData ? this.inputData.length : 0 }); } } calculateNewActivePage(previousRowsOnPage, currentRowsOnPage) { const firstRowOnPage = (this.activePage - 1) * previousRowsOnPage + 1; const newActivePage = Math.ceil(firstRowOnPage / currentRowsOnPage); return newActivePage; } recalculatePage() { const lastPage = Math.ceil(this.inputData.length / this.rowsOnPage); this.activePage = lastPage < this.activePage ? lastPage : this.activePage; this.activePage = this.activePage || 1; this.onPageChange.emit({ activePage: this.activePage, rowsOnPage: this.rowsOnPage, dataLength: this.inputData.length }); } ngOnChanges(changes) { if (changes["rowsOnPage"]) { this.rowsOnPage = changes["rowsOnPage"].previousValue; this.setPage(this.activePage, changes["rowsOnPage"].currentValue); this.mustRecalculateData = true; } if (changes["sortBy"] || changes["sortOrder"]) { if (["asc", "desc"].indexOf(this.sortOrder) < 0) { console.warn("ng-datatable: value for input mfSortOrder must be one of ['asc', 'desc'], but is:", this.sortOrder); this.sortOrder = "asc"; } if (this.sortBy) { this.onSortChange.next({ sortBy: this.sortBy, sortOrder: this.sortOrder }); } this.mustRecalculateData = true; } if (changes["inputData"]) { this.inputData = changes["inputData"].currentValue || []; this.diff.diff(this.inputData); // Update diff to prevent duplicate update in ngDoCheck this.recalculatePage(); this.mustRecalculateData = true; } } ngDoCheck() { const changes = this.diff.diff(this.inputData); if (changes) { this.recalculatePage(); this.mustRecalculateData = true; } if (this.mustRecalculateData) { this.fillData(); this.mustRecalculateData = false; } } fillData() { // this.activePage = this.activePage; // this.rowsOnPage = this.rowsOnPage; const offset = (this.activePage - 1) * this.rowsOnPage; // let data = this.inputData; // const sortBy = this.sortBy; // if (typeof sortBy === "string" || sortBy instanceof String) { // data = orderBy(data, this.caseInsensitiveIteratee(sortBy as string), [this.sortOrder]); // } else { // data = orderBy(data, sortBy, [this.sortOrder]); // } // data = slice(data, offset, offset + this.rowsOnPage); this.data = [...this.inputData] .sort(this.sorter(this.sortBy, this.sortOrder)) .slice(offset, offset + this.rowsOnPage); } caseInsensitiveIteratee(sortBy) { return (row) => { let value = row; if (typeof sortBy === "string" || sortBy instanceof String) { for (const sortByProperty of sortBy.split(".")) { if (value) { value = value[sortByProperty]; } } } else if (typeof sortBy === "function") { value = sortBy(value); } if (value && typeof value === "string" || value instanceof String) { return value.toLowerCase(); } return value; }; } compare(left, right) { if (left === right) { return 0; } if (left == null && right != null) { return -1; } if (right == null) { return 1; } return left > right ? 1 : -1; } sorter(sortBy, sortOrder) { const order = sortOrder === "desc" ? -1 : 1; if (Array.isArray(sortBy)) { const iteratees = sortBy.map((entry) => this.caseInsensitiveIteratee(entry)); return (left, right) => { for (const iteratee of iteratees) { const comparison = this.compare(iteratee(left), iteratee(right)) * order; if (comparison !== 0) { return comparison; } } return 0; }; } else { const iteratee = this.caseInsensitiveIteratee(sortBy); return (left, right) => this.compare(iteratee(left), iteratee(right)) * order; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DataTable, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: DataTable, isStandalone: true, selector: "table[mfData]", inputs: { inputData: ["mfData", "inputData"], sortBy: ["mfSortBy", "sortBy"], sortOrder: ["mfSortOrder", "sortOrder"], rowsOnPage: ["mfRowsOnPage", "rowsOnPage"], activePage: ["mfActivePage", "activePage"] }, outputs: { sortByChange: "mfSortByChange", sortOrderChange: "mfSortOrderChange" }, exportAs: ["mfDataTable"], usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DataTable, decorators: [{ type: Directive, args: [{ selector: "table[mfData]", exportAs: "mfDataTable" }] }], ctorParameters: () => [], propDecorators: { inputData: [{ type: Input, args: ["mfData"] }], sortBy: [{ type: Input, args: ["mfSortBy"] }], sortOrder: [{ type: Input, args: ["mfSortOrder"] }], sortByChange: [{ type: Output, args: ["mfSortByChange"] }], sortOrderChange: [{ type: Output, args: ["mfSortOrderChange"] }], rowsOnPage: [{ type: Input, args: ["mfRowsOnPage"] }], activePage: [{ type: Input, args: ["mfActivePage"] }] } }); class Paginator { injectMfTable = inject(DataTable, { optional: true }); inputMfTable = input(undefined, { alias: "mfTable" }); mfTable; activePage; rowsOnPage; dataLength = 0; lastPage; ngOnChanges() { this.mfTable = this.inputMfTable() ?? this.injectMfTable; this.onPageChangeSubscriber(this.mfTable.getPage()); this.mfTable.onPageChange.subscribe(this.onPageChangeSubscriber); } setPage(pageNumber) { this.mfTable.setPage(pageNumber, this.rowsOnPage); } setRowsOnPage(rowsOnPage) { this.mfTable.setPage(this.activePage, rowsOnPage); } onPageChangeSubscriber = (event) => { this.activePage = event.activePage; this.rowsOnPage = event.rowsOnPage; this.dataLength = event.dataLength; this.lastPage = Math.ceil(this.dataLength / this.rowsOnPage); }; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Paginator, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: Paginator, isStandalone: true, selector: "mfPaginator", inputs: { inputMfTable: { classPropertyName: "inputMfTable", publicName: "mfTable", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Paginator, decorators: [{ type: Component, args: [{ selector: "mfPaginator", template: `<ng-content></ng-content>` }] }] }); class BootstrapPaginator { rowsOnPageSet = input([]); mfTable = input(); minRowsOnPage = computed(() => this.rowsOnPageSet().reduce((previous, current) => current < previous ? current : previous, 0)); static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: BootstrapPaginator, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: BootstrapPaginator, isStandalone: true, selector: "mfBootstrapPaginator", inputs: { rowsOnPageSet: { classPropertyName: "rowsOnPageSet", publicName: "rowsOnPageSet", isSignal: true, isRequired: false, transformFunction: null }, mfTable: { classPropertyName: "mfTable", publicName: "mfTable", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: ` <mfPaginator #p [mfTable]="mfTable()"> @if (p.dataLength > p.rowsOnPage) { <ul class="pagination float-start"> <li class="page-item" [class.disabled]="p.activePage <= 1" (click)="p.setPage(1)"> <a class="page-link" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a> </li> @if (p.activePage > 4 && p.activePage + 1 > p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage - 4)"> <a class="page-link">{{p.activePage-4}}</a> </li> } @if (p.activePage > 3 && p.activePage + 2 > p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage - 3)"> <a class="page-link">{{p.activePage-3}}</a> </li> } @if (p.activePage > 2) { <li class="page-item" (click)="p.setPage(p.activePage - 2)"> <a class="page-link">{{p.activePage-2}}</a> </li> } @if (p.activePage > 1) { <li class="page-item" (click)="p.setPage(p.activePage - 1)"> <a class="page-link">{{p.activePage-1}}</a> </li> } <li class="page-item active"> <a class="page-link">{{p.activePage}}</a> </li> @if (p.activePage + 1 <= p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage + 1)"> <a class="page-link">{{p.activePage+1}}</a> </li> } @if (p.activePage + 2 <= p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage + 2)"> <a class="page-link">{{p.activePage+2}}</a> </li> } @if (p.activePage + 3 <= p.lastPage && p.activePage < 3) { <li class="page-item" (click)="p.setPage(p.activePage + 3)"> <a class="page-link">{{p.activePage+3}}</a> </li> } @if (p.activePage + 4 <= p.lastPage && p.activePage < 2) { <li class="page-item" (click)="p.setPage(p.activePage + 4)"> <a class="page-link">{{p.activePage+4}}</a> </li> } <li class="page-item" [class.disabled]="p.activePage >= p.lastPage" (click)="p.setPage(p.lastPage)"> <a class="page-link" aria-label="Next"><span aria-hidden="true">&raquo;</span></a> </li> </ul> } @if (p.dataLength > minRowsOnPage()) { <ul class="pagination float-end"> @for (rows of rowsOnPageSet(); track rows) { <li class="page-item" [class.active]="p.rowsOnPage===rows" (click)="p.setRowsOnPage(rows)"> <a class="page-link">{{rows}}</a> </li> } </ul> } </mfPaginator> `, isInline: true, styles: [".page-link{cursor:pointer}\n"], dependencies: [{ kind: "component", type: Paginator, selector: "mfPaginator", inputs: ["mfTable"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: BootstrapPaginator, decorators: [{ type: Component, args: [{ selector: "mfBootstrapPaginator", template: ` <mfPaginator #p [mfTable]="mfTable()"> @if (p.dataLength > p.rowsOnPage) { <ul class="pagination float-start"> <li class="page-item" [class.disabled]="p.activePage <= 1" (click)="p.setPage(1)"> <a class="page-link" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a> </li> @if (p.activePage > 4 && p.activePage + 1 > p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage - 4)"> <a class="page-link">{{p.activePage-4}}</a> </li> } @if (p.activePage > 3 && p.activePage + 2 > p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage - 3)"> <a class="page-link">{{p.activePage-3}}</a> </li> } @if (p.activePage > 2) { <li class="page-item" (click)="p.setPage(p.activePage - 2)"> <a class="page-link">{{p.activePage-2}}</a> </li> } @if (p.activePage > 1) { <li class="page-item" (click)="p.setPage(p.activePage - 1)"> <a class="page-link">{{p.activePage-1}}</a> </li> } <li class="page-item active"> <a class="page-link">{{p.activePage}}</a> </li> @if (p.activePage + 1 <= p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage + 1)"> <a class="page-link">{{p.activePage+1}}</a> </li> } @if (p.activePage + 2 <= p.lastPage) { <li class="page-item" (click)="p.setPage(p.activePage + 2)"> <a class="page-link">{{p.activePage+2}}</a> </li> } @if (p.activePage + 3 <= p.lastPage && p.activePage < 3) { <li class="page-item" (click)="p.setPage(p.activePage + 3)"> <a class="page-link">{{p.activePage+3}}</a> </li> } @if (p.activePage + 4 <= p.lastPage && p.activePage < 2) { <li class="page-item" (click)="p.setPage(p.activePage + 4)"> <a class="page-link">{{p.activePage+4}}</a> </li> } <li class="page-item" [class.disabled]="p.activePage >= p.lastPage" (click)="p.setPage(p.lastPage)"> <a class="page-link" aria-label="Next"><span aria-hidden="true">&raquo;</span></a> </li> </ul> } @if (p.dataLength > minRowsOnPage()) { <ul class="pagination float-end"> @for (rows of rowsOnPageSet(); track rows) { <li class="page-item" [class.active]="p.rowsOnPage===rows" (click)="p.setRowsOnPage(rows)"> <a class="page-link">{{rows}}</a> </li> } </ul> } </mfPaginator> `, imports: [Paginator], styles: [".page-link{cursor:pointer}\n"] }] }] }); class DefaultSorter { mfTable = inject((DataTable)); sortBy = input.required({ alias: "by" }); isSortedByMeAsc = false; isSortedByMeDesc = false; ngOnInit() { this.mfTable.onSortChange.subscribe((event) => { this.isSortedByMeAsc = (event.sortBy == this.sortBy() && event.sortOrder === "asc"); this.isSortedByMeDesc = (event.sortBy == this.sortBy() && event.sortOrder === "desc"); }); } sort() { if (this.isSortedByMeAsc) { this.mfTable.setSort(this.sortBy(), "desc"); } else { this.mfTable.setSort(this.sortBy(), "asc"); } return false; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DefaultSorter, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: DefaultSorter, isStandalone: true, selector: "mfDefaultSorter", inputs: { sortBy: { classPropertyName: "sortBy", publicName: "by", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: ` <a (click)="sort()" (keydown.enter)="sort()" (keydown.space)="sort()" class="text-nowrap text-decoration-none" tabindex="0"> <ng-content></ng-content> @if (isSortedByMeAsc) { <span aria-hidden="true" aria-label="asc">▲</span> } @else if (isSortedByMeDesc) { <span aria-hidden="true" aria-label="desc">▼</span> } </a>`, isInline: true, styles: ["a{cursor:pointer}\n"] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DefaultSorter, decorators: [{ type: Component, args: [{ selector: "mfDefaultSorter", template: ` <a (click)="sort()" (keydown.enter)="sort()" (keydown.space)="sort()" class="text-nowrap text-decoration-none" tabindex="0"> <ng-content></ng-content> @if (isSortedByMeAsc) { <span aria-hidden="true" aria-label="asc">▲</span> } @else if (isSortedByMeDesc) { <span aria-hidden="true" aria-label="desc">▼</span> } </a>`, styles: ["a{cursor:pointer}\n"] }] }] }); class DataTableModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DataTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: DataTableModule, imports: [DataTable, DefaultSorter, Paginator, BootstrapPaginator], exports: [DataTable, DefaultSorter, Paginator, BootstrapPaginator] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DataTableModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DataTableModule, decorators: [{ type: NgModule, args: [{ imports: [ DataTable, DefaultSorter, Paginator, BootstrapPaginator ], exports: [ DataTable, DefaultSorter, Paginator, BootstrapPaginator ] }] }] }); /* * Public API Surface of ng-datatable */ /** * Generated bundle index. Do not edit. */ export { BootstrapPaginator, DataTable, DataTableModule, DefaultSorter, Paginator }; //# sourceMappingURL=pascalhonegger-ng-datatable.mjs.map