ng2-bootstrap pagination pageChanged triggered multiple times

Rhushikesh picture Rhushikesh · Jan 29, 2016 · Viewed 8.7k times · Source

I am trying to implement the pagination in my angular2 app with the ng2-bootrap. am following http://valor-software.github.io/ng2-bootstrap/#pagination

my app.html

<div>
    <div class="col-lg-12 text-right">
        <pagination [totalItems]="totalItems" [itemsPerPage]='2' (pageChanged)="pageChanged($event)" [(ngModel)]="currentPage" [maxSize]="maxSize"
        class="pagination-sm" [boundaryLinks]="true"></pagination>
    </div>
</div>

my component

import { Component, View, Inject} from 'angular2/core';
import { CORE_DIRECTIVES } from 'angular2/common';
import { PAGINATION_COMPONENTS } from 'ng2-bootstrap/ng2-bootstrap';

// webpack html imports
@View({
    templateUrl: '/scripts/src/components/demo/demo.html',
    directives: [PAGINATION_COMPONENTS, CORE_DIRECTIVES]
})
@Component({
    selector: 'tabs-demo',
})
export class DemoComponent {
    private totalItems: number = 64;
    private currentPage: number = 4;

    private maxSize: number = 5;
    private bigTotalItems: number = 175;
    private bigCurrentPage: number = 1;

    private setPage(pageNo: number): void {
        this.currentPage = pageNo;
    };

    private pageChanged(event: any): void {
        console.log('Page changed to: ' + event.page);
        console.log('Number items per page: ' + event.itemsPerPage);
    };
}

its trigger the pageChange event multiple time without clicking on pagination

enter image description here

Answer

Thierry Templier picture Thierry Templier · Jan 29, 2016

The event is actually triggered every time the page property of the component is updated (this can be done programmatically without any interaction from the UI).

In fact, this event is triggered three times when initializing the pagination component because of the following:

  • from the ngInit method. This is part of the lifecycle of the component.

    export class Pagination implements ControlValueAccessor, OnInit, IPaginationConfig, IAttribute {
      (...)
    
      ngOnInit() {
        (...)
        this.page = this.cd.value;
        (...)
      }
    
      (...)
    }
    
  • from the writeValue method. This method is called because the component is ngModel-compliant. When the expression associated in the ngModel is updated, this method is called with the new value. During initialization, the writeValue method is called twice: first with the null value and then with the 1 value.

    export class Pagination implements ControlValueAccessor, OnInit, IPaginationConfig, IAttribute {
      (...)
    
      writeValue(value:number) {
        this.page = value;
        this.pages = this.getPages(this.page, this.totalPages);
      }
    
      (...)
    }
    

That said, after this initialization phase, the pageChanged is only triggered once per page update.

Edit

After having a look at the code of ng2-bootstrap, I can't see how to do that without updating the code of the Pagination component.

Here are the updates you could do in this class (file node_modules/ng2-bootstrap/components/pagination/pagination.ts):

  • Update the set page block to trigger events only when the inited property is true:

    public set page(value) {
      this._page = (value > this.totalPages) ? this.totalPages : (value || 1);
    
      if (this.inited) { // <---------------
        this.pageChanged.next({
          page: this._page,
          itemsPerPage: this.itemsPerPage
        });
      }
    }
    
  • Update the ngOnInit method not to set the inited property to true at its end:

    ngOnInit() {
      (...)
      //this.inited = true;
    }
    
  • Set the inited property to true at the end of the first call of the writeValue:

    writeValue(value:number) {
      this.page = value;
      this.pages = this.getPages(this.page, this.totalPages);
    
      if (!this.inited) {
        this.inited = true;
      }
    }
    

This way the pageChanged event will be called only once during the pagination initialization phase.

Hope it helps you, Thierry