src/components/sq-pagination/sq-pagination.component.ts
Represents a pagination component for navigating through pages.
Look the link about the component in original framework and the appearance
See https://css.squidit.com.br/components/pagination
Example :<sq-pagination [currentPage]="currentPage" [totalPages]="totalPages" [showPages]="5" (pageChange)="onPageChange($event)"></sq-pagination>
OnInit
OnChanges
OnDestroy
selector | sq-pagination |
styleUrls | ./sq-pagination.component.scss |
templateUrl | ./sq-pagination.component.html |
Properties |
Methods |
Inputs |
Outputs |
constructor(route: ActivatedRoute, router: Router, getWindow: GetWindow, ngZone: NgZone)
|
||||||||||||||||||||
Initializes a new instance of the
Parameters :
|
currentPage | |
Type : number
|
|
Default value : 1
|
|
The current page number. |
customClass | |
Type : string
|
|
Default value : ''
|
|
A custom CSS class for styling the component. |
showPages | |
Type : number
|
|
Default value : 5
|
|
The number of page links to show in the pagination control. |
totalPages | |
Type : number
|
|
Default value : 1
|
|
The total number of pages. |
useQueryString | |
Type : boolean
|
|
Default value : false
|
|
Indicates whether to use query string parameters for page navigation. |
pageChange | |
Type : EventEmitter<number>
|
|
Emits an event when the current page is changed. |
calculateHalf |
calculateHalf()
|
Calculates half of the
Returns :
any
|
createOrDestroyQueryObservable |
createOrDestroyQueryObservable()
|
Creates or destroys the query parameter observable based on the
Returns :
void
|
destroyQueryObservable |
destroyQueryObservable()
|
Destroys the query parameter observable and removes the 'page' query parameter from the URL.
Returns :
void
|
handlePageChange | ||||||||
handlePageChange(newPage: number)
|
||||||||
Handles a page change event and updates the page number.
Parameters :
Returns :
void
|
mountQueryObservable |
mountQueryObservable()
|
Mounts the query parameter observable to track page changes in the URL query string.
Returns :
void
|
ngOnChanges | ||||||||
ngOnChanges(changes: SimpleChanges)
|
||||||||
Responds to changes in input properties.
Parameters :
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Cleans up resources when the component is destroyed.
Returns :
void
|
ngOnInit |
ngOnInit()
|
Initializes the component.
Returns :
void
|
Public getWindow |
Type : GetWindow
|
- The GetWindow service for accessing the window object.
|
page |
Default value : this.currentPage
|
The current page number. |
pages |
Default value : Array.from({ length: this.totalPages }, (_, i) => i + 1)
|
An array of page numbers to display in the pagination control. |
routeObservable |
Type : Subscription
|
A subscription to the route query parameters. |
showDotMax | ||||
Default value : useMemo((actualPage: number) => {
const half = this.calculateHalf()
return actualPage + half < this.totalPages
})
|
||||
Checks if the maximum page number dot should be shown. |
||||
Parameters :
|
showDotMin | ||||
Default value : useMemo((actualPage: number) => {
const half = this.calculateHalf()
return actualPage - half > 1
})
|
||||
Checks if the minimum page number dot should be shown. |
||||
Parameters :
|
import { Component, EventEmitter, Input, NgZone, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'
import { useMemo } from '../../helpers/memo.helper'
import { ActivatedRoute, Router } from '@angular/router'
import { Subscription } from 'rxjs'
import { GetWindow } from '../../helpers/window.helper'
/**
* Represents a pagination component for navigating through pages.
*
* Look the link about the component in original framework and the appearance
*
* @see {@link https://css.squidit.com.br/components/pagination}
*
* <div class='my-3' >
* <ul class="pagination" style='padding: 0; margin: 0;'>
* <li class="disabled">
* <a>
* <i class="fas fa-chevron-left"></i>
* </a>
* </li>
* <li>
* <a>1</a>
* </li>
* <li class='active'>
* <a>2</a>
* </li>
* <li>
* <a>3</a>
* </li>
* <li>
* <a>
* <i class="fas fa-chevron-right"></i>
* </a>
* </li>
* </ul>
* </div>
*
* @example
* <sq-pagination [currentPage]="currentPage" [totalPages]="totalPages" [showPages]="5" (pageChange)="onPageChange($event)"></sq-pagination>
*
* @implements {OnInit, OnChanges, OnDestroy}
*/
@Component({
selector: 'sq-pagination',
templateUrl: './sq-pagination.component.html',
styleUrls: ['./sq-pagination.component.scss']
})
export class SqPaginationComponent implements OnInit, OnChanges, OnDestroy {
/**
* A custom CSS class for styling the component.
*/
@Input() customClass = ''
/**
* The current page number.
*/
@Input() currentPage = 1
/**
* The total number of pages.
*/
@Input() totalPages = 1
/**
* The number of page links to show in the pagination control.
*/
@Input() showPages = 5
/**
* Indicates whether to use query string parameters for page navigation.
*/
@Input() useQueryString = false
/**
* Emits an event when the current page is changed.
*/
@Output() pageChange: EventEmitter<number> = new EventEmitter<number>()
/**
* The current page number.
*/
page = this.currentPage
/**
* An array of page numbers to display in the pagination control.
*/
pages = Array.from({ length: this.totalPages }, (_, i) => i + 1)
/**
* A subscription to the route query parameters.
*/
routeObservable!: Subscription
/**
* Initializes a new instance of the `SqPaginationComponent` class.
* @constructor
* @param {ActivatedRoute} route - The ActivatedRoute service for retrieving route information.
* @param {Router} router - The Router service for programmatic navigation.
* @param {GetWindow} getWindow - The GetWindow service for accessing the window object.
* @param {NgZone} ngZone - The NgZone service for running code outside Angular's zone.
*/
constructor(private route: ActivatedRoute, private router: Router, public getWindow: GetWindow, private ngZone: NgZone) { }
/**
* Initializes the component.
*/
ngOnInit() {
this.createOrDestroyQueryObservable()
}
/**
* Responds to changes in input properties.
*
* @param {SimpleChanges} changes - The changes in input properties.
*/
ngOnChanges(changes: SimpleChanges) {
if (changes['currentPage'] && changes['currentPage'].currentValue !== changes['currentPage'].previousValue) {
this.page = this.currentPage
}
if (changes['totalPages'] && changes['totalPages'].currentValue !== changes['totalPages'].previousValue) {
this.pages = Array.from({ length: this.totalPages }, (_, i) => i + 1)
}
if (changes['useQueryString'] && changes['useQueryString'].currentValue !== changes['useQueryString'].previousValue) {
this.createOrDestroyQueryObservable()
}
}
/**
* Cleans up resources when the component is destroyed.
*/
ngOnDestroy() {
this.destroyQueryObservable()
}
/**
* Creates or destroys the query parameter observable based on the `useQueryString` input.
*/
createOrDestroyQueryObservable() {
if (this.useQueryString) {
this.mountQueryObservable()
} else {
this.destroyQueryObservable()
}
}
/**
* Mounts the query parameter observable to track page changes in the URL query string.
*/
mountQueryObservable() {
this.routeObservable = this.route.queryParams.subscribe(search => {
const searchParams = new URLSearchParams(search)
const newPageQuery = parseInt(searchParams.get('page') ?? '1', 10)
if (newPageQuery !== this.page) {
this.page = newPageQuery
}
})
}
/**
* Destroys the query parameter observable and removes the 'page' query parameter from the URL.
*/
destroyQueryObservable() {
const searchParams = new URLSearchParams(this.getWindow.window()?.location.search)
searchParams.delete('page')
this.ngZone.run(() => {
this.router.navigate([], { relativeTo: this.route, queryParams: { page: null }, queryParamsHandling: 'merge' })
})
this.routeObservable?.unsubscribe()
}
/**
* Checks if a page number should be displayed based on the current page and showPages setting.
*
* @param {number} actualPage - The page number to check.
* @returns {boolean} - `true` if the page should be shown, otherwise `false`.
*/
canShow = useMemo((actualPage: number) => {
const half = this.calculateHalf()
return actualPage === this.page || (actualPage >= this.page - half && actualPage <= this.page + half)
})
/**
* Checks if the maximum page number dot should be shown.
*
* @param {number} actualPage - The page number to check.
* @returns {boolean} - `true` if the dot should be shown, otherwise `false`.
*/
showDotMax = useMemo((actualPage: number) => {
const half = this.calculateHalf()
return actualPage + half < this.totalPages
})
/**
* Checks if the minimum page number dot should be shown.
*
* @param {number} actualPage - The page number to check.
* @returns {boolean} - `true` if the dot should be shown, otherwise `false`.
*/
showDotMin = useMemo((actualPage: number) => {
const half = this.calculateHalf()
return actualPage - half > 1
})
/**
* Calculates half of the `showPages` setting for determining which pages to display.
*/
calculateHalf() {
return Math.floor(this.showPages / 2)
}
/**
* Handles a page change event and updates the page number.
*
* @param {number} newPage - The new page number.
*/
handlePageChange(newPage: number) {
if (newPage < 1 || newPage > this.totalPages) {
return
}
if (this.useQueryString) {
const searchParams = new URLSearchParams(this.getWindow.window()?.location.search)
searchParams.set('page', newPage.toString())
this.ngZone.run(() => {
this.router.navigate([], { relativeTo: this.route, queryParams: { page: newPage }, queryParamsHandling: 'merge' })
})
}
this.page = newPage
this.pageChange.emit(newPage)
}
}
<div class='pagination-wrapper {{ customClass }}'>
<ul class="pagination">
<li class='page-item' [ngClass]="{
'disabled': page === 1,
}">
<button (click)='handlePageChange(page - 1)'>
<i class="fa-solid fa-chevrons-left"></i>
</button>
</li>
<li class="disabled" *ngIf="showDotMin(page)">
<button>
<i class="fa-solid fa-ellipsis"></i>
</button>
</li>
<ng-container *ngFor="let p of pages">
<li
[ngClass]="{
'active': page === p,
}"
*ngIf="canShow(p)"
>
<button (click)='handlePageChange(p)'>
{{ p }}
</button>
</li>
</ng-container>
<li class="disabled" *ngIf="showDotMax(page)">
<button>
<i class="fa-solid fa-ellipsis"></i>
</button>
</li>
<li class='page-item' [ngClass]="{
'disabled': page >= totalPages,
}">
<button (click)='handlePageChange(page + 1)'>
<i class="fa-solid fa-chevrons-right"></i>
</button>
</li>
</ul>
</div>
./sq-pagination.component.scss
.pagination-wrapper {
width: 100%;
text-align: center;
}
.pagination li.active {
color: var(--primary_color);
}
:host {
display: inline-block;
}