Мне нужна была одна таблица с такими функциями, как нумерация страниц, фильтр (каждый столбец), сортировка, складная строка, редактируемая строка, фиксированная общая строка внизу, но я не смог найти точный плагин. поэтому я пытаюсь создать свой собственный плагин. я придумал нумерацию страниц, фильтр и сортировку на данный момент. и он работает, как ожидалось, но он загружает слишком много времени. на нумерации страниц 10 это работает нормально, но для 50 это занимает слишком много времени.
m-table.component. html
<div class="datatable table-responsive">
<div class="row mb-4">
<div class="col-sm-12" style="overflow-x: scroll;">
<table class="table table-bordered table-hover mb-0" width="100%" cellspacing="0">
<thead>
<tr>
<th *ngFor="let header of headers; let i = index;">
<a href="javascript:void(0);" (click)="sort(header)" style="text-decoration: none;">{{settings.columns[header]['title']}}</a>
<img class="float-right" src="../../../assets/img/sort-up.webp" *ngIf="sortHeader === header && direction" style="width: 18px;" />
<img class="float-right" src="../../../assets/img/sort-down.webp" *ngIf="sortHeader === header && !direction" style="width: 18px;" />
</th>
</tr>
</thead>
<tfoot>
<tr>
<th *ngFor="let header of headers">{{settings.columns[header]['title']}}</th>
</tr>
</tfoot>
<tbody>
<tr>
<td *ngFor="let header of headers">
<input class="form-control form-control-sm" [(ngModel)]="settings.columns[header]['filter']"
(ngModelChange)="filterChangeEvent($event, header)"
placeholder="{{settings.columns[header]['title']}}"/>
</td>
</tr>
<tr *ngFor="let record of pageOfItems">
<td *ngFor="let header of headers">
<div *ngIf="!settings.columns[header].type" [ngClass]="settings.columns[header].pill ? 'badge badge-primary badge-pill' : ''">
{{record[header]}}
</div>
<div *ngIf="settings.columns[header].type === 'date'" [ngClass]="settings.columns[header].pill ? 'badge badge-primary badge-pill' : ''">
{{record[header] | date: 'yyyy-mm-dd hh:mm:ss'}}
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="px-4">
<app-pagination [items]="dataCopy" [settings]="settings.pager" (changePage)="onChangePage($event)"></app-pagination>
</div>
</div>
</div>
</div>
m- table.component.ts
export class MTableComponent implements OnInit {
filterQuery: string;
filterQueryChanged: Subject<string> = new Subject<string>();
@Input() data;
@Input() settings;
dataCopy = [];
pageOfItems: Array<any>;
siteName = '';
headers = [];
direction = false;
sortHeader = '';
constructor() {
this.filterQueryChanged.pipe(debounceTime(2000), distinctUntilChanged()).subscribe(query => {
this.filterQuery = query;
this.dataCopy = JSON.parse(JSON.stringify(this.data));
for(let key in this.settings.columns) {
if(this.settings.columns[key]['filter'] && this.settings.columns[key]['filter'] != '') {
this.dataCopy = this.dataCopy.filter(a => a[key].toLowerCase().includes(this.settings.columns[key]['filter'].toLowerCase()));
}
}
});
}
ngOnInit(): void {}
ngOnChanges() {
this.dataCopy = JSON.parse(JSON.stringify(this.data));
this.headers = Object.keys(this.settings.columns);
}
filterChangeEvent(search, column) {
this.filterQueryChanged.next(search);
}
compareValues(direction: any, a: any, b: any) {
if (a < b) {
return -1 * direction;
}
if (a > b) {
return direction;
}
return 0;
}
sort(header: string) {
if(this.sortHeader === header) {
this.direction = !this.direction;
} else {
this.direction = false;
}
this.sortHeader = header;
const dir: number = this.direction ? 1 : -1;
const compare: Function = this.compareValues;
let dataCopy = this.dataCopy.sort((a, b) => {
return compare.call(null, dir, a[header], b[header]);
});
// did this because pagination was not detecting changes
this.dataCopy = JSON.parse(JSON.stringify(dataCopy));
}
onChangePage(pageOfItems: Array<any>) {
this.pageOfItems = pageOfItems;
}
}
pagination.component. html
<div class="dataTables_paginate paging_simple_numbers" *ngIf="pager.pages && pager.pages.length">
<div class="float-left">
<div>
<span class="float-left" style="padding-top: 7px;">Showing {{pager.startIndex + 1}} to {{pager.endIndex + 1}} of {{pager.totalItems}} entries</span>
</div>
</div>
<div class="float-right">
<ul class="pagination">
<li [ngClass]="{disabled:pager.currentPage === 1}" class="page-item first-item">
<a (click)="setPage(1)" class="page-link">
<i class="fas fa-angle-double-left"></i>
</a>
</li>
<li [ngClass]="{disabled:pager.currentPage === 1}" class="page-item previous-item">
<a (click)="setPage(pager.currentPage - 1)" class="page-link">
<i class="fas fa-angle-left"></i>
</a>
</li>
<li *ngFor="let page of pager.pages" [ngClass]="{active:pager.currentPage === page}" class="page-item number-item">
<a (click)="setPage(page)" class="page-link">{{page}}</a>
</li>
<li [ngClass]="{disabled:pager.currentPage === pager.totalPages}" class="page-item next-item">
<a (click)="setPage(pager.currentPage + 1)" class="page-link">
<i class="fas fa-angle-right"></i>
</a>
</li>
<li [ngClass]="{disabled:pager.currentPage === pager.totalPages}" class="page-item last-item">
<a (click)="setPage(pager.totalPages)" class="page-link">
<i class="fas fa-angle-double-right"></i>
</a>
</li>
</ul>
</div>
<div class="float-right mr-3" style="margin-top: 3px;">
<select [(ngModel)]="settings.pageSize" (ngModelChange)="setPage(initialPage)" class="form-control form-control-sm" style="width: 160px;">
<option *ngFor="let pageSize of settings.pageSizeOptions" [value]="pageSize">{{pageSize}}</option>
</select>
</div>
</div>
pagination.component.ts
export class PaginationComponent implements OnInit {
@Input() items: Array<any>;
@Output() changePage = new EventEmitter<any>(true);
@Input() initialPage = 1;
@Input() settings = {
pageSize: 100,
pageSizeOptions: [100, 200, 500],
maxPages: 5
};
pager: any = {};
ngOnInit() {
if (this.items && this.items.length) {
this.setPage(this.initialPage);
}
}
ngOnChanges(changes: SimpleChanges) {
if (changes.items.currentValue !== changes.items.previousValue) {
this.setPage(this.initialPage);
}
}
setPage(page: number) {
this.pager = paginate(this.items.length, page, this.settings.pageSize, this.settings.maxPages);
var pageOfItems = this.items.slice(this.pager.startIndex, this.pager.endIndex + 1);
this.changePage.emit(pageOfItems);
}
}
paginate.ts
export default function paginate(
totalItems: number,
currentPage: number = 1,
pageSize: number = 10,
maxPages: number = 10
) {
let totalPages = Math.ceil(totalItems / pageSize);
if (currentPage < 1) {
currentPage = 1;
} else if (currentPage > totalPages) {
currentPage = totalPages;
}
let startPage: number, endPage: number;
if (totalPages <= maxPages) {
startPage = 1;
endPage = totalPages;
} else {
let maxPagesBeforeCurrentPage = Math.floor(maxPages / 2);
let maxPagesAfterCurrentPage = Math.ceil(maxPages / 2) - 1;
if (currentPage <= maxPagesBeforeCurrentPage) {
startPage = 1;
endPage = maxPages;
} else if (currentPage + maxPagesAfterCurrentPage >= totalPages) {
startPage = totalPages - maxPages + 1;
endPage = totalPages;
} else {
startPage = currentPage - maxPagesBeforeCurrentPage;
endPage = currentPage + maxPagesAfterCurrentPage;
}
}
let startIndex = (currentPage - 1) * pageSize;
let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);
let pages = Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);
return {
totalItems: totalItems,
currentPage: currentPage,
pageSize: pageSize,
totalPages: totalPages,
startPage: startPage,
endPage: endPage,
startIndex: startIndex,
endIndex: endIndex,
pages: pages
};
}
Я не могу понять, что не так и как это исправить. все будет полезно, спасибо.
демо stackblitz