I'm trying to update the page index from the parent component in an Angular application using a child component that handles pagination. The child component has an index input property and an event emitter for page changes. However, when I try to update the index from the parent, the UI does not reflect the updated value, and the pagination does not change.My project is on Angular 13.
import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'numbered-pagination',
templateUrl: './numbered-pagination.component.html',
styleUrls: ['./numbered-pagination.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NumberedPaginationComponent implements OnChanges {
@Input() index: number = 1;
@Input() totalCount: number = 0;
@Input() pageSize: number = 50;
@Input() rulerLength: number = 5;
@Output() page: EventEmitter<number> = new EventEmitter<number>();
maxPages: number = 1;
ngOnChanges(changes: SimpleChanges): void {
if (changes['totalCount'] || changes['pageSize']) {
this.calculateMaxPages();
}
}
private calculateMaxPages(): void {
this.maxPages = Math.ceil(this.totalCount / this.pageSize) || 1;
}
get pagination(): NumberedPagination {
const { index, maxPages, rulerLength } = this;
const pages = ruler(index, maxPages, rulerLength);
return { index, maxPages, pages };
}
navigateToPage(pageNumber: number): void {
if (allowNavigation(pageNumber, this.index, this.maxPages)) {
this.index = pageNumber;
this.page.emit(this.index);
console.log("Index =>> " + this.index);
}
console.log("Index1 =>> " + this.index);
}
trackByFn(index: number): number {
return index;
}
constructor(private cdr: ChangeDetectorRef) {}
refreshToInitial() {
this.navigateToPage(1);
this.cdr.detectChanges();
this.cdr.markForCheck();
}
}
function generatePageArray(rulerLength: number): number[] {
const result: number[] = [];
for (let i = 1; i <= rulerLength; i++) {
result.push(i);
}
return result;
}
const ruler = (
currentIndex: number,
maxPages: number,
rulerLength: number
): number[] => {
if (maxPages <=rulerLength) {
return generatePageArray(maxPages);; // If maxPages is 1, return an array with only 1 page
}
const array = new Array(rulerLength).fill(null);
const min = Math.floor(rulerLength / 2);
return array.map((_, index) =>
rulerFactory(currentIndex, index, min, maxPages, rulerLength)
);
};
const rulerOption = (
currentIndex: number,
min: number,
maxPages: number
): RulerFactoryOption => {
return currentIndex <= min
? RulerFactoryOption.Start
: currentIndex >= maxPages - min
? RulerFactoryOption.End
: RulerFactoryOption.Default;
};
const rulerFactory = (
currentIndex: number,
index: number,
min: number,
maxPages: number,
rulerLength: number
): number => {
const factory = {
[RulerFactoryOption.Start]: () => index + 1,
[RulerFactoryOption.End]: () => maxPages - rulerLength + index + 1,
[RulerFactoryOption.Default]: () => currentIndex + index - min,
};
return factory[rulerOption(currentIndex, min, maxPages)]();
};
const allowNavigation = (
pageNumber: number,
index: number,
maxPages: number
): boolean => {
return pageNumber !== index && pageNumber > 0 && pageNumber <= maxPages;
};
HTML part of Child Component
<ol *ngIf="maxPages>1" class="paginator-container">
<li (click)="navigateToPage(1)">
<i matTooltip="First Page" class="fa-solid fa-angles-left"></i>
<span>First</span>
</li>
<li (click)="navigateToPage(index - 1)"><i matTooltip="Previous Page" class="fa-solid fa-angle-left"></i> <span>Previous</span></li>
<li
*ngFor="let page of pagination.pages; trackBy: trackByFn"
class="paginator-number"
[class.active]="page === pagination.index"
(click)="navigateToPage(page)"
>
{{ page }}
</li>
<li (click)="navigateToPage(index + 1)"><span>Next</span> <i matTooltip="Next Page" class="fa-solid fa-angle-right"></i></li>
<li (click)="navigateToPage(maxPages)">
<span>Last</span>
<i matTooltip="Last Page" class="fa-solid fa-angles-right"></i>
</li>
</ol>
Parent Component TypeScript
<button class="edit_button" (click)="onAssignToButtonClick('Extracted')">
Assign To
</button>
<numbered-pagination [index]="extractedPageNumber" (page)="pageEvent('New', $event)" [pageSize]="pageSize" [totalCount]="pageNumberExtractedLimit"></numbered-pagination>
Problem:
What I've tried:
I’m using ChangeDetectorRef in the child component to manually trigger change detection, but it doesn’t seem to update the UI.
The child’s pagination logic correctly emits page changes via the page output, but the UI doesn't react to the changes.
Can someone explain why this isn't working or suggest a solution?
Thanks to Pieterjan’s reply, I tried implementing two-way binding. However, to fix the issue, I had to create a new component with the same logic. Here’s the change I made :
@Output() page: EventEmitter<number> = new EventEmitter<number>();
With this:
@Output() indexChange: EventEmitter<number> = new EventEmitter<number>();
Despite this change, it didn’t work in the old component, and I had to create a new pagination component.
I’m not sure why this change didn’t take effect in the existing component. Does anyone know why this might happen?