41

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.

pcgilday
  • 1,032
  • 2
  • 10
  • 15

7 Answers7

45

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.

maja
  • 17,250
  • 17
  • 82
  • 125
pcgilday
  • 1,032
  • 2
  • 10
  • 15
  • 1
    Hi I am in same situation. I can't understand what you mean with 'state resolve'. Please, could you explain it? – wildbyte May 26 '15 at 06:13
  • 1
    @wildbyte - ui router has a resolve function that gets run and completes before the state loads. This allows you to set values prior to the states controller or directives loading. – pcgilday May 28 '15 at 14:49
  • 1
    Thank you very much, you really saved my day :) – murnax Aug 04 '15 at 08:47
  • 1
    Thanks for the finding. This is very helpful. Cheers :) – Abhishek Prakash Sep 03 '15 at 06:26
  • I wont be able to load the items in state resolve as I am using $futureProvider to build the states , Is there any other alternate solution . – 32teeths Mar 11 '16 at 05:52
41

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

Mudassir Ali
  • 7,913
  • 4
  • 32
  • 60
8

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>
theluckyluke
  • 81
  • 1
  • 3
1

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.

Ariful Haque
  • 3,662
  • 5
  • 37
  • 59
0

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!

TommyMac
  • 299
  • 1
  • 6
  • Thank you for your answer; however, I had the directive set up like that. If you see my solution below my issue was the controller initializing totalItems to 0 (while waiting for the api response) and triggering a $scope.$watch that reset currentPage. – pcgilday Jan 12 '15 at 23:18
0

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!

Housty
  • 56
  • 3
0

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)">

Muhammad Umar
  • 1,291
  • 7
  • 13