import { ChangeDetectionStrategy , ChangeDetectorRef , Component , EventEmitter , forwardRef , Input , OnInit , Output , TemplateRef } from '@angular/core' ; import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ; export const PAGINATION_CONTROL_VALUE_ACCESSOR = { provide : NG_VALUE_ACCESSOR , useExisting : forwardRef ( ( ) => PaginationComponent ) , multi : true } ; @ Component ( { selector : 'ux-pagination' , templateUrl : './pagination.component.html' , providers : [ PAGINATION_CONTROL_VALUE_ACCESSOR ] , changeDetection : ChangeDetectionStrategy . OnPush , } ) export class PaginationComponent implements OnInit , ControlValueAccessor { /** Specify if we should show the next and previous buttons */ @ Input ( ) directionButtons : boolean = true ; /** Limit the number of pages shown at any given time */ @ Input ( ) maxSize : number = 5 ; /** Specify if the component should be disabled */ @ Input ( ) disabled : boolean = false ; /** Apply classes to the bootstrap pagination element */ @ Input ( 'class' ) classes : string ; /** Allow custom class to be added to page buttons */ @ Input ( ) pageBtnClass : string ; /** Aria Label for the component navigation */ @ Input ( 'aria-label' ) ariaLabel : string = 'Pagination Navigation' ; /** Aria label for the previous button */ @ Input ( ) previousAriaLabel : string = 'Navigate to the previous page' ; /** Aria label for the next button */ @ Input ( ) nextAriaLabel : string = 'Navigate to the next page' ; constructor ( private readonly _changeDetector ) { } /** Specify the index of the active page */ @ Input ( ) set page ( page ) { if ( page === this . _page ) { return ; } this . _page = page ; this . pages = this . getPages ( ) ; this . onChange ( this . page ) ; } get page ( ) : number { return this . _page ; } /** Define a custom template for the previous button */ @ Input ( ) previousBtnTemplate : TemplateRef < any > ; /** Define a custom template for the next button */ @ Input ( ) nextBtnTemplate : TemplateRef < any > ; /** Specify the page size */ @ Input ( ) set itemsPerPage ( pagesize ) { this . _pagesize = pagesize ; this . pages = this . getPages ( ) ; } /** Specify how many items there are in total */ @ Input ( ) set totalItems ( total ) { this . _total = total ; this . pages = this . getPages ( ) ; } /** Emit the current page number */ @ Output ( ) pageChange = new EventEmitter < number > ( ) ; /** Emit the total number of pages */ @ Output ( ) numPages = new EventEmitter < number > ( ) ; /** Store a list of pages to display in the UI */ pages : ReadonlyArray < Page > = [ ] ; /** ControlValueAccessor functions */ onTouched : Function = ( ) => { } ; onChange : Function = ( ) => { } ; isKeyboardEvent : boolean = false ; private _page : number = 1 ; private _total : number = 100 ; private _pagesize : number = 10 ; get pageCount ( ) : number { return Math . ceil ( this . _total / this . _pagesize ) ; } ngOnInit ( ) { this . pages = this . getPages ( ) ; } select ( index ) { const target = this . pages . find ( page => page . index === index ) ; if ( ! target ) { return ; } this . onTouched ( ) ; this . page = target . index ; this . pages = this . getPages ( ) ; this . pageChange . emit ( this . page ) ; } trackByFn ( _index , item ) { return item . index ; } registerOnChange ( fn ) { this . onChange = fn ; } registerOnTouched ( fn ) { this . onTouched = fn ; } setDisabledState ( isDisabled ) { this . disabled = isDisabled ; this . _changeDetector . markForCheck ( ) ; } writeValue ( page ) { this . page = page ; this . _changeDetector . markForCheck ( ) ; } private getPages ( ) { const pages = [ ] ; for ( let index = 1 ; index <= this . pageCount ; index ++ ) { pages . push ( { index , visible : this . isPageVisible ( index ) } ) ; } this . numPages . emit ( this . pageCount ) ; return pages ; } private isPageVisible ( index ) { if ( ! this . maxSize || this . pageCount <= this . maxSize ) { return true ; } let start = Math . max ( 1 , Math . ceil ( this . page - ( this . maxSize / 2 ) ) ) ; const end = Math . min ( start + this . maxSize , this . pageCount + 1 ) ; const range = end - start ; if ( range < this . maxSize ) { start = start - ( this . maxSize - range ) ; } return index >= start && index < end ; } } export interface Page { index : number ; visible : boolean ; }