I am using angular datatable to display the response from the http request
I will send the request to web API that will communicate with the SQL Server database and gives the response
It is working fine for the response that are having the data, but for null response the datatable displayed in the UI is displaying the values from the previous response
Can anyone please help me to intimate like "There are no records inserted for the given request" when the response is null ?
Angular JS:
$scope.currentPage = 0; //current page
$scope.entryLimit = 10;
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < ($scope.filteredItems/$scope.entryLimit) - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
$scope.filter = function() {
$timeout(function() {
$scope.filteredItems = $scope.filtered.length;
}, 10);
};
$scope.sort_by = function(predicate) {
$scope.predicate = predicate;
$scope.reverse = !$scope.reverse;
};
$scope.range = function (size,start, cu,elimit) {
var ret = [];
if( ($scope.filteredItems/$scope.entryLimit) < elimit)
{
if(($scope.filteredItems/$scope.entryLimit) ==0)
{
elimit = 1;
}
else
{
elimit = Math.ceil($scope.filteredItems/$scope.entryLimit);
}
}
var end = parseInt(cu)+parseInt(elimit);
console.log(size,start, end);
if (size < end) {
end = size;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
console.log(ret);
return ret;
};
HTML:
<div ng-show="filteredItems > 0">
<div class="col-md-2">PageSize:
<select ng-model="entryLimit" class="form-control">
<option>10</option>
<option>20</option>
<option>50</option>
<option>100</option>
</select>
</div>
<div class="col-md-3">Filter:
<input type="text" ng-model="search" ng-change="filter()" placeholder="Filter" class="form-control" />
</div>
<div class="col-md-4">
<h5>Filtered {{ filtered.length }} of {{ totalItems}} total </h5>
</div>
</div>
<div>
<div class="col-md-12" ng-show="filteredItems > 0" >
<br/>
<br/>
<table class="table table-bordered table-striped table-hover " style=" outline: 1px solid orange;" >
<thead>
<tr>
<th ng-repeat="(key,value) in items[0]" ng-click="sort_by(key);" >{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="items in filtered = (list | filter:search | orderBy : predicate :reverse) | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit ">
<td ng-repeat="(key,value) in items" > {{value}} </td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-12" ng-show="filteredItems == 0">
<div class="col-md-12">
<h4>No details found</h4>
</div>
</div>
<div class="col-md-12" ng-show="filteredItems > 0 ">
<div colspan="6">
<div class="pagination pull-right">
<ul>
<li ng-class="{disabled: currentPage == 0}">
<a href ng-click="prevPage()">« Prev</a>
</li>
<li ng-repeat="n in range(filteredItems, currentPage, currentPage , 5) "
ng-class="{active: n == currentPage}"
ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: (currentPage) == filteredItems - 1}">
<a href ng-click="nextPage()">Next »</a>
</li>
</ul>
</div>
</div>
</div>
</div>
My Http resonse will be resent in $scope.items.
Thanks
Looks like maybe you are keeping the response from the API call in $scope for longer than needed.
Destroy and refresh the model object in $scope prior to API call so that the $scope only has objects from the new response.
eg.
stories.destory()
In your controller, say your model
$scope.items.destroy();
// API call to receive results form server,
// now check if you received items response from server, if not display the message to the user.
Thanks,
Paul
Try to validate the response before populating the table...
Something like
if(response!== null){
$scope.items={};
return;
}
else{
$scope.items=response;
}
Related
I am working on a small application that displays a "users" JSON in an HTML5 table. It uses Bootstrap 3 and AngularJS. I want to paginate this table.
I do not have an array to loop through, with ng-repeat. I have the number of pages.
var root = 'https://jsonplaceholder.typicode.com';
// Create an Angular module named "usersApp"
var app = angular.module("usersApp", []);
// Create controller for the "usersApp" module
app.controller("usersCtrl", ["$scope", "$http", "$filter", function($scope, $http, $filter) {
var url = root + "/users";
$scope.userList = [];
$scope.search = "";
$scope.filterList = function() {
$scope.userList = $filter('filter')($scope.users, $scope.search);
$scope.itemsCount = $scope.userList.length;
$scope.pageMax = Math.ceil($scope.itemsCount / $scope.perPage);
};
$http.get(url)
.then(function(data) {
// Users arary
$scope.users = data.data;
$scope.filterList();
// Order by function
$scope.orderByMe = function(criteria) {
$scope.myOrderBy = criteria;
}
// Paginate
$scope.pageNum = 1;
$scope.perPage = 3;
$scope.startAt = 0;
$scope.filterList();
$scope.currentPage = function() {
$scope.startAt = $scope.index * $scope.perPage;
};
$scope.prevPage = function() {
if ($scope.pageNum > 1) {
$scope.pageNum = $scope.pageNum - 1;
$scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
}
};
$scope.nextPage = function() {
if ($scope.pageNum < $scope.pageMax) {
$scope.pageNum = $scope.pageNum + 1;
$scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
}
};
});
}]);
.table-container {
margin: 10px 0 0 0 !important;
}
.table-responsive {
margin: 0 !important;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<div data-ng-app="usersApp">
<div class="container" data-ng-controller="usersCtrl">
<div class="panel panel-default table-container">
<div class="panel-heading">Users</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-12">
<div class="form-group search-box">
<input type="text" class="form-control" id="search"
placeholder="Search User" data-ng-model="search"
ng-change="filterList()">
</div>
</div>
<div class="col-sm-12">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th>#</th>
<th ng-click="orderByMe('name')">Full name</th>
<th ng-click="orderByMe('email')">Email</th>
<th ng-click="orderByMe('city')">City</th>
<th>Street</th>
<th>Suite</th>
<th>Zipcode</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="user in userList|orderBy:myOrderBy| limitTo : perPage : startAt">
<td>{{$index + startAt + 1}}</td>
<td>{{user.name}}</td>
<td>{{user.email | lowercase}}</td>
<td>{{user.address.city}}</td>
<td>{{user.address.street}}</td>
<td>{{user.address.suite}}</td>
<td>{{user.address.zipcode}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="text-center" ng-if="pageMax > 1">
<ul class="pagination pagination-sm">
<li><i class="fa fa-chevron-left"></i></li>
<li ng-repeat="n in [].constructor(pageMax) track by $index">
{{$index+1}}
</li>
<li><i class="fa fa-chevron-right"></i></li>
</ul>
</div>
</div>
</div>
Whenever I click the Next and Previous page pagination items (the chevrons), the script works right, but when I click the numbered pagination items, the $scope.startAt variable does not update and the table row numbers are NaN.
What am I doing wrong?
Invoke the currentPage function with $index as an argument:
<ul class="pagination pagination-sm">
<li><i class="fa fa-chevron-left"></i></li>
<li ng-repeat="n in [].constructor(pageMax) track by $index">
̶<̶a̶ ̶h̶r̶e̶f̶=̶"̶#̶"̶ ̶n̶g̶-̶c̶l̶i̶c̶k̶=̶"̶c̶u̶r̶r̶e̶n̶t̶P̶a̶g̶e̶(̶)̶"̶>̶{̶{̶$̶i̶n̶d̶e̶x̶+̶1̶}̶}̶<̶/̶a̶>̶
{{$index+1}}
</li>
<li><i class="fa fa-chevron-right"></i></li>
</ul>
BEFORE
$scope.currentPage = function() {
$scope.startAt = $scope.index * $scope.perPage;
};
After
$scope.currentPage = function(index) {
$scope.pageNum = index+1;
$scope.startAt = index * $scope.perPage;
};
How would you update the pagination with the search filter?
$scope.filterList = function() {
var oldList = $scope.userList || [];
$scope.userList = $filter('filter')($scope.users, $scope.search);
if (oldList.length != $scope.userList.length) {
$scope.pageNum = 1;
$scope.startAt = 0;
};
$scope.itemsCount = $scope.userList.length;
$scope.pageMax = Math.ceil($scope.itemsCount / $scope.perPage);
};
The DEMO
angular.module("usersApp", [])
.controller("usersCtrl", function($scope, $http, $filter) {
var root = '//jsonplaceholder.typicode.com';
var url = root + "/users";
$scope.userList = [];
$scope.search = "";
$scope.filterList = function() {
var oldList = $scope.userList || [];
$scope.userList = $filter('filter')($scope.users, $scope.search);
if (oldList.length != $scope.userList.length) {
$scope.pageNum = 1;
$scope.startAt = 0;
};
$scope.itemsCount = $scope.userList.length;
$scope.pageMax = Math.ceil($scope.itemsCount / $scope.perPage);
};
// Order by function
$scope.orderByMe = function(criteria) {
$scope.myOrderBy = criteria;
};
$http.get(url)
.then(function(response) {
$scope.users = response.data;
$scope.filterList();
// Paginate
$scope.pageNum = 1;
$scope.perPage = 3;
$scope.startAt = 0;
$scope.filterList();
});
$scope.currentPage = function(index) {
$scope.pageNum = index+1;
$scope.startAt = index * $scope.perPage;
};
$scope.prevPage = function() {
if ($scope.pageNum > 1) {
$scope.pageNum = $scope.pageNum - 1;
$scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
}
};
$scope.nextPage = function() {
if ($scope.pageNum < $scope.pageMax) {
$scope.pageNum = $scope.pageNum + 1;
$scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
}
};
});
.table-container {
margin: 10px 0 0 0 !important;
}
.table-responsive {
margin: 0 !important;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<div data-ng-app="usersApp">
<div class="container" data-ng-controller="usersCtrl">
<div class="panel panel-default table-container">
<div class="panel-heading">Users</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-12">
<div class="form-group search-box">
<input type="text" class="form-control" id="search" placeholder="Search User" data-ng-model="search" ng-change="filterList()">
</div>
</div>
<div class="col-sm-12">
<div class="table-responsive">
<table class="table table-striped table-bordered" id="dataTable">
<thead>
<tr>
<th>#</th>
<th ng-click="orderByMe('name')">Full name</th>
<th ng-click="orderByMe('email')">Email</th>
<th ng-click="orderByMe('city')">City</th>
<th>Street</th>
<th>Suite</th>
<th>Zipcode</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="user in userList|orderBy:myOrderBy| limitTo : perPage : startAt">
<td>{{$index + startAt + 1}}</td>
<td>{{user.name}}</td>
<td>{{user.email | lowercase}}</td>
<td>{{user.address.city}}</td>
<td>{{user.address.street}}</td>
<td>{{user.address.suite}}</td>
<td>{{user.address.zipcode}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="text-center" ng-if="pageMax > 1">
<ul class="pagination pagination-sm">
<li><i class="fa fa-chevron-left"></i></li>
<li ng-repeat="n in [].constructor(pageMax) track by $index">{{$index+1}}
</li>
<li><i class="fa fa-chevron-right"></i></li>
</ul>
</div>
</div>
</div>
I'm doing client-side pagination using angular ui-bootstrap pagination to add paging to the list and then I'm getting a problem that the sorting and filtering process only sort and filter the data only in the current page.
Here is the code snippets in view to display the data:
<tr ng-repeat="reminderType in reminderTypes | filter: paginate | filter: searchText | orderBy:sortBy:sortDescending">
<td>
<a class="btn btn-sm btn-primary" ng-click="editReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-pencil"></i> Edit</a>
<a class="btn btn-sm btn-info" ng-click="detailsReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-eye-open"></i> View</a>
</td>
<td>{{reminderType.Name}}</td>
<td>{{reminderType.EmailTemplate}}</td>
</tr>
...
<uib-pagination class="pagination-sm"
total-items="totalItems" max-size="maxSize" items-per-page="numPerPage" num-pages="numPages"
ng-model="currentPage" boundary-links="true" rotate="false"></uib-pagination>
and here is the code snippets in controller to do the pagination:
$scope.maxSize = 3;
$scope.totalItems = 7;
$scope.currentPage = 1;
$scope.numPerPage = 2;
$scope.paginate = function (value) {
var begin, end, index;
begin = ($scope.currentPage - 1) * $scope.numPerPage;
end = begin + $scope.numPerPage;
index = $scope.reminderTypes.indexOf(value);
return (begin <= index && index < end);
};
I also check this link on SO, but it doesn't work.
How to make this work to sort and filter the data across the page?
I've posted the complete code in plnkr
For some reason I'm unable to fork your plunkr, but here is a fix. The JS:
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('PagerDemoCtrl', function($scope) {
$scope.reminderTypes = [{"ReminderTypeID":1,"Name":"STAMPING OF SPA","EmailTemplate":null},{"ReminderTypeID":2,"Name":"CONDITION PRECEDENT","EmailTemplate":null},{"ReminderTypeID":3,"Name":"STATE AUTHORITY CONSENT","EmailTemplate":null},{"ReminderTypeID":4,"Name":"PAYMENT OF BALANCE PURCHASE PRICE","EmailTemplate":null},{"ReminderTypeID":5,"Name":"CKHT FILING","EmailTemplate":null},{"ReminderTypeID":6,"Name":"TRANSFER FORM 14A","EmailTemplate":null},{"ReminderTypeID":7,"Name":"TRANSFER NOTICE OF ASSESSMENT","EmailTemplate":null}]
$scope.sortBy = 'Name';
$scope.sortDescending = false;
$scope.filteredRT = angular.copy($scope.reminderTypes);
$scope.searchText = '';
$scope.maxSize = 3;
$scope.totalItems = 7;
$scope.currentPage = 1;
$scope.numPerPage = 2;
$scope.paginate = function (value) {
var begin, end, index;
begin = ($scope.currentPage - 1) * $scope.numPerPage;
end = begin + $scope.numPerPage;
index = $scope.filteredRT.indexOf(value);
return (begin <= index && index < end);
};
$scope.filter = function(){
var results = $scope.filteredRT;
results.length = 0;
var searchText = $scope.searchText;
var reminderTypes = $scope.reminderTypes;
for(var i = 0; i < reminderTypes.length; ++i){
if(searchText.length > 0){
if(reminderTypes[i].Name.includes(searchText)){
results.push(reminderTypes[i]);
}
} else {
results.push(reminderTypes[i]);
}
}
$scope.totalItems = results.length;
}
});
And the HTML
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.3.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="PagerDemoCtrl">
<div class="row">
<div class="col-md-offset-9 col-md-3">
<p>
<div class="input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span>
<input type="text" class="form-control" placeholder="Enter Search Text"
ng-model="searchText" ng-change="filter()" />
</div>
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table class="table table-striped table-hover table-condensed">
<thead>
<tr class="bg-info">
<th></th>
<th>
<a ng-click="sortBy = 'Name'; sortDescending = !sortDescending">Reminder Type Name</a>
<span ng-show="sortBy == 'Name' && !sortDescending" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortBy == 'Name' && sortDescending" class="glyphicon glyphicon-chevron-up"></span>
</th>
<th>
<a ng-click="sortBy = 'EmailTemplate'; sortDescending = !sortDescending">Email Template</a>
<span ng-show="sortBy == 'EmailTemplate' && !sortDescending" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortBy == 'EmailTemplate' && sortDescending" class="glyphicon glyphicon-chevron-up"></span>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="reminderType in filteredRT | filter: paginate | orderBy:sortBy:sortDescending">
<td>
<a class="btn btn-sm btn-primary" ng-click="editReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-pencil"></i> Edit</a>
<a class="btn btn-sm btn-info" ng-click="detailsReminderType(reminderType.ReminderTypeID)"><i class="glyphicon glyphicon-eye-open"></i> View</a>
</td>
<td>{{reminderType.Name}}</td>
<td>{{reminderType.EmailTemplate}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3" class="text-right">
Showing page {{currentPage}} of {{numPages}}
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<uib-pagination class="pagination-sm"
total-items="totalItems" max-size="maxSize" items-per-page="numPerPage" num-pages="numPages"
ng-model="currentPage" boundary-links="true" rotate="false"></uib-pagination>
</div>
</div>
</div>
</body>
</html>
In particular, I added a ngChange directive in the input filter, and now a copy of reminderTypes is used. Unfortunately, I think that what you aim to do is a bit too complex to work with angular filters alone. I didn't test the order by but the pagination seems to work just fine in this way.
EDIT : juste adding the correct fork that respond to the question: https://plnkr.co/edit/HMw8U4OUsW5DNDGfQKHY?p=preview
I am new in angularJS .. when I delete row from table, i want to show next one from next page to keep rows number = 3 (for example)..
html :here are parts of codes :
<tbody id="t"> <!-- fetch data from DB -->
<tr id="tr-{{item.id}}" ng-repeat="item in ItemsByPage[currentPage]">
<td>
<div ng-model="tid"> {{item.id}} </div>
</td>
<td id="tdn-{{item.id}}">
<div ng-model="tname">{{item.name}} </div>
</td>
</tr>
</tbody>
<ul class="pagination">
<li>First</li>
<li ng-repeat="n in range(ItemsByPage.length)">1</li>
<li>Last</li>
</ul>
<div class="col-xs-4"> <!-- delete user -->
<input type="text" ng-model="delId" class="form-control" placeholder="Enter user id to delete the user">
<button ng-click="deleteuser(delId)" type="button" class="btn btn-primary">Delete User</button>
</div>
JS:
$scope.deleteuser = function (delId) {
var data = {delId : $scope.delId};
$http.post('delete.php', data )
.success(function(response) {
$("#tr-"+delId).hide();
console.log($("#tr-"+delId).next());
$("#tr-"+delId).next().show();// It doesnt work
});
$scope.resetAll();
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
$scope.firstPage = function () {
$scope.currentPage = 0;
};
$scope.lastPage = function () {
$scope.currentPage = $scope.ItemsByPage.length - 1;
};
I read about $routeProvider and routing between pages, but i didnt know how to use it with pagination,, so if the routing is the solution, how to do it in my code?
thanx alot ...
plunker : http://plnkr.co/edit/6GnDdNesbfoy2VbdF2Cr?p=preview
$scope.fetchStatus = function (job) {
$http
.get('http://gtrapi/pool/checkStatus/' + sessionId + '/' + job.jobId)
.success(function (response) {
job[job.jobId] = response;
if (response.status !== 'InProgress') {
$scope.refreshDataTimeout = $timeout($scope.fetchStatus(job), 1000);
}
})
.error (function () {
});
};
Here is my HTML code
<div ng-repeat="job in gtrLogs" class="each-log">
<div class="row job-id">
<div class="col-xs-2">
Job ID: {{job.jobId}}
</div>
<div class="col-xs-10">
End Point: {{job.changes.endpoint}}
</div>
</div>
<div class="each-job" ng-init="fetchStatus(job)">
<div class="job-header row">
<span class="col-xs-6">Job Status: <strong>{{job[job.jobId].status}}</strong>
<span class="glyphicon" ng-class="{'glyphicon-refresh spin' : job[job.jobId].status === 'InProgress', 'glyphicon-ok' : job[job.jobId].status === 'submitted', 'glyphicon-remove' : job[job.jobId].status === 'Aborted'}"></span>
</span>
<span class="col-xs-6">
<span class="glyphicon glyphicon-stop pull-right" ng-click="stopLogs()" tooltip="Stop Action"></span>
<span class="glyphicon glyphicon-repeat pull-right" ng-click="rollBack()" tooltip="Roll Back"></span>
</span>
</div>
<div class="logs-progress">
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th>
Message
</th>
<th>
Time
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in job[job.jobId].logs">
<td>{{row.msg}}</td>
<td>{{row.time | date:'yyyy/MM/dd HH:mm:ss'}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
I have to update the data every second and placed $timeout in the function. But because the function is being called multiple times from the HTML the calls are nested.
How Do I keep polling with respect to the same job.
Since you have a unique jobid, use can use that to maintain an array of key value pairs where your job id can correspond to a unique counter.
var counters = [];
$scope.fetchStatus = function (job) {
$http
.get('http://url:9090/gtrapi/pool/checkStatus/' + sessionId + '/' + job.jobId)
.success(function (response) {
job[job.jobId] = response;
if (response.status !== 'InProgress') {
updateCounter(job.jobId);
$scope.refreshDataTimeout = $timeout($scope.fetchStatus(job), 1000);
}
})
.error (function () {
});
};
function updateCounter(jobId) {
var exists = false,
jobId = parseInt(jobId);
for (var i in counters) {
if (counters[i].id === jobId) {
projects[i].counter++;
exists = true;
break;
}
}
if (!exists) {
counters.push({id: jobId, counter: 0});
}
}
I'm trying to add pages to my list. I followed the AngularJS tutorial, the one about smartphones and I'm trying to display only certain number of objects. Here is my html file:
<div class='container-fluid'>
<div class='row-fluid'>
<div class='span2'>
Search: <input ng-model='searchBar'>
Sort by:
<select ng-model='orderProp'>
<option value='name'>Alphabetical</option>
<option value='age'>Newest</option>
</select>
You selected the phones to be ordered by: {{orderProp}}
</div>
<div class='span10'>
<select ng-model='limit'>
<option value='5'>Show 5 per page</option>
<option value='10'>Show 10 per page</option>
<option value='15'>Show 15 per page</option>
<option value='20'>Show 20 per page</option>
</select>
<ul class='phones'>
<li class='thumbnail' ng-repeat='phone in phones | filter:searchBar | orderBy:orderProp | limitTo:limit'>
<a href='#/phones/{{phone.id}}' class='thumb'><img ng-src='{{phone.imageUrl}}'></a>
<a href='#/phones/{{phone.id}}'>{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
</div>
</div>
</div>
I've added a select tag with some values in order to limit the number of items that will be displayed. What I want now is to add the pagination to display the next 5, 10, etc.
I have a controller that works with this:
function PhoneListCtrl($scope, Phone){
$scope.phones = Phone.query();
$scope.orderProp = 'age';
$scope.limit = 5;
}
And also I have a module in order to retrieve the data from the json files.
angular.module('phonecatServices', ['ngResource']).
factory('Phone', function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method: 'GET', params:{phoneId:'phones'}, isArray:true}
});
});
If you have not too much data, you can definitely do pagination by just storing all the data in the browser and filtering what's visible at a certain time.
Here's a simple pagination example from the list of fiddles on the angular.js Github wiki, which should be helpful:
var app=angular.module('myApp', []);
function MyCtrl($scope) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [];
$scope.numberOfPages=function(){
return Math.ceil($scope.data.length/$scope.pageSize);
}
for (var i=0; i<45; i++) {
$scope.data.push("Item "+i);
}
}
//We already have a limitTo filter built-in to angular,
//let's make a startFrom filter
app.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in data | startFrom:currentPage*pageSize | limitTo:pageSize">
{{item}}
</li>
</ul>
<button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">
Previous
</button>
{{currentPage+1}}/{{numberOfPages()}}
<button ng-disabled="currentPage >= data.length/pageSize - 1" ng-click="currentPage=currentPage+1">
Next
</button>
</div>
I copied the accepted answer but added some Bootstrap classes to the HTML:
var app=angular.module('myApp', []);
function MyCtrl($scope) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [];
$scope.numberOfPages=function(){
return Math.ceil($scope.data.length/$scope.pageSize);
}
for (var i=0; i<45; i++) {
$scope.data.push("Item "+i);
}
}
//We already have a limitTo filter built-in to angular,
//let's make a startFrom filter
app.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
<html xmlns:ng="http://angularjs.org" ng-app lang="en">
<head>
<meta charset="utf-8">
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.no-icons.min.css" rel="stylesheet">
<link href="http://netdna.bootstrapcdn.com/font-awesome/2.0/css/font-awesome.css" rel="stylesheet">
<script src="http://code.angularjs.org/1.1.0/angular.min.js"></script>
</head>
<body>
<script type="text/javascript">
var sortingOrder = 'name';
</script>
<div ng-controller="ctrlRead">
<div class="input-append">
<input type="text" ng-model="query" ng-change="search()" class="input-large search-query" placeholder="Search">
<span class="add-on"><i class="icon-search"></i></span>
</div>
<table class="table table-striped table-condensed table-hover">
<thead>
<tr>
<th class="id">Id <a ng-click="sort_by('id')"><i class="icon-sort"></i></a></th>
<th class="name">Name <a ng-click="sort_by('name')"><i class="icon-sort"></i></a></th>
<th class="description">Description <a ng-click="sort_by('description')"><i class="icon-sort"></i></a></th>
<th class="field3">Field 3 <a ng-click="sort_by('field3')"><i class="icon-sort"></i></a></th>
<th class="field4">Field 4 <a ng-click="sort_by('field4')"><i class="icon-sort"></i></a></th>
<th class="field5">Field 5 <a ng-click="sort_by('field5')"><i class="icon-sort"></i></a></th>
</tr>
</thead>
<tfoot>
<td colspan="6">
<div class="pagination pull-right">
<ul>
<li ng-class="{disabled: currentPage == 0}">
<a href ng-click="prevPage()">« Prev</a>
</li>
<li ng-repeat="n in range(pagedItems.length)"
ng-class="{active: n == currentPage}"
ng-click="setPage()">
<a href ng-bind="n + 1">1</a>
</li>
<li ng-class="{disabled: currentPage == pagedItems.length - 1}">
<a href ng-click="nextPage()">Next »</a>
</li>
</ul>
</div>
</td>
</tfoot>
<tbody>
<tr ng-repeat="item in pagedItems[currentPage] | orderBy:sortingOrder:reverse">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
<td>{{item.field3}}</td>
<td>{{item.field4}}</td>
<td>{{item.field5}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
http://jsfiddle.net/SAWsA/11/
I've built a module that makes in-memory pagination incredibly simple.
It allows you to paginate by simply replacing ng-repeat with dir-paginate, specifying the items per page as a piped filter, and then dropping the controls wherever you like in the form of a single directive, <dir-pagination-controls>
To take the original example asked by Tomarto, it would look like this:
<ul class='phones'>
<li class='thumbnail' dir-paginate='phone in phones | filter:searchBar | orderBy:orderProp | limitTo:limit | itemsPerPage: limit'>
<a href='#/phones/{{phone.id}}' class='thumb'><img ng-src='{{phone.imageUrl}}'></a>
<a href='#/phones/{{phone.id}}'>{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
<dir-pagination-controls></dir-pagination-controls>
There is no need for any special pagination code in your controller. It's all handled internally by the module.
Demo: http://plnkr.co/edit/Wtkv71LIqUR4OhzhgpqL?p=preview
Source: dirPagination of GitHub
I know this thread is old now but I am answering it to keep things a bit updated.
With Angular 1.4 and above you can directly use limitTo filter which apart from accepting the limit parameter also accepts a begin parameter.
Usage: {{ limitTo_expression | limitTo : limit : begin}}
So now you may not need to use any third party library to achieve something like pagination. I have created a fiddle to illustrate the same.
Check out this directive: https://github.com/samu/angular-table
It automates sorting and pagination a lot and gives you enough freedom to customize your table/list however you want.
Here is a demo code where there is pagination + Filtering with AngularJS :
https://codepen.io/lamjaguar/pen/yOrVym
JS :
var app=angular.module('myApp', []);
// alternate - https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
// alternate - http://fdietz.github.io/recipes-with-angular-js/common-user-interface-patterns/paginating-through-client-side-data.html
app.controller('MyCtrl', ['$scope', '$filter', function ($scope, $filter) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [];
$scope.q = '';
$scope.getData = function () {
// needed for the pagination calc
// https://docs.angularjs.org/api/ng/filter/filter
return $filter('filter')($scope.data, $scope.q)
/*
// manual filter
// if u used this, remove the filter from html, remove above line and replace data with getData()
var arr = [];
if($scope.q == '') {
arr = $scope.data;
} else {
for(var ea in $scope.data) {
if($scope.data[ea].indexOf($scope.q) > -1) {
arr.push( $scope.data[ea] );
}
}
}
return arr;
*/
}
$scope.numberOfPages=function(){
return Math.ceil($scope.getData().length/$scope.pageSize);
}
for (var i=0; i<65; i++) {
$scope.data.push("Item "+i);
}
// A watch to bring us back to the
// first pagination after each
// filtering
$scope.$watch('q', function(newValue,oldValue){ if(oldValue!=newValue){
$scope.currentPage = 0;
}
},true);
}]);
//We already have a limitTo filter built-in to angular,
//let's make a startFrom filter
app.filter('startFrom', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
HTML :
<div ng-app="myApp" ng-controller="MyCtrl">
<input ng-model="q" id="search" class="form-control" placeholder="Filter text">
<select ng-model="pageSize" id="pageSize" class="form-control">
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
<option value="20">20</option>
</select>
<ul>
<li ng-repeat="item in data | filter:q | startFrom:currentPage*pageSize | limitTo:pageSize">
{{item}}
</li>
</ul>
<button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">
Previous
</button> {{currentPage+1}}/{{numberOfPages()}}
<button ng-disabled="currentPage >= getData().length/pageSize - 1" ng-click="currentPage=currentPage+1">
Next
</button>
</div>