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 |
| standalone | true |
| imports |
NgClass
|
| 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 { NgClass } from '@angular/common';
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'],
standalone: true,
imports: [NgClass],
})
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>
@if (showDotMin(page)) {
<li class="disabled">
<button>
<i class="fa-solid fa-ellipsis"></i>
</button>
</li>
}
@for (p of pages; track p) {
@if (canShow(p)) {
<li
[ngClass]="{
active: page === p,
}"
>
<button (click)="handlePageChange(p)">
{{ p }}
</button>
</li>
}
}
@if (showDotMax(page)) {
<li class="disabled">
<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;
}