Skip to content

Commit

Permalink
feat: pagination with changer, jump to, text links, total number text…
Browse files Browse the repository at this point in the history
… and simple mode
  • Loading branch information
AntoninoBonanno authored Mar 13, 2023
1 parent 84cb4d0 commit 95f9767
Show file tree
Hide file tree
Showing 33 changed files with 715 additions and 43 deletions.
4 changes: 4 additions & 0 deletions projects/design-angular-kit/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@
"close-notification": "Close Notification: {{title}}",
"close-alert": "Close alert",
"page": "Page",
"previous": "Previous",
"previous-page": "Previous page",
"next": "Next",
"next-page": "Next page",
"go-to": "Go to",
"page-of-total": "Page {{page}} of {{total}}",
"progress": "Progress",
"loading": "Loading",
"active": "Active",
Expand Down
4 changes: 4 additions & 0 deletions projects/design-angular-kit/assets/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@
"close-notification": "Chiudi notifica: {{title}}",
"close-alert": "Chiudi avviso",
"page": "Pagina",
"previous": "Precedente",
"previous-page": "Pagina precedente",
"next": "Successiva",
"next-page": "Pagina successiva",
"go-to": "Vai a",
"page-of-total": "Pagina {{page}} di {{total}}",
"progress": "Progresso",
"loading": "Caricamento",
"active": "Attivo",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,83 @@
<nav class="pagination-wrapper"
[class.justify-content-center]="alignment==='center'"
[class.justify-content-end]="alignment==='end'">
<ul class="pagination">
[class.justify-content-end]="alignment==='end'"
[class.pagination-total]="totalNumberText.hasChildNodes()">

<ul *ngIf="pages.length" class="pagination">
<li class="page-item" [class.disabled]="currentPage < 1">
<a class="page-link" (click)="pageChange(currentPage)">
<it-icon name="chevron-left" color="primary"></it-icon>
<span class="visually-hidden">{{'it.core.previous-page'|translate}}</span>
<a class="page-link" [class.text]="isTextLinks" href="#" (click)="pageChange($event, currentPage)">
<it-icon *ngIf="!isTextLinks" name="chevron-left" color="primary"></it-icon>
<span class="visually-hidden">
{{(isTextLinks ? 'it.core.page' : 'it.core.previous-page') | translate}}
</span>
<ng-container *ngIf="isTextLinks">{{'it.core.previous' | translate}}</ng-container>
</a>
</li>

<ng-container *ngIf="pageNumbers > 5 && currentPage > 2">
<li class="page-item"><a class="page-link" (click)="pageChange(1)">1</a></li>
<li class="page-item" *ngIf="currentPage > 3">
<span class="page-link">...</span>
<ng-container *ngIf="isSimpleMode; else defaultView">
<li class="page-item"><span class="page-link" aria-current="page">{{currentPage + 1}}</span></li>
<li class="page-item"><span class="page-link">/</span></li>
<li class="page-item"><span class="page-link">{{pageNumbers}}</span></li>
<li class="page-item visually-hidden">
<a class="page-link" href="#" aria-current="page">
{{'it.core.page-of-total'|translate : {page: (currentPage + 1), total: pageNumbers} }}
</a>
</li>
</ng-container>
<ng-template #defaultView>
<ng-container *ngIf="pageNumbers > visiblePages && pages[0] >= 2">
<li class="page-item">
<a class="page-link" href="#" (click)="pageChange($event, 1)">1</a>
</li>
<li class="page-item" *ngIf="pages[0] >= 3">
<span class="page-link">...</span>
</li>
</ng-container>

<li class="page-item" *ngFor="let page of pages">
<a class="page-link" aria-current="page" *ngIf="page === (currentPage + 1); else inactivePage">
<span class="d-inline-block d-sm-none">{{'it.core.page'|translate}}</span> {{page}}
</a>
<ng-template #inactivePage>
<a class="page-link" (click)="pageChange(page)">{{page}}</a>
</ng-template>
</li>

<ng-container *ngIf="pageNumbers > 5 && pageNumbers - currentPage > 3">
<li class="page-item">
<span class="page-link">...</span>
<li class="page-item" *ngFor="let page of pages">
<a class="page-link" aria-current="page" *ngIf="page === (currentPage + 1); else inactivePage">
<span class="d-inline-block d-sm-none">{{'it.core.page'|translate}}</span> {{page}}
</a>
<ng-template #inactivePage>
<a class="page-link" href="#" (click)="pageChange($event, page)">{{page}}</a>
</ng-template>
</li>
<li class="page-item"><a class="page-link" (click)="pageChange(pageNumbers)">{{pageNumbers}}</a></li>
</ng-container>

<ng-container *ngIf="pageNumbers > visiblePages && pages[pages.length - 1] < pageNumbers">
<li class="page-item" *ngIf="pages[pages.length - 1] < (pageNumbers - 1)">
<span class="page-link">...</span>
</li>
<li class="page-item">
<a class="page-link" href="#" (click)="pageChange($event, pageNumbers)">{{pageNumbers}}</a>
</li>
</ng-container>
</ng-template>

<li class="page-item" [class.disabled]="currentPage >= pageNumbers - 1">
<a class="page-link" (click)="pageChange(currentPage + 2)">
<span class="visually-hidden">{{'it.core.next-page'|translate}}</span>
<it-icon name="chevron-right" color="primary"></it-icon>
<a class="page-link" [class.text]="isTextLinks" href="#" (click)="pageChange($event, currentPage + 2)">
<span class="visually-hidden">
{{(isTextLinks ? 'it.core.page' : 'it.core.next-page') | translate}}
</span>
<ng-container *ngIf="isTextLinks">{{'it.core.next' | translate}}</ng-container>
<it-icon *ngIf="!isTextLinks" name="chevron-right" color="primary"></it-icon>
</a>
</li>
</ul>

<it-dropdown *ngIf="currentChanger !== undefined" id="pager-changer">
<span button>{{currentChanger}} / {{'it.core.page' | translate | lowercase}}</span>
<ng-container list>
<it-dropdown-item *ngFor="let value of changerValues" href="#" externalLink="true"
(click)="changerChange($event, value)">
{{value}} / {{'it.core.page' | translate | lowercase}}
</it-dropdown-item>
</ng-container>
</it-dropdown>

<it-input *ngIf="isShowJumpToPage" id="jump-to-page" type="number" [min]="1" [max]="pageNumbers"
[label]="('it.core.go-to' | translate) + '...'" [formControl]="jumpToPage"></it-input>

<p [class.d-none]="!totalNumberText.hasChildNodes()" #totalNumberText>
<ng-content></ng-content>
</p>
</nav>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnChanges,
Output,
SimpleChanges
} from '@angular/core';
import { BooleanInput, isTrueBooleanInput } from '../../../utils/boolean-input';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged, filter } from 'rxjs';

@Component({
selector: 'it-pagination[currentPage][pageNumbers]',
templateUrl: './pagination.component.html',
styleUrls: ['./pagination.component.scss']
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PaginationComponent {
export class PaginationComponent implements OnChanges {

/**
* Index of page (start 0)
Expand All @@ -17,27 +28,119 @@ export class PaginationComponent {
*/
@Input() pageNumbers!: number;

/**
* Number of pages closest to the current one to display
* @default 5
*/
@Input() visiblePages: number = 5;

/**
* Pagination alignment (justify-content)
*/
@Input() alignment?: 'center' | 'end';

/**
* Fired when page is changed
* Enable/Disable simple mode
* Pagination in the "Simple mode" version is optimized for mobile devices.
* @default undefined - disabled
*/
@Input() simpleMode?: BooleanInput;

/**
* Enable/Disable text links
* Chevron icons used as navigation links are replaced by text links such as “previous” and “next”.
* @default undefined - disabled
*/
@Input() textLinks?: BooleanInput;

/**
* Current value of Changer
* If is set show the Changer
* @default undefined - hide the Changer
*/
@Input() currentChanger?: number;

/**
* Available Changer values
* @default [10, 25, 50, 100]
*/
@Output() newPageEvent = new EventEmitter<number>();
@Input() changerValues: Array<number> = [10, 25, 50, 100];

/**
* Create array to generate pagination of 5 element
* Hide/Show "Jump to page" input
* @default undefined - hidden
*/
get pages(): Array<number> {
const length = this.pageNumbers > 5 ? 5 : this.pageNumbers;
let start = (this.currentPage > 1 && this.pageNumbers > 5) ? this.currentPage - 1 : 1;
@Input() showJumpToPage?: BooleanInput;

if (this.pageNumbers > 5) {
/**
* Fired when page is changed. Emit the new index of page
*/
@Output() pageEvent = new EventEmitter<number>();

/**
* Fired when changer is changed. Emit the new changer value
*/
@Output() changerEvent = new EventEmitter<number>();

/**
* The pages
* @protected
*/
protected pages: Array<number> = [];

/**
* Jump to page input
* @protected
*/
protected jumpToPage: FormControl<number | null> = new FormControl<number | null>(null);

get isSimpleMode(): boolean {
return isTrueBooleanInput(this.simpleMode);
}

get isTextLinks(): boolean {
return isTrueBooleanInput(this.textLinks);
}

get isShowJumpToPage(): boolean {
return isTrueBooleanInput(this.showJumpToPage);
}

constructor() {
this.jumpToPage.valueChanges.pipe(
debounceTime(300), // Delay filter data after time span has passed without another source emission
distinctUntilChanged(),
filter(value => !!value && this.jumpToPage.valid)
).subscribe(value => {
this.pageEvent.emit(value! - 1);
});
}

ngOnChanges(changes: SimpleChanges): void {
this.pages = this.calculatePages();
if (changes['currentPage']) {
this.jumpToPage.setValue(null, { emitEvent: false });
}
}

/**
* Create array to generate pagination of `visiblePages` element
*/
private calculatePages(): Array<number> {
if (this.isSimpleMode) {
return [this.currentPage];
}

const length = this.pageNumbers > this.visiblePages ? this.visiblePages : this.pageNumbers;

const halfVisiblePages = Math.floor(this.visiblePages / 2);
let start = (this.currentPage > halfVisiblePages && this.pageNumbers > this.visiblePages) ?
this.currentPage - halfVisiblePages + 1 : 1;

if (this.pageNumbers > this.visiblePages) {
if ((this.currentPage + 1) >= this.pageNumbers) {
start -= 2;
} else if (this.currentPage >= (this.pageNumbers - 2)) {
start -= halfVisiblePages;
} else if (this.currentPage >= (this.pageNumbers - halfVisiblePages)) {
start -= (this.pageNumbers - (this.currentPage + 1));
}
}
Expand All @@ -47,10 +150,22 @@ export class PaginationComponent {

/**
* On click page change
* @param event click event
* @param newPage the new page of table
*/
pageChange(newPage: number): void {
this.newPageEvent.emit(newPage - 1); // emit new page
protected pageChange(event: Event, newPage: number): void {
event.preventDefault();
this.pageEvent.emit(newPage - 1); // emit new page index
}

/**
* On click changer
* @param event click event
* @param value the new changer value
*/
protected changerChange(event: Event, value: number): void {
event.preventDefault();
this.changerEvent.emit(value); // emit new changer value
}

}
1 change: 1 addition & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const routes: Routes = [
{ path: 'select', loadChildren: () => import('src/app/select/select.module').then(m => m.SelectModule) },
{ path: 'notifications', loadChildren: () => import('src/app/notifications/notifications.module').then(m => m.NotificationsModule) },
{ path: 'rating', loadChildren: () => import('src/app/rating/rating.module').then(m => m.RatingModule) },
{ path: 'pagination', loadChildren: () => import('src/app/pagination/pagination.module').then(m => m.PaginationModule) },
{ path: 'table', loadChildren: () => import('src/app/table/table.module').then(m => m.TableModule) },
{ path: 'textarea', loadChildren: () => import('src/app/textarea/textarea.module').then(m => m.TextareaModule) },
{ path: 'alert', loadChildren: () => import('src/app/alert/alert.module').then(m => m.AlertModule) },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h3>Changer</h3>
<p>La funzionalità di changer permette di scegliere da un dropdown la quantità di record da visualizzare in una pagina.</p>

<div class="bd-example">
<it-pagination [currentPage]="currentPage" [pageNumbers]="50"
[currentChanger]="changerValue"
[changerValues]="changerValues"
(pageEvent)="pageChange($event)"
(changerEvent)="changerEvent($event)"></it-pagination>

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { PaginationChangerExampleComponent } from './pagination-changer-example.component';

describe('PaginationChangerExampleComponent', () => {
let component: PaginationChangerExampleComponent;
let fixture: ComponentFixture<PaginationChangerExampleComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PaginationChangerExampleComponent ]
})
.compileComponents();

fixture = TestBed.createComponent(PaginationChangerExampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Component } from '@angular/core';

@Component({
selector: 'it-pagination-changer-example',
templateUrl: './pagination-changer-example.component.html'
})
export class PaginationChangerExampleComponent {
currentPage: number = 25;

changerValue: number = 10;

/**
* By default, the values are [10, 25, 50, 100]
*/
changerValues: Array<number> = [10, 25, 50, 100, 250];

pageChange(page: number): void {
this.currentPage = page;
}

changerEvent(value: number): void {
this.changerValue = value;
}
}
Loading

1 comment on commit 95f9767

@vercel
Copy link

@vercel vercel bot commented on 95f9767 Mar 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.