I already have the pagination implemented. Now I want the pagination to be updated after filtering my results.
The form:
<input type="text" data-ng-model="search.name" data-ng-change="filter()"/>
The list:
<li data-ng-repeat="data in filtered = (list | filter:search) | filter:search | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">{{data.name}}</li>
The pagination:
<pagination data-boundary-links="true" data-num-pages="noOfPages" data-current-page="currentPage" max-size="maxSize"></pagination>
The controller:
$scope.filter = function() {
window.setTimeout(function() { //wait for 'filtered' to be changed
$scope.noOfPages = Math.ceil($scope.filtered.length/$scope.entryLimit);
$scope.setPage = function(pageNo) {
$scope.currentPage = pageNo;
};
}, 10);
};
My problem is, the pagination is just updated after clicking on a page number or after entering the next character into the input field. So it is update one step to late.
EDIT: I added the source to jsFiddle: http://jsfiddle.net/eqCWL/2/
@abject_error 's answer using $timeout
does work. I edited your fiddle with his suggestion and made this jsFiddle
CAVEAT
I think the solution is indicative of a bigger problem in the form of a race condition!
and that fiddle is the way around it for reals.
And here is the explanation
Your race condition is between handling the change of search
and the availability of $scope.filtered
.
I think the culprits to eliminate in order to resolve this race condition are:
ng-model="search" ng-change="filter()"
and
ng-repeat="data in filtered = (list | filter:search)......."
Using ng-change
to fire off "filter()" to do the calculation of noOfPages
but also depending on a change in search in order to create filtered
. Doing it this way, ensures the filtered list cannot possibly be ready in time to calculate the number of pages, and that's why hobbling "filter()" by 10ms with a timeout gives you the illusion of a working program.
What you need is a way to "watch" search
for changes, and then filter the list in a place where you have access to both creating $scope.filtered
and calculating $scope.noOfPages
. All in sequence, without a race.
Angular has that way! It is possible to use the filter
filter in your controller as function very poorly named: filterFilter
. Check this out in the Filters Guide - Using filters in controllers and services
Inject it into the controller.
function pageCtrl($scope, filterFilter) {
// ...
}
Use it in a $watch
function, documented in the scopes docs
$scope.$watch('search', function(term) {
// Create filtered
$scope.filtered = filterFilter($scope.list, term);
// Then calculate noOfPages
$scope.noOfPages = Math.ceil($scope.filtered.length/$scope.entryLimit);
})
Change the template to reflect our new way. No more in DOM filter, or ng-change
<input type="text" ng-model="search" placeholder="Search"/>
and
<li ng-repeat="data in filtered | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
{{data.name}}
</li>
You could simply use this directive instead:
https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
It offers pagination with a filter while keeping the code nice and clean.
Kudos to michaelbromley for the great code.
Use $timeout
instead of window.setTimeOut
. $timeout
is wrapped properly to work consistently in Angular.
Use angular $scope.$watch
$scope.$watch('search', function(term) {
$scope.filter = function() {
$scope.noOfPages = Math.ceil($scope.filtered.length/$scope.entryLimit);
}
});
Source ; http://jsfiddle.net/eqCWL/2/
Demo ; http://jsfiddle.net/eqCWL/192/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With