/*
* © 2017 Stratio Big Data Inc., Sucursal en España.
*
* This software is licensed under the Apache License, Version 2.0.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the terms of the License for more details.
*
* SPDX-License-Identifier: Apache-2.0.
*/
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output
} from '@angular/core';
import { StDropDownMenuItem } from '../st-dropdown-menu/st-dropdown-menu.interface';
import { Paginate, PaginateIconClasses, PaginateOptions, PaginateTexts } from './st-pagination.interface';
/**
* @description {Component} [Table]
*
* The pagination component has been designed to allow content to be displayed per pages. This informs user about the
* number of the current page, the items displayed per page and the total of items. Moreover, when there are a lot of
* items, it allows user to customize the number of items displayed per page.
*
* It is made by two sub-components:
* - A range selector, that allows the user provides a dropdown to set how many items he wants to be displayed per page.
* - A page navigation control, in order to let the user where he is and where he can go to.
*
* * @model
*
* [Paginate] {./st-pagination.interface.ts#Paginate}
* [PaginateOptions] {./st-pagination.interface.ts#PaginateOptions}
* [PaginateTexts] {./st-pagination.interface.ts#PaginateTexts}
* [PaginateTextsSchema] {./st-pagination.interface.ts#PaginateTextsSchema}
* [PaginateIconClasses] {./st-pagination.interface.ts#PaginateIconClasses}
*
* @example
*
* {html}
*
* ```
*
* ```
*
*/
@Component({
selector: 'st-pagination',
templateUrl: './st-pagination.component.html',
styleUrls: ['./st-pagination.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StPaginationComponent implements OnInit {
/** @Input {PaginateTexts} [label={element: 'Rows', perPage: 'per page', of: 'of'}] Translated texts displayed at the pagination */
@Input() label: PaginateTexts = {
element: 'Rows', perPage: 'per page', of: 'of'
};
/** @Input {PaginateOptions[]}
* [perPageOptions=Array( Object( value: 20, showFrom: 0 ),Object( value: 50, showFrom: 50 ), Object( value: 200, showFrom: 200 ))]
* List of options displayed at a selector where user can change the number of items displayed per page
*/
@Input() perPageOptions: PaginateOptions[] = [
{ value: 20, showFrom: 0 }, { value: 50, showFrom: 50 }, { value: 200, showFrom: 200 }
];
/** @Input {PaginateIconClasses} [iconClasses=Object(previous='', next='')] Icon classes for previous and next page buttons */
@Input() iconClasses: PaginateIconClasses = { previous: 'icon-arrow2_left', next: 'icon-arrow2_right' };
/** @Output {Paginate} [change=''] Event emitted when user interacts with some of the elements in the pagination.
* This sends the new pagination status (current page and items per page)
*/
@Output() change: EventEmitter = new EventEmitter();
/** @Output {PaginateOptions} [changePerPage=''] Event emitted when user interacts with some of the elements in the selector of items displayed per page.
* This sends the current items per page.
*/
@Output() changePerPage: EventEmitter = new EventEmitter();
/** @Input {number} [currentPage=1] Number of the current page */
@Input()
get currentPage(): number {
return this._currentPage;
}
set currentPage(currentPage: number) {
this._currentPage = currentPage;
this.updatePages(false);
}
/** @Input {number} [perPage=20] The maximum number of items displayed per page */
@Input()
get perPage(): number {
return this._perPage;
}
set perPage(perPage: number) {
this.onChangePerPage(perPage, false);
}
/** @Input {number} [total=''] Total of items */
@Input()
get total(): number {
return this._total;
}
set total(total: number) {
this._total = total;
this.generateItems();
this.updatePages(false);
}
public disableNextButton: boolean = false;
public disablePrevButton: boolean = true;
public firstItem: number;
public lastItem: number;
public items: StDropDownMenuItem[] = [];
public selectedItem: StDropDownMenuItem;
private _currentPage: number = 1;
private _perPage: number = 20;
private _total: number;
constructor(private _cd: ChangeDetectorRef,
private _paginationElement: ElementRef) {
}
get hasOptions(): boolean {
return this.items && this.items.length > 1;
}
get paginationId(): string | null {
const pagination: HTMLElement = this._paginationElement.nativeElement;
return pagination.getAttribute('id') !== null ? pagination.id : null;
}
get selectId(): string {
return this.paginationId !== null ? `${this.paginationId}-select` : null;
}
get buttonPrevId(): string {
return this.paginationId !== null ? `${this.paginationId}-prev` : null;
}
get buttonNextId(): string {
return this.paginationId !== null ? `${this.paginationId}-next` : null;
}
ngOnInit(): void {
this.updatePages(false);
this.generateItems();
}
generateItems(): void {
this.items = [];
this.perPageOptions.forEach(this.addPageOption.bind(this));
if (this.items.length) {
this.selectedItem = this.items.find(item => item.value === this._perPage) || this.items[0];
}
this._cd.markForCheck();
}
nextPage(): void {
this.currentPage++;
this.updatePages();
}
prevPage(): void {
this.currentPage--;
this.updatePages();
}
onChangePerPage(perPage: number, emit: boolean = true): void {
if (perPage && typeof perPage === 'number') {
this._currentPage = 1;
this._perPage = perPage;
this.updatePages(emit);
this.selectedItem = this.items.find(item => item.value === this._perPage);
if (emit) {
this.changePerPage.emit(this._perPage);
}
}
}
private addPageOption(option: PaginateOptions): void {
if (this._total && (!option.showFrom || option.showFrom <= this._total)) {
this.items.push({
label: `${option.value}`,
value: option.value
});
}
}
private updatePages(emit: boolean = true): void {
this.lastItem = this._perPage * this._currentPage;
if (this._currentPage === 1) {
this.firstItem = this._currentPage;
this.disablePrevButton = true;
} else {
this.firstItem = this._perPage * (this._currentPage - 1) + 1;
this.disablePrevButton = false;
}
if (this.lastItem >= this._total) {
this.lastItem = this._total;
this.disableNextButton = true;
} else {
this.disableNextButton = false;
}
if (emit) {
this.change.emit({
currentPage: this._currentPage,
perPage: this._perPage
});
}
}
}