Search code examples
angularpaginationngx-bootstrap

Angular - ngx-Pagination not working as expected


In Angular-14, I am implementing server-side pagination using ngx-bootstrap-pagination with ASP.NET Core-6 as the backend.

service:

getPaymentStatus(): Observable<IPaymentStatus[]> {
  return this.http.get<IPaymentStatus[]>(this.baseUrl + '/payments-status');
}

I got this JSON response from the backend:

{
    "data": {
        "pageItems": [
            {
                "id": "2b0ab0db-523f-4b5f-837e-3f24ba6e0325",
                "dueDate": "2025-06-12T00:00:00",
                "narration": null,
                "paymentStatus": 0
            },
            ....
        ],
        "pageSize": 10,
        "currentPage": 1,
        "numberOfPages": 9,
        "totalRecord": 81
    },
    "successful": true,
    "message": "All data retrieved successfully",
    "statusCode": 200
}

So, in the typescipt, I got this:

component.ts:

  page: number = 1;
  pageSize!: number;
  currentPage!: number;
  numberOfPages!: number;
  totalRecords!: number;
  pageSizes = [10, 20, 50, 100];

  ngOnInit(): void {
    this.loadAllPayments();
  }

  getRequestParams(page: number, pageSize: number): any {
    let params: any = {};
    if (page) {
      params[`page`] = page - 1;
    }
    if (pageSize) {
      params[`size`] = pageSize;
    }
    return params;
  }

  handlePageChange(event: number): void {
    this.page = event;
    this.loadAllPayments();
  }

  handlePageSizeChange(event: any): void {
    this.pageSize = event.target.value;
    this.page = 1;
    this.loadAllPayments();
  }

  onTableDataChange(event: any) {
    this.currentPage = event;
    this.loadAllPayments();
  }
  onTableSizeChange(event: any): void {
    this.pageSize = event.target.value;
    this.currentPage = 1;
    this.loadAllPayments();
  }

  loadAllPayments() {
    this.dataService.getPaymentStatus().subscribe({
      next: (res: any) => {
        this.allPaymentList = res.data.pageItems;
        this.totalRecords = res.data.totalRecord;
        this.currentPage = res.data.currentPage;
        this.pageSize = res.data.pageSize;
      },
      error: (error) => {
        this.toastr.error(error.message);
        this.isLoading = false;
      }
    })
  }

component.html:

      <div class="card-body">
        <table class="table table-striped table-bordered table-hover">
          <thead>
            <tr>
              <th style="width: 10px">#</th>
              <th>Due Date</th>
              <th>Narration</th>
              <th>Payment Status</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody *ngIf="allPaymentList != undefined">
            <tr *ngFor="let row of allPaymentList
            | paginate : {
              itemsPerPage: pageSize,
              currentPage: currentPage,
              totalItems: totalRecords
            }; let i = index;">
              <td>{{ i + 1 }}.</td>
              <td>{{ row?.dueDate | date: 'dd-MM-yyyy' || 'N/A' }}</td>
              <td>{{ row?.narration || 'N/A' }}</td>
              <td>{{ row?.paymentStatus || 'N/A' }}</td>
              <td>
                <a class="btn btn-primary btn-sm" (click)="viewPaymentData(paymentDetail, row)">
                  <i class="fa fa-eye" aria-hidden="true"></i> View
                </a>&nbsp;
              </td>
            </tr>
            <tr *ngIf="allPaymentList.length ==0;">
              <td colspan="9" class="text-center">
                <span class="align-center">No Data Found!</span>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <div class="card-footer clearfix">
        <div class="row">
          <div class="col-md-6">
            <pagination-controls
            previousLabel="Prev"
            nextLabel="Next"
            [responsive]="true"
            (pageChange)="onTableDataChange($event)"
          >
          </pagination-controls>
          </div>
          <div class="col-md-4">
            Items Per Page:
            <select (change)="onTableSizeChange($event)">
              <option *ngFor="let size of pageSizes" [ngValue]="size">
                {{ size }}
              </option>
            </select>
          </div>
        </div>
      </div>

console.log(this.allPaymentList) gives:

{
    "data": {
        "pageItems": [
            {
                "id": "2b0ab0db-523f-4b5f-837e-3f24ba6e0325",
                "dueDate": "2025-06-12T00:00:00",
                "narration": null,
                "paymentStatus": 0
            },
            {
                "id": "d76b297a-70b5-4a29-82e1-937f6710cbb2",
                "dueDate": "2025-03-12T00:00:00",
                "narration": null,
                "paymentStatus": 0
            },
            {
                "id": "ef94ac6e-e18e-474f-961b-3b995ce7b4a7",
                "dueDate": "2024-12-12T00:00:00",
                "narration": null,
                "paymentStatus": 0,
            },
            {
                "id": "a4b35e3b-0bb7-4115-aee7-858259703b62",
                "dueDate": "2023-03-12T00:00:00",
                "narration": null,
                "paymentStatus": 0
            }
             ...
        ],
        "pageSize": 10,
        "currentPage": 1,
        "numberOfPages": 9,
        "totalRecord": 81,
        "previousPage": 0
    },
    "successful": true,
    "message": "All payments retrieved successfully",
    "statusCode": 200
}

The pagination is as shown below:

pagination

which is correct.

But where I have an issue is that when I click on each number (1,2,3,4 ..9), it remains on the same page instead of navigating to the next page. Also, the Item Per Page is not taking me to the pages.

How do I correct all these?

Thanks


Solution

  • You forgot to tell the API to return the correct data based on your pagination input format.

    Here is what you can do.

    in you service you need to add more information to send (this data must be provided by your backend team.

    So, from this

    getPaymentStatus(): Observable<IPaymentStatus[]> {
      return this.http.get<IPaymentStatus[]>(this.baseUrl + '/payments-status');
    }
    

    Change it to:

    getPaymentStatus(page: number = 1, perPage: number = 10): Observable<IPaymentStatus[]> {
      return this.http.get<IPaymentStatus[]>(this.baseUrl + `/payments-status?page=${page}&perPage=${perPage}`);
    }
    

    Note: Keys page and perPage must be provided by your backend team.


    Now, in your components you can make a request with more inputs this.dataService.getPaymentStatus($page, $perPage)

    Like:

    // Example One: page 1, 10 per page
    this.dataService.getPaymentStatus(1).subscribe((data) => {
        console.log({data});
    });
    
    
    // Example Two: page 2, 20 per page
    this.dataService.getPaymentStatus(2, 20).subscribe((data) => {
        console.log({data});
    });
    

    And so on...