美文网首页我爱编程
基于 Angular 2+ 的分页指令

基于 Angular 2+ 的分页指令

作者: 环零弦 | 来源:发表于2018-04-20 19:07 被阅读0次

    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>&nbsp; Search
          </button>
          <button id="refreshBtn" type="button" class="btn btn-success" style="margin-left: 2px">
            <i class="fa fa-refresh"></i>&nbsp; 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);
      }
    }
    
    

    相关文章

      网友评论

        本文标题:基于 Angular 2+ 的分页指令

        本文链接:https://www.haomeiwen.com/subject/phuzkftx.html