基于 Angular 2+ 的分页指令

Angular 2+ 中分页指令是有的,比如 ngx-bootstrap pagination,这里我参考了 angular2-datatable, 加入我们自己的逻辑,自己写分页指令。

HTML 页代码

User ID User Name User Phone Modi Time User Address
{{item['ghu_uid']}} {{item['ghu_usrname']}} {{item['ghu_usrphone']}} {{item['ghu_birthdate']}} {{item['ghu_usraddr']}}

解释一下,表格上方有一个搜索框,一个搜索按钮,一个刷新按钮,下来就是表格,再下来就是分页。

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;
  private inputData: Array = [];
  /* tslint:disable */
  @Input('rdDataSrc') public dataSrc: string;
  @Input('rdIsInc') public isInc = false;
  @Input('rdFilterQuery') public filterQuery: string;
  @Input('rdSearchScopes') public searchScopes: Array = [];
  @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> = new EventEmitter;
  @Output() selectedRows: EventEmitter> = new EventEmitter;

  private mustRecalculateData = false;
  public data: any[];
  public onPageChange = new EventEmitter();
  public inputDataLength = 0;
  private getPageData = null;
  private readonly _selectedIds: Set;
  private readonly _selectedRows: Set;
  private rdArrayIndices: Set;

  @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();
    this._selectedRows = new Set();
    // this.rdArrayData = [];
    this.rdArrayIndices = new Set();
  }

  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();
      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();
      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);
  }
}







你可能感兴趣的:(基于 Angular 2+ 的分页指令)