diff --git a/components/core/util/convert.ts b/components/core/util/convert.ts index d876a8a248d..494b8d348d7 100644 --- a/components/core/util/convert.ts +++ b/components/core/util/convert.ts @@ -1,12 +1,14 @@ -import { coerceBooleanProperty, coerceCssPixelValue, coerceNumberProperty } from '@angular/cdk/coercion'; +import { coerceBooleanProperty, coerceCssPixelValue, _isNumberValue } from '@angular/cdk/coercion'; import { FunctionProp } from '../types/common-wrap'; export function toBoolean(value: boolean | string): boolean { return coerceBooleanProperty(value); } -export function toNumber(value: number | string, fallback: D): number | D { - return coerceNumberProperty(value, fallback); +export function toNumber(value: number | string): number; +export function toNumber(value: number | string, fallback: D): number | D; +export function toNumber(value: number | string, fallbackValue: number = 0): number { + return _isNumberValue(value) ? Number(value) : fallbackValue; } export function toCssPixel(value: number | string): string { @@ -70,4 +72,8 @@ export function InputBoolean(): any { // tslint:disable-line: no-any export function InputCssPixel(): any { // tslint:disable-line: no-any return propDecoratorFactory('InputCssPixel', toCssPixel); -} \ No newline at end of file +} + +export function InputNumber(): any { // tslint:disable-line: no-any + return propDecoratorFactory('InputNumber', toNumber); +} diff --git a/components/pagination/doc/index.en-US.md b/components/pagination/doc/index.en-US.md index 8db593c7fc3..bc6c0feba1f 100755 --- a/components/pagination/doc/index.en-US.md +++ b/components/pagination/doc/index.en-US.md @@ -28,7 +28,7 @@ A long list can be divided into several pages by `Pagination`, and only one page | `[nzShowQuickJumper]` | determine whether you can jump to pages directly | `boolean` | `false` | | `[nzShowSizeChanger]` | determine whether `nzPageSize` can be changed | `boolean` | `false` | | `[nzSimple]` | whether to use simple mode | `boolean` | - | -| `[nzSize]` | specify the size of `nz-pagination`, can be set to `small` | `'small'` | `""` | +| `[nzSize]` | specify the size of `nz-pagination`, can be set to `small` | `'small'` | `'default'` | | `[nzPageSizeOptions]` | specify the sizeChanger options | `number[]` | `[10, 20, 30, 40]` | | `[nzItemRender]` | to customize item | `TemplateRef<{ $implicit: 'page'|'prev'|'next', page: number }>` | - | | `[nzShowTotal]` | to display the total number and range | `TemplateRef<{ $implicit: number, range: [ number, number ] }>` | - | diff --git a/components/pagination/doc/index.zh-CN.md b/components/pagination/doc/index.zh-CN.md index 5b1dc61a1fb..e95bb803ea1 100755 --- a/components/pagination/doc/index.zh-CN.md +++ b/components/pagination/doc/index.zh-CN.md @@ -29,7 +29,7 @@ cols: 1 | `[nzShowQuickJumper]` | 是否可以快速跳转至某页 | `boolean` | `false` | | `[nzShowSizeChanger]` | 是否可以改变 `nzPageSize` | `boolean` | `false` | | `[nzSimple]` | 当添加该属性时,显示为简单分页 | `boolean` | - | -| `[nzSize]` | 当为「small」时,是小尺寸分页 | `'small'` | `""` | +| `[nzSize]` | 当为「small」时,是小尺寸分页 | `'small'` | `'default'` | | `[nzPageSizeOptions]` | 指定每页可以显示多少条 | `number[]` | `[10, 20, 30, 40]` | | `[nzItemRender]` | 用于自定义页码的结构 | `TemplateRef<{ $implicit: 'page'|'prev'|'next', page: number }>` | - | | `[nzShowTotal]` | 用于显示数据总量和当前数据范围,具体使用方式见代码演示部分 | `TemplateRef<{ $implicit: number, range: [ number, number ] }>` | - | diff --git a/components/pagination/nz-pagination.component.html b/components/pagination/nz-pagination.component.html index 40d7f1675fa..958d46773ef 100644 --- a/components/pagination/nz-pagination.component.html +++ b/components/pagination/nz-pagination.component.html @@ -1,133 +1,111 @@ - {{page}} + {{ page }} - -
    +
      -
    • - -
    • -
    • - - - {{ lastIndex }} -
    • -
    • - -
    • -
    - \ No newline at end of file diff --git a/components/pagination/nz-pagination.component.ts b/components/pagination/nz-pagination.component.ts index bf5b6b710c4..4e4883f0d51 100644 --- a/components/pagination/nz-pagination.component.ts +++ b/components/pagination/nz-pagination.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, @@ -6,181 +7,103 @@ import { OnInit, Output, TemplateRef, - ViewChild + ViewChild, + ViewEncapsulation } from '@angular/core'; - import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; - import { isInteger } from '../core/util/check'; -import { toBoolean } from '../core/util/convert'; +import { toNumber, InputBoolean, InputNumber } from '../core/util/convert'; import { NzI18nService } from '../i18n/nz-i18n.service'; @Component({ selector : 'nz-pagination', preserveWhitespaces: false, + encapsulation : ViewEncapsulation.None, + changeDetection : ChangeDetectionStrategy.OnPush, templateUrl : './nz-pagination.component.html' }) export class NzPaginationComponent implements OnInit, OnDestroy { - private unsubscribe$ = new Subject(); // tslint:disable-next-line:no-any locale: any = {}; - @ViewChild('renderItemTemplate') private _itemRender: TemplateRef<{ $implicit: 'page' | 'prev' | 'next', page: number }>; - private _showSizeChanger = false; - private _showQuickJumper = false; - private _simple = false; - private _hideOnSinglePage = false; - private _pageSize = 10; - private _pageSizeOptions = [ 10, 20, 30, 40 ]; - private _total: number; - private _pageIndex = 1; firstIndex = 1; pages = []; - @Input() nzShowTotal: TemplateRef<{ $implicit: number, range: [ number, number ] }>; - @Input() nzInTable = false; - @Input() nzSize: string; + private $destroy = new Subject(); + private _pageSize = 10; + private _pageIndex = 1; + private _total = 0; @Output() readonly nzPageSizeChange: EventEmitter = new EventEmitter(); @Output() readonly nzPageIndexChange: EventEmitter = new EventEmitter(); - - @Input() - set nzItemRender(value: TemplateRef<{ $implicit: 'page' | 'prev' | 'next', page: number }>) { - this._itemRender = value; - } - - get nzItemRender(): TemplateRef<{ $implicit: 'page' | 'prev' | 'next', page: number }> { - return this._itemRender; - } - - @Input() - set nzShowSizeChanger(value: boolean) { - this._showSizeChanger = toBoolean(value); - } - - get nzShowSizeChanger(): boolean { - return this._showSizeChanger; - } - - @Input() - set nzHideOnSinglePage(value: boolean) { - this._hideOnSinglePage = toBoolean(value); - } - - get nzHideOnSinglePage(): boolean { - return this._hideOnSinglePage; - } - - @Input() - set nzShowQuickJumper(value: boolean) { - this._showQuickJumper = toBoolean(value); - } - - get nzShowQuickJumper(): boolean { - return this._showQuickJumper; - } - - @Input() - set nzSimple(value: boolean) { - this._simple = toBoolean(value); - } - - get nzSimple(): boolean { - return this._simple; - } - - /** page size changer select values */ - @Input() - set nzPageSizeOptions(value: number[]) { - if (value && value.length) { - this._pageSizeOptions = value; - } + @Input() nzShowTotal: TemplateRef<{ $implicit: number, range: [ number, number ] }>; + @Input() nzInTable = false; + @Input() nzSize: 'default' | 'small' = 'default'; + @Input() nzPageSizeOptions = [ 10, 20, 30, 40 ]; + @Input() @ViewChild('renderItemTemplate') nzItemRender: TemplateRef<{ $implicit: 'page' | 'prev' | 'next', page: number }>; + @Input() @InputBoolean() nzShowSizeChanger = false; + @Input() @InputBoolean() nzHideOnSinglePage = false; + @Input() @InputBoolean() nzShowQuickJumper = false; + @Input() @InputBoolean() nzSimple = false; + + @Input() @InputNumber() + set nzTotal(value: number) { + this._total = value; + this.buildIndexes(); } - get nzPageSizeOptions(): number[] { - return this._pageSizeOptions; + get nzTotal(): number { + return this._total; } - @Input() + @Input() @InputNumber() set nzPageIndex(value: number) { - if (this._pageIndex === value) { - return; + if (this._pageIndex !== value) { + this._pageIndex = this.validatePageIndex(value); + this.buildIndexes(); } - if (value > this.lastIndex) { - this._pageIndex = this.lastIndex; - } else if (value < this.firstIndex) { - this._pageIndex = this.firstIndex; - } else { - this._pageIndex = Number(value); - } - this.buildIndexes(); } get nzPageIndex(): number { return this._pageIndex; } - @Input() + @Input() @InputNumber() set nzPageSize(value: number) { - if (value === this._pageSize) { - return; - } - this._pageSize = value; - const pageIndexOverflow = this.checkLastIndexOverflow(); - if (pageIndexOverflow) { - this.nzPageIndex = this.lastIndex; - this.nzPageIndexChange.emit(this.lastIndex); + if (value !== this._pageSize) { + this._pageSize = value; + if (this.nzPageIndex > this.lastIndex) { + this.nzPageIndex = this.lastIndex; + this.nzPageIndexChange.emit(this.lastIndex); + } + this.buildIndexes(); } - this.buildIndexes(); } get nzPageSize(): number { return this._pageSize; } - @Input() - set nzTotal(value: number) { - this._total = value; - this.buildIndexes(); - } - - get nzTotal(): number { - return this._total; - } - - jumpPage(index: number): void { - if (index === this.nzPageIndex) { - return; - } - - if (index < this.firstIndex) { - this.nzPageIndex = this.firstIndex; - } else if (index > this.lastIndex) { - this.nzPageIndex = this.lastIndex; + validatePageIndex(value: number): number { + if (value > this.lastIndex) { + return this.lastIndex; + } else if (value < this.firstIndex) { + return this.firstIndex; } else { - this.nzPageIndex = index; + return value; } - this.nzPageIndexChange.emit(this.nzPageIndex); - } - - jumpPreFive(): void { - this.jumpPage(this.nzPageIndex - 5); } - jumpNextFive(): void { - this.jumpPage(this.nzPageIndex + 5); - } - - jumpPreOne(): void { - if (this.isFirstIndex) { - return; + jumpPage(index: number): void { + if (index !== this.nzPageIndex) { + const pageIndex = this.validatePageIndex(index); + if (pageIndex !== this.nzPageIndex) { + this.nzPageIndex = pageIndex; + this.nzPageIndexChange.emit(this.nzPageIndex); + } } - this.jumpPage(this.nzPageIndex - 1); } - jumpNextOne(): void { - if (this.isLastIndex) { - return; - } - this.jumpPage(this.nzPageIndex + 1); + jumpDiff(diff: number): void { + this.jumpPage(this.nzPageIndex + diff); } onPageSizeChange($event: number): void { @@ -190,27 +113,11 @@ export class NzPaginationComponent implements OnInit, OnDestroy { handleKeyDown(e: KeyboardEvent, input: HTMLInputElement, clearInputValue: boolean): void { const target = input; - const inputValue = target.value; - const currentInputValue = this.nzPageIndex; - let value; - - if (inputValue === '') { - value = inputValue; - } else if (isNaN(Number(inputValue))) { - value = currentInputValue; - } else { - value = Number(inputValue); - } - this.handleChange(value, target, clearInputValue); - } - - isValid(page: number): boolean { - return isInteger(page) && (page >= 1) && (page !== this.nzPageIndex) && (page <= this.lastIndex); - } - - handleChange(value: number, target: HTMLInputElement, clearInputValue: boolean): void { - const page = value; - if (this.isValid(page)) { + const page = toNumber(target.value, this.nzPageIndex); + if (isInteger(page) && + (page >= 1) && + (page !== this.nzPageIndex) && + (page <= this.lastIndex)) { this.nzPageIndex = page; this.nzPageIndexChange.emit(this.nzPageIndex); } @@ -221,39 +128,32 @@ export class NzPaginationComponent implements OnInit, OnDestroy { } } - checkLastIndexOverflow(): boolean { - return this.nzPageIndex > this.lastIndex; - } - - get lastIndex(): number { - return Math.ceil(this.nzTotal / this.nzPageSize); - } - /** generate indexes list */ buildIndexes(): void { - const tmpPages = []; + const pages = []; if (this.lastIndex <= 9) { for (let i = 2; i <= this.lastIndex - 1; i++) { - tmpPages.push({ index: i }); + pages.push(i); } } else { const current = +this.nzPageIndex; let left = Math.max(2, current - 2); let right = Math.min(current + 2, this.lastIndex - 1); - if (current - 1 <= 2) { right = 5; } - if (this.lastIndex - current <= 2) { left = this.lastIndex - 4; } - for (let i = left; i <= right; i++) { - tmpPages.push({ index: i }); + pages.push(i); } } - this.pages = tmpPages; + this.pages = pages; + } + + get lastIndex(): number { + return Math.ceil(this.nzTotal / this.nzPageSize); } get isLastIndex(): boolean { @@ -264,19 +164,28 @@ export class NzPaginationComponent implements OnInit, OnDestroy { return this.nzPageIndex === this.firstIndex; } - min(val1: number, val2: number): number { - return Math.min(val1, val2); + get ranges(): number[] { + return [ (this.nzPageIndex - 1) * this.nzPageSize + 1, Math.min(this.nzPageIndex * this.nzPageSize, this.nzTotal) ]; + } + + get showAddOption(): boolean { + return this.nzPageSizeOptions.indexOf(this.nzPageSize) === -1; } - constructor(private i18n: NzI18nService) { + constructor(private i18n: NzI18nService, private cdr: ChangeDetectorRef) { } ngOnInit(): void { - this.i18n.localeChange.pipe(takeUntil(this.unsubscribe$)).subscribe(() => this.locale = this.i18n.getLocaleData('Pagination')); + this.i18n.localeChange.pipe( + takeUntil(this.$destroy) + ).subscribe(() => { + this.locale = this.i18n.getLocaleData('Pagination'); + this.cdr.markForCheck(); + }); } ngOnDestroy(): void { - this.unsubscribe$.next(); - this.unsubscribe$.complete(); + this.$destroy.next(); + this.$destroy.complete(); } } diff --git a/components/pagination/nz-pagination.spec.ts b/components/pagination/nz-pagination.spec.ts index f3ad0770fbf..b7d07340d3f 100644 --- a/components/pagination/nz-pagination.spec.ts +++ b/components/pagination/nz-pagination.spec.ts @@ -151,7 +151,7 @@ describe('pagination', () => { testComponent.showSizeChanger = true; fixture.detectChanges(); fixture.whenStable().then(() => { - expect(paginationElement.children.length).toBe(12); + expect(paginationElement.children.length).toBe(10); expect(paginationElement.lastElementChild.classList.contains('ant-pagination-options')).toBe(true); }); }));