ui-bootstrap pagination resetting current page on initialization

All we need is an easy explanation of the problem, so here it is.

I am using the pagination directive from the ui-bootstrap (angular-bootstrap) library. I am having an issue when it initializes. My issue occurs when I navigate to a specific page via url.

What is happening is that my controller initializes with the correct page from $stateParams, then the pagination directive initializes and triggers the ng-change function which is resetting the page to 1. Now that on-select-page is no longer used, is there a way to only capture user clicks to change the page? Ideally I would like the directive to initialize before the controller so that my page does not get reset. Thank you in advance.

I can include code if needed, but I feel my question does not necessarily require a code block.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

So I found a solution after drilling down into the angular-bootstrap code. Their code has a watch on totalPages that checks if the current page is greater than the totalPages value.

angular-bootstrap code:

if ( $scope.page > value ) {
  $scope.selectPage(value);
} else {
  ngModelCtrl.$render();
}

What was happening was if I refreshed the page on page 3 (for example) my controller was reloading the items for that page temporarily causing total-items to be 0 and totalPages to be calculated as 1. This triggered the watch and the above code.

My solution was to load the items in the state resolve so that total-items (and in turn totalPages) would always be accurate.

Method 2

If you don’t want to use state resolve the data then you could just add a ng-if directive on paginator. Assuming $scope.total_count is used to bind to total-items attribute, you can do something like the following:

<pagination data-ng-if="total_count"
            total-items="total_count"
            ng-model="applied_filters.page"
            max-size="maxSize"
            class="pagination-sm"
            boundary-links="true"
            rotate="false"
            class="nomargin"
            num-pages="numPages"></pagination>

This way the directive is always initialized when you have total count from the server & currentPage will not be greater than totalPages

Method 3

The ng-if directive didn’t work for me as expected (I didn’t use the controllerAs syntax): the pagination wasn’t able to update the $scope.currentPage variable anymore. The solution was to use ng-model="$parent.currentPage" instead of ng-model="currentPage".

<uib-pagination ng-if="totalItems"
                total-items="totalItems"
                items-per-page="itemsPerPage"
                ng-model="$parent.currentPage">
</uib-pagination>

Method 4

A solution to this problem I’ve found from Github and implemented and worked perfectly.

As mentioned in other answers also, the issue is with totalItems and when I try to move to page 2/3/n, totalItems becomes 0 for a moment and in the process, currentPage value becomes 1 and I can’t move to my desired page. So my trick is, before I call the data from server, I just set a bigger number as totalItems and after I receive data from server, I update totalItems.

$scope.totalItems = 1000;
QuotationService.getQuotations(url).then(function ( response ) {

     $scope.totalItems = response.data.total;
     $scope.quotations = response.data.data;
     $scope.isTableLoading = false;

});

In my view, only if isTableLoading is false, I show the Pagination, otherwise pagination will show a wrong number of pages.

<div class="text-center" ng-show="isTableLoading == false">
     <uib-pagination boundary-links="true"  
           total-items="totalItems"
           items-per-page="15" max-size="15" ng-model="currentPage"
           class="pagination-sm" previous-text="&lsaquo;"
           next-text="&rsaquo;" first-text="&laquo;" last-text="&raquo;">
     </uib-pagination>
</div>

Now everything working perfectly.

Method 5

If you are looking to set the page when the page loads, then just load up the model as it describes here.

From the website:

<pagination total-items="totalItems" ng-model="currentPage" ng-change="pageChanged()">
</pagination>

I’m sure you’ve already looked there, so if the model is not being set properly upon the initialization of the controller then you’re obviously going to have problems. There is also the case where it is possibly being overwritten in another place where you are using $scope.currentPage. Although you may feel it is easier without code, I would suggest posting the HTML and Angular Controller you are referring to. Hope it helps!

Method 6

An alternative to the state resolve would be to set the total-items in a value module once known. Same dealio, actually I just wanted to comment on your above answer, but I didn’t have the points necessary. Thanks for the explanation, helped me out!

Method 7

Just adding another simplest way to fix the problem.
1. First, pass query params to your URL(to make more sense about at which page you are currently at). To do this, add this line of code to your function that runs on (pageChange). i.e (pageChange)="getAllData(page)"

this.router.navigate(['/Advertisement'], { queryParams: { page: page }});

2. Second, get query params and assign the params to page variable. i.e

this.route.queryParamMap.subscribe((params:any) => { this.page = +params.get('page')});

My HTML
<ngb-pagination [collectionSize]="collectionSize" [(page)]="page" [pageSize]="pageSize" (pageChange)="getAdvertisements(page)">

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply