ngx-table-pagination v1.1.5
Pagination for Angular 
The all featured solution for pagination in Angular.
Table of Contents
- Demo
- Quick Start
- Simple Example
- API
- Styling
- Server-Side Paging
- Multiple Instances
- FAQ
- Building from source
- Building the docs
- License
Demo
Play with it on StackBlitz here: https://stackblitz.com/edit/ngx-table-pagination-example
Quick Start
npm install ngx-table-pagination --saveAngular Version
This library is built to work with Angular 5+, and support ahead-of-time compilation. If you need to support an earlier or pre-release version of Angular for now, please see the changelog for advice on which version to use.
Module Format
This library ships as a "flat ES module" (FESM). This means that all the JavaScript code is located in a single ES5-compatible file, but makes use of ES2015 import and export statements.
Webpack, Systemjs and Rollup all support this format and should work without problems.
A UMD bundle is also provided for systems which do not support FESM.
Simple Example
// app.module.ts
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {NgxTablePaginationModule} from 'ngx-table-pagination'; // <-- import the module
import {MyComponent} from './my.component';
@NgModule({
imports: [BrowserModule, NgxTablePaginationModule], // <-- include it in your app module
declarations: [MyComponent],
bootstrap: [MyComponent]
})
export class MyAppModule {}// my.component.ts
import {Component} from '@angular/core';
@Component({
selector: 'my-component',
template: `
<paging-controls [isItemsPerPage]="true" ></paging-controls>
<ul>
<li *ngFor="let item of collection | paginate: { currentPage: p }"> ... </li>
</ul>
<paging-controls [isItemsPerPage]="false" (pageChange)="p = $event"></paging-controls>
`
})
export class MyComponent {
p: number = 1;
collection: any[] = someArrayOfThings;
}API
PaginatePipe
The PaginatePipe should be placed at the end of an NgFor expression. It accepts a single argument, an object conforming
to the PaginationInstance interface. The following config options are available:
<some-element *ngFor="let item of collection | paginate: { id: 'foo',
itemsPerPage:10
currentPage: p,
totalItems: total }">...</some-element>currentPagenumber- required The current (active) page number.itemsPerPagenumber- The number of items to display on each page (default is 5).idstringIf you need to support more than one instance of pagination at a time, set theidand ensure it matches the id attribute of thePaginationControlsComponent/PaginationControlsDirective(see below).totalItemsnumberThe total number of items in the collection. Only useful when doing server-side paging, where the collection size is limited to a single page returned by the server API. For in-memory paging, this property should not be set, as it will be automatically set to the value ofcollection.length.
PaginationControlsComponent
This a default component for displaying pagination controls. It is implemented on top of the PaginationControlsDirective, and has a pre-set
template and styles based on the Foundation 6 pagination component. If you require a more
customised set of controls, you will need to use the PaginationControlsDirective and implement your own component.
<paging-controls id="some_id"
(pageChange)="pageChanged($event)"
(pageBoundsCorrection)="pageChanged($event)"
maxSize="9"
directionLinks="true"
autoHide="true"
responsive="true"
previousLabel="Previous"
nextLabel="Next"
screenReaderPaginationLabel="Pagination"
screenReaderPageLabel="page"
screenReaderCurrentLabel="You're on page">
</paging-controls>idstringIf you need to support more than one instance of pagination at a time, set theidand ensure it matches the id set in the PaginatePipe config.pageChangeevent handlerThe expression specified will be invoked whenever the page changes via a click on one of the pagination controls. The$eventargument will be the number of the new page. This should be used to update the value of thecurrentPagevariable which was passed to thePaginatePipe.pageBoundsCorrectionevent handlerThe expression specified will be invoked when thecurrentPagevalue is found to be out-of-bounds (e.g. the collection size was reduced). The$eventargument will be the number of the closest valid page.maxSizenumberDefines the maximum number of page links to display. Default is7.directionLinksbooleanIf set tofalse, the "previous" and "next" links will not be displayed. Default istrue.autoHidebooleanIf set totrue, the pagination controls will not be displayed when all items in the collection fit onto the first page. Default isfalse.responsivebooleanIf set totrue, individual page links will not be displayed on small screens. Default isfalse.previousLabelstringThe label displayed on the "previous" link.nextLabelstringThe label displayed on the "next" link.screenReaderPaginationLabelstringThe word for "Pagination" used to label the controls for screen readers.screenReaderPageLabelstringThe word for "page" used in certain strings generated for screen readers, e.g. "Next page".screenReaderCurrentLabelstringThe phrase indicating the current page for screen readers, e.g. "You're on page ".
PaginationControlsDirective
The PaginationControlsDirective is used to build components for controlling your pagination instances. The directive selector is pagination-template, either as an element or an attribute.
It exports an API named "paginationApi", which can then be used to build the controls component.
It has the following inputs and outputs:
@Input() id: string;
@Input() maxSize: number;
@Output() pageChange: EventEmitter<number>;
@Output() pageBoundsCorrection: EventEmitter<number>;Here is an example of how it would be used to build a custom component:
<pagination-template
#p="paginationApi"
[id]="id"
[maxSize]="maxSize"
(pageChange)="pageChange.emit($event)"
(pageBoundsCorrection)="pageBoundsCorrection.emit($event)"
>
<div *ngIf="!(autoHide && p.pages.length <= 1)">
<div class="items-number" *ngIf="isItemsPerPage">
<span style="display: flex" class="pagination-font">
<label class="show-label">Show</label>
<select
class="no-padding pagination-font"
[(ngModel)]="p.itemsPerPage"
(change)="p.pageSizeChanged($event.target.value)"
>
<option
*ngFor="let pageSizeDefault of p.pageSizes"
value="{{ pageSizeDefault }}"
[selected]="pageSizeDefault == p.itemsPerPage"
>
{{ pageSizeDefault }}
</option>
</select>
<label class="entries-label">entries</label></span
>
</div>
<div
class="ngx-pagination pagination-font"
role="navigation"
*ngIf="!isItemsPerPage"
[attr.aria-label]="screenReaderPaginationLabel"
[class.responsive]="responsive"
>
<label
>Showing {{ p.getStartIndex() }} - {{ p.getEndIndex() }} of
{{ p.getTotalItems() }} entries</label
>
<ul role="navigation" class="">
<li
class="pagination-previous pagination-font"
[class.disabled]="p.isFirstPage()"
*ngIf="directionLinks"
>
<a
tabindex="0"
*ngIf="1 < p.getCurrent()"
(keyup.enter)="p.previous()"
(click)="p.previous()"
[attr.aria-label]="previousLabel + ' ' + screenReaderPageLabel"
>
{{ previousLabel }}
</a>
<span *ngIf="p.isFirstPage()">
{{ previousLabel }}
</span>
</li>
<li class="small-screen pagination-font">
{{ p.getCurrent() }} / {{ p.getLastPage() }}
</li>
<li
class="pagination-font"
[class.current]="p.getCurrent() === page.value"
[class.ellipsis]="page.label === '...'"
*ngFor="let page of p.pages"
>
<a
tabindex="0"
(keyup.enter)="p.setCurrent(page.value)"
(click)="p.setCurrent(page.value)"
*ngIf="p.getCurrent() !== page.value"
>
<span class="show-for-sr">{{ screenReaderPageLabel }} </span>
<span>{{
page.label === "..." ? page.label : (page.label | number: "")
}}</span>
</a>
<ng-container *ngIf="p.getCurrent() === page.value">
<span class="show-for-sr">{{ screenReaderCurrentLabel }} </span>
<span>{{
page.label === "..." ? page.label : (page.label | number: "")
}}</span>
</ng-container>
</li>
<li
class="pagination-next pagination-font"
[class.disabled]="p.isLastPage()"
*ngIf="directionLinks"
>
<a
tabindex="0"
*ngIf="!p.isLastPage()"
(keyup.enter)="p.next()"
(click)="p.next()"
[attr.aria-label]="nextLabel + ' ' + screenReaderPageLabel"
>
{{ nextLabel }}
</a>
<span *ngIf="p.isLastPage()">
{{ nextLabel }}
</span>
</li>
</ul>
</div>
</div>
</pagination-template>The key thing to note here is #p="paginationApi" - this provides a local variable, p (name it however you like), which can be used in the
template to access the directive's API methods and properties, which are explained below:
pages[{ label: string, value: any }[]] Array of page objects containing the page number and label.maxSizenumberCorresponds to the value ofmaxSizewhich is passed to the directive.getCurrent()() => numberReturns the current page number.setCurrent(val)(val: number) => voidTriggers thepageChangeevent with the page number passed asval.previous()() => voidSets current page to previous, triggering thepageChangeevent.next()() => voidSets current page to next, triggering thepageChangeevent.isFirstPage()() => booleanReturns true if the current page is the first page.isLastPage()() => booleanReturns true if the current page is the last pagegetLastPage()() => numberReturns the page number of the last page.getTotalItems()() => numberReturns the total number of items in the collection.
For a real-world implementation of a custom component, take a look at the source for the PaginationControlsComponent.
Styling
The PaginationControlsComponent can be styled by simply overriding the default styles. To overcome Angular's view encapsulation, you may need to use the /deep/ operator to target it (depending on the type of encapsulation your component is using).
To avoid specificity issues, just add your own custom class name to the element, which will allow your styles to override the defaults:
// head
<style>
.my-pagination /deep/ .ngx-pagination .current {
background: red;
}
</style>
// body
<paging-controls class="my-pagination"><paging-controls>Server-Side Paging
In many cases - for example when working with very large data-sets - we do not want to work with the full collection in memory, and use some kind of server-side paging, where the server sends just a single page at a time.
This scenario is supported by ngx-pagination by using the totalItems config option.
Given a server response json object like this:
{
"count": 14453,
"data": [
{ /* item 1 */ },
{ /* item 2 */ },
{ /* item 3 */ },
{ /* ... */ },
{ /* item 10 */ }
]
}we should pass the value of count to the PaginatePipe as the totalItems argument:
<li *ngFor="let item of collection | paginate: { currentPage: p, totalItems: res.count }">...</li>This will allow the correct number of page links to be calculated. To see a complete example of this (including
using the async pipe), see the demo.
Multiple Instances
It is possible to have any number of pagination pipe/controls pairs in the same template. To do this, just make use of the "id" attribute:
<paging-controls id="first" [isItemsPerPage]="true"></paging-controls>
<ul>
<li *ngFor="let item of collection | paginate: { currentPage: p1, id: 'first' }"> ... </li>
</ul>
<paging-controls (pageChange)="p1 = $event" id="first" [isItemsPerPage]="false"></paging-controls>
<paging-controls id="second" [isItemsPerPage]="true"></paging-controls>
<ul>
<li *ngFor="let item of collection | paginate: { currentPage: p2, id: 'second' }"> ... </li>
</ul>
<paging-controls (pageChange)="p2 = $event" id="second" [isItemsPerPage]="false"></paging-controls>You can even have dynamically-generated instances, e.g. within an ngFor block:
export class MyComponent {
p: number[] = [];
}<div *ngFor="let id of [1, 2]; let i = index;">
<paging-controls [id]="id" [isItemsPerPage]="true"></paging-controls>
<ul>
<li *ngFor="let item of collection | paginate: { itemsPerPage: 10, currentPage: p[i], id: id }">{{ item }}</li>
</ul>
<paging-controls (pageChange)="p[i] = $event" [id]="id" [isItemsPerPage]="false"></paging-controls>
</div>FAQ
Why does my filter not work with pagination?
A common issue is that people have trouble combining some kind of filter pipe with the paginate pipe. The typical symptom is that only the contents of the current page are filtered. The reason is that the paginate pipe must come after the filter pipe:
<ul>
<li *ngFor="let item of collection | paginate: config | filter: queryString">WRONG</li> <-- This will not work as expected
</ul>
<ul>
<li *ngFor="let item of collection | filter: queryString | paginate: config">CORRECT</li>
</ul>How do I use the ngFor index with the pagination pipe?
If you need to use the index of the *ngFor in combination with pagination pipe, the index should be declared after the pagination pipe:
<ul>
<li *ngFor="let item of collection; let i = index | paginate: config">WRONG</li>
</ul>
<ul>
<li *ngFor="let item of collection | paginate: config; let i = index">CORRECT</li>
</ul>How do I get the absolute index of a list item?
Using the index variable exposed by ngFor will always give you the index of the items relative to the current page. For example, if you have 10 items per page, you might expect the first item on page 2 to have an index value of 10, whereas you will find the index value to be 0. This is because ngFor has no knowledge of the pagination, it only ever knows about the 10 items of the current page.
However, the absolute index can be calculated according to the following formula:
absoluteIndex(indexOnPage: number): number {
return this.itemsPerPage * (this.currentPage - 1) + indexOnPage;
}In a template this would look something like:
<ul>
<li *ngFor="let item of collection | paginate: { currentPage: currentPage, itemsPerPage: itemsPerPage }; let i = index">
{{ itemsPerPage * (currentPage - 1) + i }}
</li>
</ul>Building from source
Requires globally-installed node (tested with v5.x) & npm.
npm install
npm run test
npm run buildtest runs the Karma tests once. You can also use test:watch to keep tests running in watch mode.
npm run build creates an intermediate /build folder, but the final output of the lib (which gets published to npm) is in the /dist folder.
Building the docs
cd docs
npm install
npm run docs:watch // dev mode
npm run docs:dist // production modeWhen in dev mode, serve the /docs folder with an http server, and go to http://localhost:<port>/index-dev.html in your browser.
License
MIT