diff --git a/apps/docs/src/app/core/component-docs/pagination/examples/pagination-example.component.ts b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-example.component.ts
index 0857d68317c..e0e5bdcea2a 100644
--- a/apps/docs/src/app/core/component-docs/pagination/examples/pagination-example.component.ts
+++ b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-example.component.ts
@@ -1,48 +1,53 @@
import { Component, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { PaginationComponent } from '@fundamental-ngx/core';
+import { tap, delay } from 'rxjs/operators';
@Component({
selector: 'fd-pagination-example',
template: `
- `
+
+
{{ notification }}
+ `
})
export class PaginationExampleComponent {
totalItems = 50;
itemsPerPage = 10;
- currentPage = 3;
+ currentPage = 5;
+ notification: string = null;
@ViewChild(PaginationComponent) paginationComponent: PaginationComponent;
- newPageClicked(event): void {
- this.http.get('assets/pagination-data.json').subscribe(
+ newPageClicked(event: number): void {
+ this.http.get('assets/pagination-data.json').pipe(
+ tap(() => {
+ this.notification = 'loading...';
+ }),
+ delay(100),
+ ).subscribe(
(data) => {
- /*
- update the currentPage when the http action is successful
- */
+ /* update the currentPage when the http action is successful */
this.currentPage = event;
- console.log('page change success!');
+ this.notification = 'page change success!';
},
(error) => {
- /*
- do not update the currentPage when the http action fails
- */
- console.log('page change error!');
+ /* do not update the currentPage when the http action fails */
+ this.notification = 'page change error!';
},
() => {
- alert('New page selected: ' + this.currentPage);
+ this.notification = 'New page selected: ' + this.currentPage;
}
);
}
- goToPage1(): void {
- this.paginationComponent.goToPage(1);
+ goToPage(page: number): void {
+ this.paginationComponent.goToPage(page);
}
constructor(private http: HttpClient) {}
diff --git a/apps/docs/src/app/core/component-docs/pagination/examples/pagination-per-page-example.component.html b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-per-page-example.component.html
new file mode 100644
index 00000000000..0cc6b4c6a00
--- /dev/null
+++ b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-per-page-example.component.html
@@ -0,0 +1,37 @@
+
+
[itemsPerPage]=15
Default property for items per page
+
+
+
+
[itemsPerPageOptions]="[4,8,16]"
- Default select template for items per page options
+
+
+
+
Custom items per page - list of buttons
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/docs/src/app/core/component-docs/pagination/examples/pagination-per-page-example.component.ts b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-per-page-example.component.ts
new file mode 100644
index 00000000000..157a0c3db83
--- /dev/null
+++ b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-per-page-example.component.ts
@@ -0,0 +1,22 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'fd-pagination-per-page-example',
+ templateUrl: './pagination-per-page-example.component.html'
+})
+export class PaginationPerPageExampleComponent {
+ totalItems = 50;
+ currentPage1 = 1;
+ currentPage2 = 1;
+ currentPage3 = 1;
+
+ pageChanged1(event: number): void {
+ this.currentPage1 = event;
+ }
+ pageChanged2(event: number): void {
+ this.currentPage2 = event;
+ }
+ pageChanged3(event: number): void {
+ this.currentPage3 = event;
+ }
+}
diff --git a/apps/docs/src/app/core/component-docs/pagination/examples/pagination-showing-example.component.ts b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-showing-example.component.ts
new file mode 100644
index 00000000000..6972b8893ac
--- /dev/null
+++ b/apps/docs/src/app/core/component-docs/pagination/examples/pagination-showing-example.component.ts
@@ -0,0 +1,26 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'fd-pagination-showing-example',
+ template: `
+
+
+ From {{ showing.from }} to {{ showing.to }}. Total items {{ showing.of }}
+
+ `
+})
+export class PaginationShowingExampleComponent {
+ totalItems = 50;
+ itemsPerPage = 10;
+ currentPage = 1;
+
+ pageChanged(event: number): void {
+ this.currentPage = event;
+ }
+}
diff --git a/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.html b/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.html
index 5aaee5e4ee6..92f5281f1f6 100644
--- a/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.html
+++ b/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.html
@@ -1,5 +1,5 @@
-
- Pagination
+
+ Basic Pagination
@@ -7,11 +7,47 @@
+
+
+ Pagination showing items
+
+
+ Pagination with custom showing template
+
+ Set [displayTextTemplate]
property to specify the display template for showing items.
+
+
+
+
+
+
+
+
+
+
+ Pagination with per page select.
+
+
+ Pagination with custom showing template
+
+ Set [itemsPerPage]
property to number of items per page. It's equal 10 by default.
+ Set [itemsPerPageOptions]
property to array of numbers for items per page select.
+ Set [itemsPerPageTemplate]
property to custom template.
+ You will have onSelect
property to interact with component.
+ This property has higher priority than [itemsPerPageOptions]
.
+
+
+
+
+
+
+
+
+
diff --git a/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.ts b/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.ts
index 31bc2eca2be..c6b70ed5220 100644
--- a/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.ts
+++ b/apps/docs/src/app/core/component-docs/pagination/pagination-docs.component.ts
@@ -3,6 +3,12 @@ import { Schema } from '../../../schema/models/schema.model';
import { SchemaFactoryService } from '../../../schema/services/schema-factory/schema-factory.service';
import * as paginationSrc from '!raw-loader!./examples/pagination-example.component.ts';
+
+import * as paginationShowingSrc from '!raw-loader!./examples/pagination-showing-example.component.ts';
+
+import * as paginationPerPageHtml from '!raw-loader!./examples/pagination-per-page-example.component.html';
+import * as paginationPerPageTs from '!raw-loader!./examples/pagination-per-page-example.component.ts';
+
import { ExampleFile } from '../../../documentation/core-helpers/code-example/example-file';
@Component({
@@ -53,6 +59,28 @@ export class PaginationDocsComponent {
}
];
+ paginationShowing: ExampleFile[] = [
+ {
+ language: 'typescript',
+ code: paginationShowingSrc,
+ fileName: 'pagination-showing-example',
+ component: 'PaginationShowingExampleComponent'
+ }
+ ];
+ paginationPerPageSrc: ExampleFile[] = [
+ {
+ language: 'html',
+ code: paginationPerPageHtml,
+ fileName: 'pagination-perpage-example',
+ },
+ {
+ language: 'typescript',
+ code: paginationPerPageTs,
+ fileName: 'pagination-perpage-example',
+ component: 'PaginationPerPageExampleComponent'
+ }
+ ];
+
constructor(private schemaFactory: SchemaFactoryService) {
this.schema = this.schemaFactory.getComponent('pagination');
}
diff --git a/apps/docs/src/app/core/component-docs/pagination/pagination-docs.module.ts b/apps/docs/src/app/core/component-docs/pagination/pagination-docs.module.ts
index a1a21937738..84cdc5d1d18 100644
--- a/apps/docs/src/app/core/component-docs/pagination/pagination-docs.module.ts
+++ b/apps/docs/src/app/core/component-docs/pagination/pagination-docs.module.ts
@@ -5,7 +5,10 @@ import { API_FILES } from '../../api-files';
import { PaginationHeaderComponent } from './pagination-header/pagination-header.component';
import { PaginationDocsComponent } from './pagination-docs.component';
import { PaginationExampleComponent } from './examples/pagination-example.component';
-import { PaginationModule } from '@fundamental-ngx/core';
+import { PaginationShowingExampleComponent } from './examples/pagination-showing-example.component';
+import { PaginationPerPageExampleComponent } from './examples/pagination-per-page-example.component';
+
+import { PaginationModule, ToolbarModule, SelectModule, SegmentedButtonModule } from '@fundamental-ngx/core';
import { SharedDocumentationPageModule } from '../../../documentation/shared-documentation-page.module';
const routes: Routes = [
@@ -20,8 +23,21 @@ const routes: Routes = [
];
@NgModule({
- imports: [RouterModule.forChild(routes), SharedDocumentationPageModule, PaginationModule],
+ imports: [
+ RouterModule.forChild(routes),
+ SharedDocumentationPageModule,
+ PaginationModule,
+ ToolbarModule,
+ SelectModule,
+ SegmentedButtonModule
+ ],
exports: [RouterModule],
- declarations: [PaginationDocsComponent, PaginationHeaderComponent, PaginationExampleComponent]
+ declarations: [
+ PaginationDocsComponent,
+ PaginationHeaderComponent,
+ PaginationExampleComponent,
+ PaginationShowingExampleComponent,
+ PaginationPerPageExampleComponent
+ ]
})
export class PaginationDocsModule {}
diff --git a/libs/core/src/lib/pagination/pagination.component.html b/libs/core/src/lib/pagination/pagination.component.html
index 0eb12919749..2b64c5be8ed 100644
--- a/libs/core/src/lib/pagination/pagination.component.html
+++ b/libs/core/src/lib/pagination/pagination.component.html
@@ -1,51 +1,72 @@
-
-
-
+
-
+
-
-
+
+
+ Showing {{ showing.from }}-{{ showing.to }} of {{ showing.of }}
+
+
+
+
+
+
+ {{ option }}
+
+
diff --git a/libs/core/src/lib/pagination/pagination.component.scss b/libs/core/src/lib/pagination/pagination.component.scss
index edea6b942fd..aec87ac39a5 100644
--- a/libs/core/src/lib/pagination/pagination.component.scss
+++ b/libs/core/src/lib/pagination/pagination.component.scss
@@ -1,10 +1,20 @@
@import '~fundamental-styles/dist/pagination';
-.fd-pagination-direction-override-display {
- display: inline-block;
-}
+$block: fd-pagination;
+
+.#{$block} {
+ &-direction-override-display {
+ display: inline-block;
+ }
+
+ &__total--rtl {
+ margin-right: 0;
+ margin-left: 8px;
+ }
-.fd-pagination__total--rtl {
- margin-right: 0;
- margin-left: 8px;
+ &__holder {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
}
diff --git a/libs/core/src/lib/pagination/pagination.component.spec.ts b/libs/core/src/lib/pagination/pagination.component.spec.ts
index 8b82f0bdd56..d7e14edd5f3 100644
--- a/libs/core/src/lib/pagination/pagination.component.spec.ts
+++ b/libs/core/src/lib/pagination/pagination.component.spec.ts
@@ -1,6 +1,9 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ChangeDetectionStrategy } from '@angular/core';
+import { By } from '@angular/platform-browser';
import { PaginationComponent } from './pagination.component';
import { PaginationService } from './pagination.service';
+import { SelectModule, SelectComponent } from '../select/public_api';
describe('Pagination Test', () => {
let component: PaginationComponent;
@@ -12,7 +15,10 @@ describe('Pagination Test', () => {
TestBed.configureTestingModule({
declarations: [PaginationComponent],
+ imports: [SelectModule],
providers: [{ provide: PaginationService, useValue: paginationSpy }]
+ }).overrideComponent(PaginationComponent, {
+ set: {changeDetection: ChangeDetectionStrategy.Default}
}).compileComponents();
paginationServiceSpy = TestBed.get(PaginationService);
@@ -27,6 +33,18 @@ describe('Pagination Test', () => {
fixture.detectChanges();
});
+ it('should default to first page', () => {
+ component.currentPage = null;
+ fixture.detectChanges();
+ expect(component.currentPage).toEqual(1);
+ });
+
+ it('should get the pagination object for the service', () => {
+ const retVal = component.getPaginationObject();
+
+ expect(retVal).toEqual({ totalItems: 3, currentPage: 1, itemsPerPage: 2 });
+ });
+
it('should handle keypress', () => {
const keyboardEvent = new KeyboardEvent('keypress', {
key: 'Enter'
@@ -40,6 +58,15 @@ describe('Pagination Test', () => {
expect(component.goToPage).toHaveBeenCalledWith(1);
});
+ it('should have default select for item per page with options', async () => {
+ component.totalItems = 100;
+ component.itemsPerPageOptions = [2, 4, 6];
+ fixture.detectChanges();
+ const selectComponent = fixture.debugElement.query(By.directive(SelectComponent));
+ const selectInstance = selectComponent.injector.get(SelectComponent);
+ expect(selectInstance).toBeInstanceOf(SelectComponent);
+ });
+
it('should handle mouseevent', () => {
const mouseEvent = new MouseEvent('click');
spyOn(mouseEvent, 'preventDefault');
@@ -49,10 +76,4 @@ describe('Pagination Test', () => {
expect(component.pageChangeStart.emit).toHaveBeenCalledWith(1);
});
-
- it('should get the pagination object for the service', () => {
- const retVal = component.getPaginationObject();
-
- expect(retVal).toEqual({ totalItems: 3, currentPage: 1, itemsPerPage: 2 });
- });
});
diff --git a/libs/core/src/lib/pagination/pagination.component.ts b/libs/core/src/lib/pagination/pagination.component.ts
index c1a71d64040..1250bff5390 100644
--- a/libs/core/src/lib/pagination/pagination.component.ts
+++ b/libs/core/src/lib/pagination/pagination.component.ts
@@ -8,13 +8,27 @@ import {
Optional,
Output,
SimpleChanges,
- ViewEncapsulation
+ ViewEncapsulation,
+ TemplateRef
} from '@angular/core';
+import {
+ ENTER,
+ SPACE
+} from '@angular/cdk/keycodes';
+import { coerceNumberProperty, coerceArray } from '@angular/cdk/coercion';
+
+import { KeyUtil } from '../utils/functions';
import { PaginationService } from './pagination.service';
import { RtlService } from '../utils/services/rtl.service';
-import { BehaviorSubject } from 'rxjs';
import { Pagination } from './pagination.model';
+/** Constant representing the default number of items per page. */
+const DEFAULT_ITEMS_PER_PAGE = 10;
+interface CurrentShowing {
+ from: number;
+ to: number;
+ of: number;
+};
/**
* The component that is used to provide navigation between paged information.
* ```html
@@ -41,7 +55,8 @@ import { Pagination } from './pagination.model';
],
encapsulation: ViewEncapsulation.None,
styleUrls: ['./pagination.component.scss'],
- changeDetection: ChangeDetectionStrategy.OnPush
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ preserveWhitespaces: true
})
export class PaginationComponent implements OnChanges, OnInit {
/** Represents the total number of items. */
@@ -50,22 +65,57 @@ export class PaginationComponent implements OnChanges, OnInit {
/** Represents the current page number. */
@Input()
- currentPage: number;
+ get currentPage(): number {
+ return this._currentPage;
+ };
+ set currentPage(value: number) {
+ this._currentPage = coerceNumberProperty(value, 1);
+ };
/** Represents the number of items per page. */
@Input()
- itemsPerPage: number;
+ get itemsPerPage(): number {
+ return this._itemsPerPage;
+ }
+ set itemsPerPage(value: number) {
+ this._itemsPerPage = Math.min(coerceNumberProperty(value, DEFAULT_ITEMS_PER_PAGE), this.totalItems);
+ }
+
+ /**
+ * The custom template show range of item by current page of items.
+ * It has higher priority than `itemsPerPageOptions` property.
+ */
+ @Input()
+ itemsPerPageTemplate: TemplateRef;
+
+ /** Label for options for items per page. */
+ @Input()
+ itemsPerPageLabel = 'Results per page';
+
+ /** Represents the options for items per page. */
+ @Input()
+ get itemsPerPageOptions(): number[] {
+ return this._itemsPerPageOptions;
+ }
+ set itemsPerPageOptions(value: number[]) {
+ this._itemsPerPageOptions = coerceArray(value)
+ .filter(v => v > 0 && v < this.totalItems)
+ .sort((a, b) => a - b);
+ if (this._itemsPerPageOptions.some(v => v !== this.itemsPerPage)) {
+ this.itemsPerPage = this._itemsPerPageOptions[0];
+ }
+ }
/** Whether to display the total number of items. */
@Input()
displayTotalItems = true;
/**
- * The text appended to the total number of items.
- * The default text is set to 'items'
+ * The template show range of item by current page of items.
+ * Default view: Showing {{ from }}-{{ to }} of {{ of }}
*/
@Input()
- displayText = 'items';
+ displayTextTemplate: TemplateRef;
/** Label for the 'previous' page button. */
@Input()
@@ -83,17 +133,51 @@ export class PaginationComponent implements OnChanges, OnInit {
rtl = false;
/** @hidden */
- get customClasses(): string {
+ get rtlClass(): string {
return this.rtl ? 'fd-pagination__total--rtl' : '';
}
/** @hidden */
- pages$: BehaviorSubject = new BehaviorSubject([]);
+ pages: number[] = [];
+ /** @hidden */
+ get isFirstPage(): boolean {
+ return this.currentPage === 1;
+ };
+ get isLastPage(): boolean {
+ return this.currentPage === this.paginationService.getTotalPages(this.getPaginationObject());
+ };
- isLastPage$: BehaviorSubject = new BehaviorSubject(this._isLastPage);
+ get currentShowing(): CurrentShowing {
+ return this._currentShowing;
+ };
+ /** @hidden */
+ private _currentShowing: CurrentShowing = {
+ from: 0,
+ to: 0,
+ of: 0
+ };
+ /** @hidden */
+ private _itemsPerPage: number = DEFAULT_ITEMS_PER_PAGE;
+ /** @hidden */
+ private _itemsPerPageOptions: number[];
+ /** @hidden */
+ private _currentPage = 1;
+
+ /** @hidden */
+ constructor (
+ private readonly paginationService: PaginationService,
+ @Optional() private readonly rtlService: RtlService
+ ) {}
/** @hidden */
- constructor(private paginationService: PaginationService, @Optional() private rtlService: RtlService) {}
+ onChangePerPage = (event: number) => {
+ this.itemsPerPage = event;
+ this._refreshPages();
+ const maxPage = this.pages[this.pages.length - 1];
+ if (this.currentPage > maxPage) {
+ this.pageChangeStart.emit(maxPage);
+ }
+ };
/** @hidden */
ngOnChanges(changes: SimpleChanges): void {
@@ -103,14 +187,13 @@ export class PaginationComponent implements OnChanges, OnInit {
this._refreshPages();
- const totalPages = this.paginationService.getTotalPages(this.getPaginationObject());
+ const pagination = this.getPaginationObject();
+ const totalPages = this.paginationService.getTotalPages(pagination);
if (!this.currentPage || this.currentPage < 1) {
this.currentPage = 1;
} else if (this.currentPage > totalPages) {
this.currentPage = totalPages;
}
-
- this.isLastPage$.next(this._isLastPage);
}
/** @hidden */
@@ -129,7 +212,7 @@ export class PaginationComponent implements OnChanges, OnInit {
* @param $event The keyboard event.
*/
onKeypressHandler(page: number, $event: KeyboardEvent): void {
- if ($event.key === ' ' || $event.key === 'Enter') {
+ if (KeyUtil.isKeyCode($event, SPACE) || KeyUtil.isKeyCode($event, ENTER)) {
$event.preventDefault();
this.goToPage(page);
}
@@ -147,12 +230,25 @@ export class PaginationComponent implements OnChanges, OnInit {
if (page > this.paginationService.getTotalPages(this.getPaginationObject()) || page < 1) {
return;
}
-
this._refreshPages();
this.pageChangeStart.emit(page);
}
+ /**
+ * Navigates to a previous page.
+ */
+ previousPage(): void {
+ this.goToPage(this.currentPage - 1);
+ }
+
+ /**
+ * Navigates to a next page.
+ */
+ nextPage(): void {
+ this.goToPage(this.currentPage + 1);
+ }
+
/**
* Retrieves an object that represents
* the total number of items, the current page, and the number of items per page.
@@ -167,13 +263,15 @@ export class PaginationComponent implements OnChanges, OnInit {
/** @hidden */
private _refreshPages(): void {
- let pages = this.paginationService.getPages(this.getPaginationObject());
- pages = this.rtl ? pages.slice().reverse() : pages;
- this.pages$.next(pages);
- }
+ const pagination = this.getPaginationObject();
+ let pages = this.paginationService.getPages(pagination);
+ if (this.rtl) {
+ pages = pages.slice().reverse();
+ }
+ this.pages = pages;
- /** @hidden */
- private get _isLastPage(): boolean {
- return this.currentPage === this.paginationService.getTotalPages(this.getPaginationObject());
+ this._currentShowing.from = this.currentPage - 1 === 0 ? 1 : (this.currentPage - 1) * pagination.itemsPerPage + 1;
+ this._currentShowing.to = Math.min((this.currentPage - 1) * pagination.itemsPerPage + pagination.itemsPerPage, this.totalItems);
+ this._currentShowing.of = this.totalItems;
}
}
diff --git a/libs/core/src/lib/pagination/pagination.module.ts b/libs/core/src/lib/pagination/pagination.module.ts
index cf223650e03..1bcd56af1ef 100644
--- a/libs/core/src/lib/pagination/pagination.module.ts
+++ b/libs/core/src/lib/pagination/pagination.module.ts
@@ -4,11 +4,12 @@ import { CommonModule } from '@angular/common';
import { PaginationComponent } from './pagination.component';
import { ButtonModule } from '../button/button.module';
import { IconModule } from '../icon/icon.module';
+import { SelectModule } from '../select/select.module';
import { PaginationService } from './pagination.service';
@NgModule({
declarations: [PaginationComponent],
- imports: [CommonModule, ButtonModule, IconModule],
+ imports: [CommonModule, ButtonModule, IconModule, SelectModule],
providers: [PaginationService],
exports: [PaginationComponent]
})
diff --git a/libs/core/src/lib/pagination/pagination.service.spec.ts b/libs/core/src/lib/pagination/pagination.service.spec.ts
index 9dd1faa35e2..3e79f9152f8 100644
--- a/libs/core/src/lib/pagination/pagination.service.spec.ts
+++ b/libs/core/src/lib/pagination/pagination.service.spec.ts
@@ -1,4 +1,4 @@
-import { TestBed, inject } from '@angular/core/testing';
+import { TestBed } from '@angular/core/testing';
import { PaginationService } from './pagination.service';
import { Pagination } from './pagination.model';
@@ -9,7 +9,7 @@ describe('PaginationService', () => {
TestBed.configureTestingModule({
providers: [PaginationService]
});
- service = TestBed.get(PaginationService);
+ service = TestBed.inject(PaginationService);
});
it('should be created', () => {
@@ -17,7 +17,7 @@ describe('PaginationService', () => {
});
it('should default to 10 pages per page', () => {
- const pages = service.getPages({ totalItems: 10, itemsPerPage: null });
+ const pages = service.getPages({ totalItems: 10, itemsPerPage: 10 });
expect(pages.length).toEqual(1);
});
@@ -42,22 +42,6 @@ describe('PaginationService', () => {
expect(total).toEqual(3);
});
- it('should default to 10 items per page', () => {
- const pagination: Pagination = {
- totalItems: 10
- };
- service.validate(pagination);
- expect(pagination.itemsPerPage).toEqual(service.DEFAULT_ITEMS_PER_PAGE);
- });
-
- it('should default to first page', () => {
- const pagination: Pagination = {
- totalItems: 10
- };
- service.validate(pagination);
- expect(pagination.currentPage).toEqual(1);
- });
-
it('should calc 3 pages', () => {
const pagination: Pagination = {
totalItems: 30,
@@ -69,11 +53,11 @@ describe('PaginationService', () => {
it('should have one dots section', () => {
const pagination: Pagination = {
- totalItems: 60,
+ totalItems: 100,
itemsPerPage: 10
};
const pages = service.getPages(pagination);
- expect(pages[3]).toEqual(service.MORE);
+ expect(pages[3]).toEqual(service.buffer);
});
it('should have two dots sections', () => {
@@ -83,8 +67,8 @@ describe('PaginationService', () => {
currentPage: 4
};
const pages = service.getPages(pagination);
- expect(pages[1]).toEqual(service.MORE);
- expect(pages[5]).toEqual(service.MORE);
+ expect(pages[1]).toEqual(service.buffer);
+ expect(pages[5]).toEqual(service.buffer);
});
it('should not have two dots sections if second to last page is currentPage', () => {
@@ -94,8 +78,8 @@ describe('PaginationService', () => {
currentPage: 73
};
const pages = service.getPages(pagination);
- expect(pages[1]).toEqual(service.MORE);
- expect(pages[5]).not.toEqual(service.MORE);
+ expect(pages[1]).toEqual(service.buffer);
+ expect(pages[5]).not.toEqual(service.buffer);
expect(pages[5]).toEqual(75);
});
});
diff --git a/libs/core/src/lib/pagination/pagination.service.ts b/libs/core/src/lib/pagination/pagination.service.ts
index 318b7bf7917..8fb94f3752f 100644
--- a/libs/core/src/lib/pagination/pagination.service.ts
+++ b/libs/core/src/lib/pagination/pagination.service.ts
@@ -1,7 +1,10 @@
import { Injectable, isDevMode } from '@angular/core';
+
import { Pagination } from './pagination.model';
-const DISPLAY_NUM_PAGES = 3;
+/** Constant representing the number of pages which appear before and after current page. */
+const SIDE_CURRENT_DISPLAY_PAGES = 1;
+const MIN_CORNER_DISPLAY_PAGES = 2;
/**
* Service that is used to retrieve all the pages,
@@ -10,62 +13,51 @@ const DISPLAY_NUM_PAGES = 3;
*/
@Injectable()
export class PaginationService {
- /** Constant representing the default number of items per page. */
- public DEFAULT_ITEMS_PER_PAGE = 10;
-
- /** @hidden */
- public MORE = -1;
-
/** @hidden */
- constructor() {}
-
+ buffer = -1;
/**
* Returns a number array representing the pages of the pagination object.
* @param pagination An object of type *Pagination*.
*/
- public getPages(pagination: Pagination): number[] {
+ getPages(pagination: Pagination): number[] {
+ if (!pagination.currentPage) {
+ pagination.currentPage = 1;
+ }
const pages = [];
this.validate(pagination);
const totalPages = this.getTotalPages(pagination);
-
- if (totalPages <= DISPLAY_NUM_PAGES) {
+ if (totalPages <= SIDE_CURRENT_DISPLAY_PAGES * 2 + MIN_CORNER_DISPLAY_PAGES + 1 + 2 ) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
- if (pagination.currentPage <= DISPLAY_NUM_PAGES) {
- for (let i = 1; i <= DISPLAY_NUM_PAGES; i++) {
+ for (let i = 1; i <= totalPages; i++) {
+ if (i === pagination.currentPage) {
pages.push(i);
- }
- if (totalPages !== DISPLAY_NUM_PAGES + 1 && totalPages !== DISPLAY_NUM_PAGES + 2) {
- pages.push(this.MORE);
- } else if (totalPages === DISPLAY_NUM_PAGES + 2) {
- pages.push(DISPLAY_NUM_PAGES + 1);
- }
- pages.push(totalPages);
- } else if (pagination.currentPage > totalPages - (DISPLAY_NUM_PAGES - 1)) {
- pages.push(1);
- if (totalPages !== DISPLAY_NUM_PAGES + 1 && totalPages !== DISPLAY_NUM_PAGES + 2) {
- pages.push(this.MORE);
- } else if (totalPages === DISPLAY_NUM_PAGES + 2) {
- pages.push(DISPLAY_NUM_PAGES - 1);
- }
- for (let i = totalPages - (DISPLAY_NUM_PAGES - 1); i <= totalPages; i++) {
+ } else if (pagination.currentPage <= SIDE_CURRENT_DISPLAY_PAGES
+ && i <= MIN_CORNER_DISPLAY_PAGES + 1) {
pages.push(i);
- }
- } else {
- pages.push(1);
- if (totalPages !== DISPLAY_NUM_PAGES + 1) {
- pages.push(this.MORE);
- }
- const buffer = Math.floor(DISPLAY_NUM_PAGES / 2);
- for (let i = pagination.currentPage - buffer; i <= pagination.currentPage + buffer; i++) {
+ } else if (pagination.currentPage >= totalPages - SIDE_CURRENT_DISPLAY_PAGES
+ && i >= totalPages - MIN_CORNER_DISPLAY_PAGES) {
pages.push(i);
+ } else {
+ if (i === 1) {
+ pages.push(i);
+ } else if (i === totalPages) {
+ pages.push(i);
+ }
+ // tslint:disable-next-line
+ else if (i >= pagination.currentPage - SIDE_CURRENT_DISPLAY_PAGES
+ && i < pagination.currentPage + SIDE_CURRENT_DISPLAY_PAGES + 1) {
+ pages.push(i);
+ }
}
- if (totalPages !== DISPLAY_NUM_PAGES + 1 && pagination.currentPage !== totalPages - 2) {
- pages.push(this.MORE);
- }
- pages.push(totalPages);
+ }
+ if (pagination.currentPage > SIDE_CURRENT_DISPLAY_PAGES + 2) {
+ pages.splice(1, 0, this.buffer);
+ }
+ if (pagination.currentPage < totalPages - (SIDE_CURRENT_DISPLAY_PAGES + 1)) {
+ pages.splice(pages.length - 1, 0, this.buffer);
}
}
return pages;
@@ -75,10 +67,7 @@ export class PaginationService {
* Retrieves the total number of pages.
* @param pagination An object of type *Pagination*.
*/
- public getTotalPages(pagination: Pagination): number {
- if (pagination.itemsPerPage <= 0) {
- pagination.itemsPerPage = this.DEFAULT_ITEMS_PER_PAGE;
- }
+ getTotalPages(pagination: Pagination): number {
return Math.ceil(pagination.totalItems / pagination.itemsPerPage);
}
@@ -86,17 +75,17 @@ export class PaginationService {
* Provides validation for the pagination object.
* @param pagination An object of type *Pagination*.
*/
- public validate(pagination: Pagination): void {
- if (!pagination.totalItems && isDevMode()) {
- console.warn(`No pages provided in the Pagination object. This warning only appears in development mode.`);
- }
- if (!pagination.itemsPerPage) {
- pagination.itemsPerPage = this.DEFAULT_ITEMS_PER_PAGE;
- } else if (pagination.itemsPerPage < 0 && isDevMode()) {
- console.warn(`itemsPerPage must be greater than zero. This warning only appears in development mode.`);
- }
- if (!pagination.currentPage) {
- pagination.currentPage = 1;
+ validate(pagination: Pagination): void {
+ if (isDevMode()) {
+ if (isNaN(pagination.totalItems) && !pagination.totalItems) {
+ console.warn(`No pages provided in the Pagination object. This warning only appears in development mode.`);
+ }
+ if (isNaN(pagination.itemsPerPage) && pagination.itemsPerPage <= 0) {
+ console.warn(`itemsPerPage must be greater than zero. This warning only appears in development mode.`);
+ }
+ if (!pagination.currentPage) {
+ pagination.currentPage = 1;
+ }
}
}
}