Angular 2+ 中分页指令是有的,比如 ngx-bootstrap pagination,这里我参考了 angular2-datatable, 加入我们自己的逻辑,自己写分页指令。
HTML 页代码
<div class="row mb-3">
<div class="col-md-4 offset-md-8">
<div class="input-group">
<input #searchValue type="text" (keydown.enter)="search(searchValue.value)" class="form-control" placeholder="Search by scopes you defined"/>
<button type="button" class="btn btn-primary" (click)="search(searchValue.value)">
<i class="fa fa-search"></i> Search
</button>
<button id="refreshBtn" type="button" class="btn btn-success" style="margin-left: 2px">
<i class="fa fa-refresh"></i> refresh
</button>
</div>
</div>
</div>
<table class="table table-striped" #rd="rdDataTable" [rdDataSrc]="dataSrc" [rdIsInc]="isInc" [rdFilterQuery]="filterQuery"
[rdPagesPrefetch]="pagesPrefetch" [rdRowsOnPage]="rowsOnPage" [rdSearchScopes]="searchScopes" [rdIDCol]="idCol" [rdRefreshBtn]="'refreshBtn'"
(selectedIds)="setSelectIds($event)" (selectedRows)="setSelectedRows($event)">
<thead>
<tr>
<th style="width: 5%"></th>
<th style="width: 10%">✔</th>
<th style="width: 10%">
<a class="text-nowrap">User ID</a>
</th>
<th style="width: 10%">
<a class="text-nowrap">User Name</a>
</th>
<th style="width: 20%">
<a class="text-nowrap">User Phone</a>
</th>
<th style="width: 20%">
<a class="text-nowrap">Modi Time</a>
</th>
<th style="width: 25%">
<a class="text-nowrap">User Address</a>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of rd.data; let i = index">
<td>
<label style="display: none">{{i}}</label>
</td>
<td>
<input type="checkbox">
</td>
<td>{{item['ghu_uid']}}</td>
<td class="text-middle">{{item['ghu_usrname']}}</td>
<td>{{item['ghu_usrphone']}}</td>
<td>{{item['ghu_birthdate']}}</td>
<td>{{item['ghu_usraddr']}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="999">
<app-randy-paginator [rowsOnPageSet]="rowsOnPageSet"></app-randy-paginator>
</td>
</tr>
</tfoot>
</table>
解释一下,表格上方有一个搜索框,一个搜索按钮,一个刷新按钮,下来就是表格,再下来就是分页。
table 的输入以下:
变量 | 含义 |
---|---|
rdDataSrc | 数据来源,可以是一个URL |
rdIsInc | 是否是增量查询 |
rdFilterQuery | 搜索的VALUE |
rdPagesPrefetch | 预取几页数据 |
rdRowsOnPage | 每页几行数据 |
rdSearchScopes | 搜索KEY,是个数组 |
rdIDCol | 数据ID所在的列 |
rdRefreshBtn | 刷新按钮的ID |
table 的输出如下:
变量 | 含义 |
---|---|
selectedIds | 根据输入的ID,输出checkbox选中的行的ID |
selectedRows | 输出checkbox选中的行的数据 |
以下直接贴代码了
import {
Directive, Input, EventEmitter, SimpleChange, OnChanges, DoCheck, IterableDiffers,
IterableDiffer, Output, OnInit, HostListener, ElementRef
} from '@angular/core';
import * as _ from 'lodash';
import { RequsetStructure } from '../../../models/submit.entities';
import { SubmitService } from '../../../providers/submit.service';
import { ElectronService } from '../../../providers/electron.service';
export interface PageEvent {
activePage: number;
rowsOnPage: number;
dataLength: number;
}
export interface DataEvent {
length: number;
}
@Directive({
// tslint:disable-next-line:directive-selector
selector: 'table[rdDataSrc]',
exportAs: 'rdDataTable'
})
export class DataTableDirective implements OnChanges, DoCheck, OnInit {
private diff: IterableDiffer<string>;
private inputData: Array<any> = [];
/* tslint:disable */
@Input('rdDataSrc') public dataSrc: string;
@Input('rdIsInc') public isInc = false;
@Input('rdFilterQuery') public filterQuery: string;
@Input('rdSearchScopes') public searchScopes: Array<string> = [];
@Input('rdIDCol') public idCol: number;
@Input('rdPagesPrefetch') public pagesPrefetch: number;
@Input('rdRefreshBtn') public reFreshBtn: string;
@Input('rdRowsOnPage') public rowsOnPage = 1000;
@Input('rdActivePage') public activePage = 1;
/* tslint:enable */
@Output() selectedIds: EventEmitter<Set<number>> = new EventEmitter;
@Output() selectedRows: EventEmitter<Set<object>> = new EventEmitter;
private mustRecalculateData = false;
public data: any[];
public onPageChange = new EventEmitter<PageEvent>();
public inputDataLength = 0;
private getPageData = null;
private readonly _selectedIds: Set<number>;
private readonly _selectedRows: Set<object>;
private rdArrayIndices: Set<number>;
@HostListener('document:click', ['$event.target'])
public onClick2(targetElement) {
const clickedInside = this._elementRef.nativeElement.contains(targetElement);
if (!clickedInside) {
if (targetElement.getAttribute('id') === this.reFreshBtn) {
this.getPageData(true);
}
}
}
@HostListener('click', ['$event.target']) onClick(element) {
const checkbox = element.parentElement.querySelector('[type=checkbox]');
const findTr = _node => {
if (_node.nodeName === 'TR') {
return _node;
} else {
return findTr(_node.parentElement);
}
};
if (checkbox) {
const tdsRef = findTr(element).querySelectorAll('td');
const idCell = tdsRef[this.idCol];
const indexCell = tdsRef[0].querySelector('label');
if (!checkbox.isEqualNode(element)) {
checkbox.checked = !checkbox.checked;
}
if (checkbox.checked) {
this._selectedIds.add(+idCell.innerHTML);
if (indexCell) {
this._selectedRows.add(this.inputData[+indexCell.innerHTML]);
}
} else {
this._selectedIds.delete(+idCell.innerHTML);
if (indexCell) {
this._selectedRows.delete(this.inputData[+indexCell.innerHTML]);
}
}
this.selectedIds.emit(this._selectedIds);
this.selectedRows.emit(this._selectedRows);
}
};
public constructor(private differs: IterableDiffers,
private _elementRef: ElementRef,
private submitService: SubmitService,
private electronService: ElectronService) {
this.diff = differs.find([]).create(null);
this.pagesPrefetch = 5;
this.filterQuery = '';
this._selectedIds = new Set<number>();
this._selectedRows = new Set<object>();
// this.rdArrayData = [];
this.rdArrayIndices = new Set<number>();
}
ngOnInit() {
if (this.isInc && this.electronService.containerType !== 'BROWSER') {
// console.log('SQLite 增量');
this.getPageData = this.getPageDataL;
} else {
this.getPageData = this.getPageDataR;
}
this.getPageData(true);
}
private getPageDataR = (refreshFlag: boolean = false) => {
if (refreshFlag) {
// this.rdArrayData = [];
// this.rdArrayIndices = new Set<number>();
this.rdArrayIndices.clear();
this.inputData = [];
this.inputDataLength = 0;
}
// if (!this.activePage) {
this.activePage = 1;
// }
const indexBegin = (this.activePage - 1) * this.rowsOnPage;
const indexLength = this.pagesPrefetch * this.rowsOnPage;
const reqStructure: RequsetStructure = {
reqParams: {
offset: String(indexBegin),
rowLength: String(indexLength)
},
withCredentials: true
};
if (this.filterQuery && this.filterQuery !== '') {
reqStructure.reqParams['filterQuery'] = this.filterQuery;
reqStructure.reqParams['searchScopes'] = JSON.stringify(this.searchScopes);
}
this.submitService.getHttpSubmit(this.dataSrc, true, reqStructure)
.subscribe(data => {
// this.inputData = [...data['respResultset']];
let count = 0;
const _data = [...data['respResultset']];
const _tmp = [];
this.inputDataLength = data['respData']['dataLength'];
let indexEnd = indexBegin + indexLength;
indexEnd = this.inputDataLength ? indexEnd > this.inputDataLength ? this.inputDataLength : indexEnd : indexEnd;
for (let index = indexBegin; index < indexEnd; index++) {
this.inputData[index] = _data[count];
_tmp[count] = index;
count++;
}
this.rdArrayIndices = new Set(Array.from(this.rdArrayIndices).concat(_tmp));
}, error => {
console.log(error);
});
};
private getPageDataL = (refreshFlag: boolean = false) => {
if (refreshFlag) {
// this.rdArrayData = [];
// this.rdArrayIndices = new Set<number>();
this.rdArrayIndices.clear();
this.inputData = [];
this.inputDataLength = 0;
}
// if (!this.activePage) {
this.activePage = 1;
// }
const indexBegin = (this.activePage - 1) * this.rowsOnPage;
const indexLength = this.pagesPrefetch * this.rowsOnPage;
let wStatement = '';
if (this.filterQuery) {
const _searchScopes = this.searchScopes.map(value => `${value} LIKE "%${this.filterQuery}%"`);
wStatement = this.searchScopes.length > 0 && this.filterQuery !== '' ? ` WHERE ${_searchScopes.join(' OR ')}` : '';
}
const lStatement = ` LIMIT ${indexBegin}, ${indexLength}`;
const queryStatement = `SELECT * FROM zz_rd_pub_hosproleinfo${wStatement}${lStatement};SELECT COUNT(*) AS total FROM zz_rd_pub_hosproleinfo${wStatement};`;
this.electronService.execQuery(queryStatement).then(data => {
// console.log(queryStatement);
// console.log(data);
if (!data[0]['tablename']) {
let count = 0;
this.inputDataLength = data.pop()['total'];
const _data = [...data];
const _tmp = [];
let indexEnd = indexBegin + indexLength;
indexEnd = this.inputDataLength ? indexEnd > this.inputDataLength ? this.inputDataLength : indexEnd : indexEnd;
for (let index = indexBegin; index < indexEnd; index++) {
this.inputData[index] = _data[count];
_tmp[count] = index;
count++;
}
this.rdArrayIndices = new Set(Array.from(this.rdArrayIndices).concat(_tmp));
}
})
};
public getPage(): PageEvent {
return { activePage: this.activePage, rowsOnPage: this.rowsOnPage, dataLength: this.inputDataLength };
}
public setPage(activePage: number, rowsOnPage: number): void {
if (this.rowsOnPage !== rowsOnPage || this.activePage !== activePage) {
this.activePage = this.activePage !== activePage ? activePage : this.calculateNewActivePage(this.rowsOnPage, rowsOnPage);
this.rowsOnPage = rowsOnPage;
this.mustRecalculateData = true;
// if (this.rdDataStorage[this.storeKey])
{
const indexBegin = (this.activePage - 1) * this.rowsOnPage;
const indexEnd = indexBegin + this.rowsOnPage;
let updateFrom = -1;
for (let index = indexBegin; index < indexEnd; index++) {
if (!this.rdArrayIndices.has(index)) {
updateFrom = index;
break;
}
}
if (updateFrom > -1) {
this.getPageData();
} else {
this.onPageChange.emit({
activePage: this.activePage,
rowsOnPage: this.rowsOnPage,
dataLength: this.inputData ? this.inputDataLength : 0
});
}
}
}
}
private calculateNewActivePage(previousRowsOnPage: number, currentRowsOnPage: number): number {
const firstRowOnPage = (this.activePage - 1) * previousRowsOnPage + 1;
return Math.ceil(firstRowOnPage / currentRowsOnPage); // newActivePage
}
private recalculatePage() {
const lastPage = Math.ceil(this.inputDataLength / 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.inputDataLength
});
}
public ngOnChanges(changes: { [key: string]: SimpleChange }): any {
if (changes['filterQuery']) {
this.activePage = 1;
if (this.getPageData) {
this.getPageData(true);
}
}
if (changes['rowsOnPage']) {
this.rowsOnPage = changes['rowsOnPage'].previousValue;
this.setPage(this.activePage, changes['rowsOnPage'].currentValue);
this.mustRecalculateData = true;
}
if (changes['inputData']) {
this.inputData = changes['inputData'].currentValue || [];
this.recalculatePage();
this.mustRecalculateData = true;
}
}
public ngDoCheck(): any {
const changes = this.diff.diff(this.inputData);
if (changes) {
this.recalculatePage();
this.mustRecalculateData = true;
}
if (this.mustRecalculateData) {
this.fillData();
this.mustRecalculateData = false;
}
}
private fillData(): void {
// this.activePage = this.activePage;
// this.rowsOnPage = this.rowsOnPage;
const offset = (this.activePage - 1) * this.rowsOnPage;
let data = this.inputData;
data = _.slice(data, offset, offset + this.rowsOnPage > this.inputDataLength ? this.inputDataLength : offset + this.rowsOnPage);
this.data = data;
// console.log(this.inputData);
}
}
网友评论