Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
AngularJS - Dynamic pagination on ng-repeat with search/filtering. Use with ui.bootstrap
<!DOCTYPE HTML>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title>Dynamic Pagination w/ Filtering</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Kim Maida">
<!-- JS Libraries -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js" type="text/javascript"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js" type="text/javascript"></script>
<!-- Angular Scripts -->
<script src="script.js" type="text/javascript"></script>
<!-- Bootstrap -->
<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
</head>
<body>
<div ng-controller="PageCtrl">
<div ng-controller="PageCtrl">
<label>Search:</label> <input type="text" ng-model="search.name" placeholder="Search" />
<br />
<label>Filter by Category:</label>
<ul>
<li><a href="" ng-click="search.category='engineering'">Engineering</a></li>
<li><a href="" ng-click="search.category='management'">Management</a></li>
<li><a href="" ng-click="search.category='business'">Business</a></li>
</ul>
<label>Filter by Branch:</label>
<ul>
<li><a href="" ng-click="search.branch='West'">West</a></li>
<li><a href="" ng-click="search.branch='East'">East</a></li>
</ul>
<p><strong><a href="" ng-click="resetFilters()">Show All</a></strong></p>
<h1>Items</h1>
<ul>
<li ng-repeat="item in filtered = items | filter:search | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">{{item.name}}</li>
</ul>
<pagination page="currentPage" max-size="noOfPages" total-items="totalItems" items-per-page="entryLimit"></pagination>
</div>
</body>
</html>
var app = angular.module('myApp', ['ui.bootstrap']);
app.filter('startFrom', function () {
return function (input, start) {
if (input) {
start = +start;
return input.slice(start);
}
return [];
};
});
app.controller('PageCtrl', ['$scope', 'filterFilter', function ($scope, filterFilter) {
$scope.items = [{
"name": "name 1",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "West"
}, {
"name": "name 2",
"category": [{
"category": "engineering"
}],
"branch": "West"
}, {
"name": "name 3",
"category": [{
"category": "management"
}, {
"category": "engineering"
}],
"branch": "West"
}, {
"name": "name 4",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "West"
}, {
"name": "name 5",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "East"
}, {
"name": "name 6",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "East"
}, {
"name": "name 7",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "East"
}, {
"name": "name 8",
"category": [{
"category": "business"
}],
"branch": "West"
}, {
"name": "name 9",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "East"
}, {
"name": "name 10",
"category": [{
"category": "management"
}],
"branch": "East"
}, {
"name": "name 11",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "East"
}, {
"name": "name 12",
"category": [{
"category": "engineering"
}],
"branch": "West"
}, {
"name": "name 13",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "West"
}, {
"name": "name 14",
"category": [{
"category": "engineering"
}],
"branch": "East"
}, {
"name": "name 15",
"category": [{
"category": "management"
}, {
"category": "engineering"
}],
"branch": "East"
}, {
"name": "name 16",
"category": [{
"category": "management"
}],
"branch": "West"
}, {
"name": "name 17",
"category": [{
"category": "management"
}],
"branch": "East"
}, {
"name": "name 18",
"category": [{
"category": "business"
}],
"branch": "West"
}, {
"name": "name 19",
"category": [{
"category": "business"
}],
"branch": "West"
}, {
"name": "name 20",
"category": [{
"category": "engineering"
}],
"branch": "East"
}, {
"name": "Peter",
"category": [{
"category": "business"
}],
"branch": "East"
}, {
"name": "Frank",
"category": [{
"category": "management"
}],
"branch": "East"
}, {
"name": "Joe",
"category": [{
"category": "business"
}],
"branch": "East"
}, {
"name": "Ralph",
"category": [{
"category": "management"
}, {
"category": "business"
}],
"branch": "East"
}, {
"name": "Gina",
"category": [{
"category": "business"
}],
"branch": "East"
}, {
"name": "Sam",
"category": [{
"category": "management"
}, {
"category": "engineering"
}],
"branch": "East"
}, {
"name": "Britney",
"category": [{
"category": "business"
}],
"branch": "West"
}];
// create empty search model (object) to trigger $watch on update
$scope.search = {};
$scope.resetFilters = function () {
// needs to be a function or it won't trigger a $watch
$scope.search = {};
};
// pagination controls
$scope.currentPage = 1;
$scope.totalItems = $scope.items.length;
$scope.entryLimit = 8; // items per page
$scope.noOfPages = Math.ceil($scope.totalItems / $scope.entryLimit);
// $watch search to update pagination
$scope.$watch('search', function (newVal, oldVal) {
$scope.filtered = filterFilter($scope.items, newVal);
$scope.totalItems = $scope.filtered.length;
$scope.noOfPages = Math.ceil($scope.totalItems / $scope.entryLimit);
$scope.currentPage = 1;
}, true);
}]);
@xxJimxx

This comment has been minimized.

Copy link

@xxJimxx xxJimxx commented Dec 30, 2014

Hello, Thanks for the post, it helped a lot in implementing a pager. I am a little confused on what the filterFilter is...?

I made a few adjustments to my needs, instead of the watcher I used the filtered object inline

pagination total-items="filtered.length"

ng-repeat="item in filtered = (results | SubCategory:subcat) | startFrom:(CurrentPage-1)*ItemsPerPage | limitTo:ItemsPerPage "

This provides the items as filtered after the results has been run through a custom filter to allow for multiple subcategories for a shopping cart refining filter and then runs that array against the startFrom and limitTO filters.

@kmaida

This comment has been minimized.

Copy link
Owner Author

@kmaida kmaida commented Feb 2, 2015

filterFilter is Angular's dependency injection for using filters in a controller (filter name + Filter as a suffix). In this case, the filter's name is just "filter", hence "filterFilter". You can do this instead of injecting $filter. More information can be found on this SO question if you're looking for additional explanation: http://stackoverflow.com/questions/14302267/how-to-use-a-filter-in-a-controller/14303362#14303362

@tarun-dugar

This comment has been minimized.

Copy link

@tarun-dugar tarun-dugar commented Jun 15, 2015

Thanks a lot! Very useful :)

@chanelope

This comment has been minimized.

Copy link

@chanelope chanelope commented Jul 3, 2015

Just what I was looking for, thank you!!

@NikhilNanjappa

This comment has been minimized.

Copy link

@NikhilNanjappa NikhilNanjappa commented Jul 23, 2015

This is fine for a static data set (like $scope.items) in this case. Mostly that would not be the case, what if i'm getting the data dynamically using a https service. The data(dynamically fetched $scope.items) then won't be available outside that function scope. Can you please tell me how to solve such problem.

@jasenkoh

This comment has been minimized.

Copy link

@jasenkoh jasenkoh commented Jul 23, 2015

I am sharing curiosity with @NikhilNanjappa

@tootcsen

This comment has been minimized.

Copy link

@tootcsen tootcsen commented Aug 19, 2015

Hi, I get input is not defined in startForm filter, any idea?

@hirokoymj

This comment has been minimized.

Copy link

@hirokoymj hirokoymj commented Oct 14, 2015

Hello,
I know you answered about "filterFilter" above on Feb 2, but I still don't understand it.
I downloaded your code and changed $filter('startFrom')($scope.items, newVal) instead of "filterFilter".
Then search works but pagination doesn't updated. I thought "filterFilter" calls app.filter('startFrom', function (){}. Would you explain what function "filterFilter" is calling?

Thank you,

@Novaera

This comment has been minimized.

Copy link

@Novaera Novaera commented Oct 16, 2015

Awesome way to do it! Thanks a lot! +star

@srokatonie

This comment has been minimized.

Copy link

@srokatonie srokatonie commented Nov 30, 2015

@sergio-ivanuzzo

This comment has been minimized.

Copy link

@sergio-ivanuzzo sergio-ivanuzzo commented Jan 26, 2016

don't need startFrom, just use limitTo: perPage : (currentPage-1)*perPage

@yonineitor

This comment has been minimized.

Copy link

@yonineitor yonineitor commented Feb 3, 2016

why if type on input search "HelloWorldNotFonud"
when clear input, not show records.

@guilhermepatriarca

This comment has been minimized.

Copy link

@guilhermepatriarca guilhermepatriarca commented Apr 1, 2016

ty

@abhilive

This comment has been minimized.

Copy link

@abhilive abhilive commented Apr 26, 2016

Instead of building object $scope.items in controller I am fetching as json using ajax from server. So how can we implement this ?

@ChiefTwoPencils

This comment has been minimized.

Copy link

@ChiefTwoPencils ChiefTwoPencils commented Sep 7, 2016

@abhilive, it's essentially the same way except you'd have the items loaded from the server. This is the way I did it. Note that I use ControllerAs syntax as opposed to $scope. I do that with the angular.bind call in $watch (of course, some of my names differ but you should be able to figure it out.

$scope.$watch(angular.bind(this, function () {
    return this.search;
}), function (newVal, oldVal) {
    self.pagedClients = filterFilter(self.clients, newVal);
    self.totalClients = self.pagedClients.length;
    self.numPages = Math.ceil(self.totalClients / self.perPage);
    self.currentPage = 1;
}, true);

You'll also need to set the initial values for these when the data is first loaded and force the $watch to run.

... // ajax
    .then(
        function (data) {
            self.clients = data;
            self.totalClients = self.clients.length;
            self.numPages = Math.ceil(self.totalClients / self.perPage);
            self.currentPage = 1;
            self.search = '';
        },
...// more ajax
@ancientyouthman

This comment has been minimized.

Copy link

@ancientyouthman ancientyouthman commented Nov 4, 2016

Thanks for this, helped me out a lot.

@raank

This comment has been minimized.

Copy link

@raank raank commented Nov 9, 2016

OrderBy field?

@anilkanike

This comment has been minimized.

Copy link

@anilkanike anilkanike commented Feb 20, 2017

Good example. thanks

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 13, 2017

Thank you so much for this, This helps me with my current roadblock!

@bwoodlt

This comment has been minimized.

Copy link

@bwoodlt bwoodlt commented Apr 19, 2017

Currently having issues getting this to work inside Ajax call... I'd appreciate any help.. Spent a few hours on this :(

Main issue:

  • Pagination works fine but the filter doesnt. When I tried to filter an item(about 3000 items), it was only able to filter the page its currently on. For instance, if I'm on page 1, and searched for an item on page 8, it will return nothing, but if the item I'm searching for is on page 1, it will return the result.
    I know I'm missing something...

http://plnkr.co/edit/JbZyyCiT79SkTxscqM3N?p=preview

@bwoodlt

This comment has been minimized.

Copy link

@bwoodlt bwoodlt commented Apr 24, 2017

Fixed the above! thanks all!

@manjunath10073

This comment has been minimized.

Copy link

@manjunath10073 manjunath10073 commented Sep 26, 2017

Thanks for the post, here my question is when data increases the pagination numbers also increase. Is there way to show only few numbers with dots.....
image

@son2412

This comment has been minimized.

Copy link

@son2412 son2412 commented Jul 20, 2018

what the hell ? pagination tag...

@khairulhasanmd

This comment has been minimized.

Copy link

@khairulhasanmd khairulhasanmd commented Jul 26, 2018

@manjunath10073 i think to limit the buttons, we need to change the max-size value
<pagination page="currentPage" max-size="5" total-items="totalItems" items-per-page="entryLimit"></pagination>

@gowthambopathyraj

This comment has been minimized.

Copy link

@gowthambopathyraj gowthambopathyraj commented Apr 4, 2019

hi,
Same condition. but not working in my project. only change <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js" type="text/javascript"></script> to <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.3.js" type="text/javascript"></script>
plunker example code here,

http://plnkr.co/edit/9a8heE1eWLMA0FgR6reG?p=preview

please help me gowthamjob94@gmail.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment