paginacion - ¿Cómo hacer la paginación en AngularJS?
pagination angular 5 (21)
Tengo un conjunto de datos de aproximadamente 1000 elementos en memoria y estoy intentando crear un buscapersonas para este conjunto de datos, pero no estoy seguro de cómo hacerlo.
Estoy usando una función de filtro personalizado para filtrar los resultados, y eso funciona bien, pero de alguna manera necesito sacar el número de páginas.
¿Alguna pista?
Resumen : Paginación utilizando
- ng-repeat
- uib-pagination
Ver :
<div class="row">
<div class="col-lg-12">
<table class="table">
<thead style="background-color: #eee">
<tr>
<td>Dispature</td>
<td>Service</td>
<td>Host</td>
<td>Value</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in app.metricsList">
<td>{{x.dispature}}</td>
<td>{{x.service}}</td>
<td>{{x.host}}</td>
<td>{{x.value}}</td>
</tr>
</tbody>
</table>
<div align="center">
<uib-pagination items-per-page="app.itemPerPage" num-pages="numPages"
total-items="app.totalItems" boundary-link-numbers="true"
ng-model="app.currentPage" rotate="false" max-size="app.maxSize"
class="pagination-sm" boundary-links="true"
ng-click="app.getPagableRecords()"></uib-pagination>
<div style="float: right; margin: 15px">
<pre>Page: {{app.currentPage}} / {{numPages}}</pre>
</div>
</div>
</div>
</div>
Controlador JS :
app.controller(''AllEntryCtrl'',[''$scope'',''$http'',''$timeout'',''$rootScope'', function($scope,$http,$timeout,$rootScope){
var app = this;
app.currentPage = 1;
app.maxSize = 5;
app.itemPerPage = 5;
app.totalItems = 0;
app.countRecords = function() {
$http.get("countRecord")
.success(function(data,status,headers,config){
app.totalItems = data;
})
.error(function(data,status,header,config){
console.log(data);
});
};
app.getPagableRecords = function() {
var param = {
page : app.currentPage,
size : app.itemPerPage
};
$http.get("allRecordPagination",{params : param})
.success(function(data,status,headers,config){
app.metricsList = data.content;
})
.error(function(data,status,header,config){
console.log(data);
});
};
app.countRecords();
app.getPagableRecords();
}]);
Pistola de seguridad de interfaz de usuario angular - Directiva de paginación
Echa un vistazo a la directiva de paginación de UI Bootstrap . Terminé usándolo en lugar de lo que se publica aquí, ya que tiene suficientes funciones para mi uso actual y tiene una especificación de prueba exhaustiva para acompañarlo.
Ver
<!-- table here -->
<pagination
ng-model="currentPage"
total-items="todos.length"
max-size="maxSize"
boundary-links="true">
</pagination>
<!-- items/page select here if you like -->
Controlador
todos.controller("TodoController", function($scope) {
$scope.filteredTodos = []
,$scope.currentPage = 1
,$scope.numPerPage = 10
,$scope.maxSize = 5;
$scope.makeTodos = function() {
$scope.todos = [];
for (i=1;i<=1000;i++) {
$scope.todos.push({ text:"todo "+i, done:false});
}
};
$scope.makeTodos();
$scope.$watch("currentPage + numPerPage", function() {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
, end = begin + $scope.numPerPage;
$scope.filteredTodos = $scope.todos.slice(begin, end);
});
});
He hecho un plunker de trabajo para referencia.
Versión heredada:
Ver
<!-- table here -->
<div data-pagination="" data-num-pages="numPages()"
data-current-page="currentPage" data-max-size="maxSize"
data-boundary-links="true"></div>
<!-- items/page select here if you like -->
Controlador
todos.controller("TodoController", function($scope) {
$scope.filteredTodos = []
,$scope.currentPage = 1
,$scope.numPerPage = 10
,$scope.maxSize = 5;
$scope.makeTodos = function() {
$scope.todos = [];
for (i=1;i<=1000;i++) {
$scope.todos.push({ text:"todo "+i, done:false});
}
};
$scope.makeTodos();
$scope.numPages = function () {
return Math.ceil($scope.todos.length / $scope.numPerPage);
};
$scope.$watch("currentPage + numPerPage", function() {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
, end = begin + $scope.numPerPage;
$scope.filteredTodos = $scope.todos.slice(begin, end);
});
});
He hecho un plunker de trabajo para referencia.
Acabo de hacer un JSFiddle que muestra el orden de paginación + búsqueda + en cada columna usando el código btford: http://jsfiddle.net/SAWsA/11/
Ahí está mi ejemplo. Botón seleccionado en el centro de la lista Controlador. config >>>
$scope.pagination = {total: null, pages: [], config: {count: 10, page: 1, size: 7}};
Lógica para la paginación:
/*
Pagination
*/
$scope.$watch(''pagination.total'', function (total) {
if(!total || total <= $scope.pagination.config.count) return;
_setPaginationPages(total);
});
function _setPaginationPages(total) {
var totalPages = Math.ceil(total / $scope.pagination.config.count);
var pages = [];
var start = $scope.pagination.config.page - Math.floor($scope.pagination.config.size/2);
var finish = null;
if((start + $scope.pagination.config.size - 1) > totalPages){
start = totalPages - $scope.pagination.config.size;
}
if(start <= 0) {
start = 1;
}
finish = start + $scope.pagination.config.size - 1;
if(finish > totalPages){
finish = totalPages;
}
for (var i = start; i <= finish; i++) {
pages.push(i);
}
$scope.pagination.pages = pages;
}
$scope.$watch("pagination.config.page", function(page){
_setPaginationPages($scope.pagination.total);
_getRespondents($scope.pagination.config);
});
y mi punto de vista en el arranque
<ul ng-class="{hidden: pagination.total == 0}" class="pagination">
<li ng-click="pagination.config.page = pagination.config.page - 1"
ng-class="{disabled: pagination.config.page == 1}" ><a href="#">«</a></li>
<li ng-repeat="p in pagination.pages"
ng-click="pagination.config.page = p"
ng-class="{active: p == pagination.config.page}"><a href="#">{{p}}</a></li>
<li ng-click="pagination.config.page = pagination.config.page + 1"
ng-class="{disabled: pagination.config.page == pagination.pages.length}"><a href="#">»</a></li>
</ul >
Es útil
Debajo de la solución es bastante simple.
<pagination
total-items="totalItems"
items-per-page= "itemsPerPage"
ng-model="currentPage"
class="pagination-sm">
</pagination>
<tr ng-repeat="country in countries.slice((currentPage -1) * itemsPerPage, currentPage * itemsPerPage) ">
Desde Angular 1.4, el filtro limitTo
también acepta un segundo argumento opcional.
De la docs :
{{limitTo_expression | limitTo: limit: begin}}
comenzar (opcional) cadena | número
Índice en el que comenzar la limitación. Como índice negativo, el inicio indica un desplazamiento desde el final de la entrada. El valor predeterminado es 0.
Por lo tanto, no es necesario crear una nueva directiva . Este argumento se puede usar para establecer el desplazamiento de la paginación
ng-repeat="item in vm.items| limitTo: vm.itemsPerPage: (vm.currentPage-1)*vm.itemsPerPage"
El adaptador angular jQuery Mobile tiene un filtro de paginación con el que podría basarse.
Aquí hay un violín de demostración que lo usa (agregue más de 5 elementos y se pagine): http://jsfiddle.net/tigbro/Du2DY/
Aquí está la fuente: https://github.com/tigbro/jquery-mobile-angular-adapter/blob/master/src/main/webapp/utils/paging.js
Esta es una solución javascript pura que he envuelto como un servicio Angular para implementar la lógica de paginación como en los resultados de búsqueda de Google.
Demostración de trabajo en CodePen en http://codepen.io/cornflourblue/pen/KVeaQL/
Detalles y explicaciones en este blog.
function PagerService() {
// service definition
var service = {};
service.GetPager = GetPager;
return service;
// service implementation
function GetPager(totalItems, currentPage, pageSize) {
// default to first page
currentPage = currentPage || 1;
// default page size is 10
pageSize = pageSize || 10;
// calculate total pages
var totalPages = Math.ceil(totalItems / pageSize);
var startPage, endPage;
if (totalPages <= 10) {
// less than 10 total pages so show all
startPage = 1;
endPage = totalPages;
} else {
// more than 10 total pages so calculate start and end pages
if (currentPage <= 6) {
startPage = 1;
endPage = 10;
} else if (currentPage + 4 >= totalPages) {
startPage = totalPages - 9;
endPage = totalPages;
} else {
startPage = currentPage - 5;
endPage = currentPage + 4;
}
}
// calculate start and end item indexes
var startIndex = (currentPage - 1) * pageSize;
var endIndex = startIndex + pageSize;
// create an array of pages to ng-repeat in the pager control
var pages = _.range(startPage, endPage + 1);
// return object with all pager properties required by the view
return {
totalItems: totalItems,
currentPage: currentPage,
pageSize: pageSize,
totalPages: totalPages,
startPage: startPage,
endPage: endPage,
startIndex: startIndex,
endIndex: endIndex,
pages: pages
};
}
}
He extraído los bits relevantes aquí. Este es un buscapersonas tabular ''sin adornos'', por lo que no se incluye la clasificación o el filtrado. Siéntase libre de cambiar / agregar según sea necesario:
//your data source may be different. the following line is
//just for demonstration purposes only
var modelData = [{
text: ''Test1''
}, {
text: ''Test2''
}, {
text: ''Test3''
}];
(function(util) {
util.PAGE_SIZE = 10;
util.range = function(start, end) {
var rng = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++)
rng.push(i);
return rng;
};
util.Pager = function(data) {
var self = this,
_size = util.PAGE_SIZE;;
self.current = 0;
self.content = function(index) {
var start = index * self.size,
end = (index * self.size + self.size) > data.length ? data.length : (index * self.size + self.size);
return data.slice(start, end);
};
self.next = function() {
if (!self.canPage(''Next'')) return;
self.current++;
};
self.prev = function() {
if (!self.canPage(''Prev'')) return;
self.current--;
};
self.canPage = function(dir) {
if (dir === ''Next'') return self.current < self.count - 1;
if (dir === ''Prev'') return self.current > 0;
return false;
};
self.list = function() {
var start, end;
start = self.current < 5 ? 0 : self.current - 5;
end = self.count - self.current < 5 ? self.count : self.current + 5;
return Util.range(start, end);
};
Object.defineProperty(self, ''size'', {
configurable: false,
enumerable: false,
get: function() {
return _size;
},
set: function(val) {
_size = val || _size;
}
});
Object.defineProperty(self, ''count'', {
configurable: false,
enumerable: false,
get: function() {
return Math.ceil(data.length / self.size);
}
});
};
})(window.Util = window.Util || {});
(function(ns) {
ns.SampleController = function($scope, $window) {
$scope.ModelData = modelData;
//instantiate pager with array (i.e. our model)
$scope.pages = new $window.Util.Pager($scope.ModelData);
};
})(window.Controllers = window.Controllers || {});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-controller="Controllers.SampleController">
<thead>
<tr>
<th>
Col1
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in pages.content(pages.current)" title="{{item.text}}">
<td ng-bind-template="{{item.text}}"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<a href="#" ng-click="pages.prev()">«</a>
<a href="#" ng-repeat="n in pages.list()" ng-click="pages.current = n" style="margin: 0 2px;">{{n + 1}}</a>
<a href="#" ng-click="pages.next()">»</a>
</td>
</tr>
</tfoot>
</table>
He tenido que implementar la paginación varias veces con Angular, y siempre fue un poco molesto por algo que sentí que podía simplificarse. He utilizado algunas de las ideas presentadas aquí y en otros lugares para crear un módulo de paginación que hace que la paginación sea tan simple como:
<ul>
<li dir-paginate="item in items | itemsPerPage: 10">{{ item }}</li>
</ul>
// then somewhere else on the page ....
<dir-pagination-controls></dir-pagination-controls>
Eso es. Tiene las siguientes características:
- No se necesita un código personalizado en su controlador para vincular los
items
la colección a los enlaces de paginación. - No está obligado a usar una tabla o vista de cuadrícula, ¡puede paginar cualquier cosa que pueda repetir!
- Delegados en
ng-repeat
, por lo que puede utilizar cualquier expresión que se pueda usar válidamente en unang-repeat
, incluido el filtrado, el orden, etc. - Funciona en todos los controladores: la directiva
pagination-controls
no necesita saber nada sobre el contexto en el que se llama la directivapagination-controls
.
Demostración: http://plnkr.co/edit/Wtkv71LIqUR4OhzhgpqL?p=preview
Para aquellos que buscan una solución "plug and play", creo que encontrará esto útil.
Código
El código está disponible aquí en GitHub e incluye un buen conjunto de pruebas:
https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
Si está interesado, también escribí una breve pieza con un poco más de información sobre el diseño del módulo: http://www.michaelbromley.co.uk/blog/108/paginate-almost-anything-in-angularjs/
Los mensajes anteriores recomendaban básicamente cómo construir una paginación por ti mismo. Si usted es como yo y prefiere una directiva terminada, acabo de encontrar una excelente llamada ngTable . Es compatible con la clasificación, el filtrado y la paginación.
Es una solución muy limpia, todo lo que necesita en su opinión:
<table ng-table="tableParams" class="table">
<tr ng-repeat="user in $data">
<td data-title="''Name''" sortable="''name''">
{{user.name}}
</td>
<td data-title="''Age''" sortable="''age''">
{{user.age}}
</td>
</tr>
</table>
Y en el controlador:
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: {
name: ''asc'' // initial sorting
}
}, {
total: data.length, // length of data
getData: function($defer, params) {
// use build-in angular filter
var orderedData = params.sorting() ?
$filter(''orderBy'')(data, params.orderBy()) :
data;
var start = (params.page() - 1) * params.count();
var end = params.page() * params.count();
$defer.resolve(orderedData.slice( start, end));
}
});
Enlace a GitHub: https://github.com/esvit/ng-table/
Me gustaría agregar mi solución que funcione con ngRepeat
y los filtros que usa con ella sin usar un $watch
o una matriz segmentada.
¡Sus resultados de filtro serán paginados!
var app = angular.module(''app'', [''ui.bootstrap'']);
app.controller(''myController'', [''$scope'', function($scope){
$scope.list= [''a'', ''b'', ''c'', ''d'', ''e''];
$scope.pagination = {
currentPage: 1,
numPerPage: 5,
totalItems: 0
};
$scope.searchFilter = function(item) {
//Your filter results will be paginated!
//The pagination will work even with other filters involved
//The total number of items in the result of your filter is accounted for
};
$scope.paginationFilter = function(item, index) {
//Every time the filter is used it restarts the totalItems
if(index === 0)
$scope.pagination.totalItems = 0;
//This holds the totalItems after the filters are applied
$scope.pagination.totalItems++;
if(
index >= (($scope.pagination.currentPage - 1) * $scope.pagination.numPerPage)
&& index < ((($scope.pagination.currentPage - 1) * $scope.pagination.numPerPage) + $scope.pagination.numPerPage)
)
return true; //return true if item index is on the currentPage
return false;
};
}]);
En el HTML, asegúrese de aplicar sus filtros al ngRepeat
antes del filtro de paginación.
<table data-ng-controller="myController">
<tr data-ng-repeat="item in list | filter: searchFilter | filter: paginationFilter track by $index">
<td>
{{item}}
</td>
<tr>
</table>
<ul class="pagination-sm"
uib-pagination
data-boundary-links="true"
data-total-items="pagination.totalItems"
data-items-per-page="pagination.numPerPage"
data-ng-model="pagination.currentPage"
data-previous-text="‹"
data-next-text="›"
data-first-text="«"
data-last-text="»">
</ul>
Me gustaría poder comentar, pero tendré que dejar esto aquí:
La respuesta de Scotty.NET y el rehacer de user2176745 para versiones posteriores son geniales, pero ambos extrañan algo en lo que mi versión de AngularJS (v1.3.15) rompe en:
i no está definido en $ scope.makeTodos.
Como tal, el reemplazo con esta función lo corrige para versiones angulares más recientes.
$scope.makeTodos = function() {
var i;
$scope.todos = [];
for (i=1;i<=1000;i++) {
$scope.todos.push({ text:''todo ''+i, done:false});
}
};
Para cualquiera que tenga dificultades como yo para crear un paginador para una tabla, publico esto. Por lo tanto, en su opinión:
<pagination total-items="total" items-per-page="itemPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
<!-- To specify your choice of items Per Pages-->
<div class="btn-group">
<label class="btn btn-primary" ng-model="radioModel" btn-radio="''Left''" data-ng-click="setItems(5)">5</label>
<label class="btn btn-primary" ng-model="radioModel" btn-radio="''Middle''" data-ng-click="setItems(10)">10</label>
<label class="btn btn-primary" ng-model="radioModel" btn-radio="''Right''" data-ng-click="setItems(15)">15</label>
</div>
//And don''t forget in your table:
<tr data-ng-repeat="p in profiles | offset: (currentPage-1)*itemPerPage | limitTo: itemPerPage" >
En su angularJs:
var module = angular.module(''myapp'',[''ui.bootstrap'',''dialogs'']);
module.controller(''myController'',function($scope,$http){
$scope.total = $scope.mylist.length;
$scope.currentPage = 1;
$scope.itemPerPage = 2;
$scope.start = 0;
$scope.setItems = function(n){
$scope.itemPerPage = n;
};
// In case you can replace ($scope.currentPage - 1) * $scope.itemPerPage in <tr> by "start"
$scope.pageChanged = function() {
$scope.start = ($scope.currentPage - 1) * $scope.itemPerPage;
};
});
//and our filter
module.filter(''offset'', function() {
return function(input, start) {
start = parseInt(start, 10);
return input.slice(start);
};
});
Pregunta antigua, pero como creo que mi enfoque es un poco diferente y menos complejo, compartiré esto y espero que alguien además de mí lo encuentre útil.
Lo que encontré como una solución fácil y pequeña para la paginación es combinar una directiva con un filtro que usa las mismas variables de alcance.
Para implementar esto, agregue el filtro en la matriz y agregue el directiv como este
<div class="row">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items | cust_pagination:p_Size:p_Step">
<td>{{item.Name}}</td>
<td>{{item.Price}}</td>
<td>{{item.Quantity}}</td>
</tr>
</tbody>
</table>
<div cust-pagination p-items="items" p-boundarylinks="true" p-size="p_Size" p-step="p_Step"></div>
</div>
p_Size y p_Step son variables de alcance que pueden personalizarse en el ámbito; de lo contrario, el valor predeterminado de p_Size es 5 y p_Step es 1.
Cuando se cambia un paso en la paginación, se actualiza p_Step y se activará un nuevo filtro mediante el filtro cust_pagination. El filtro cust_pagination luego corta la matriz según el valor de p_Step como se muestra a continuación y solo devuelve los registros activos seleccionados en la sección de paginación
var startIndex = nStep * nPageSize;
var endIndex = startIndex + nPageSize;
var arr = items.slice(startIndex, endIndex);
return arr;
Puede hacerlo fácilmente utilizando la directiva de la interfaz de usuario de Bootstrap.
Esta respuesta es una modificación de la respuesta dada por @ Scotty.NET. He cambiado el código porque la directiva <pagination>
ahora está en desuso.
El siguiente código genera la paginación:
<ul uib-pagination boundary-links="true" total-items="totalItems" items-per-page="itemsPerPage" ng-model="currentPage" ng-change="pageChanged()" class="pagination" previous-text="‹" next-text="›" first-text="«" last-text="»"></ul>
Para hacerlo funcional, usa esto en tu controlador:
$scope.filteredData = []
$scope.totalItems = $scope.data.length;
$scope.currentPage = 1;
$scope.itemsPerPage = 5;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage)
, end = begin + $scope.itemsPerPage;
$scope.filteredData = $scope.data.slice(begin, end);
};
$scope.pageChanged();
Consulte esto para obtener más opciones de paginación: Directiva de paginación de la interfaz de usuario de Bootstrap
Recientemente implementé la paginación para el sitio Construido con Angular. Puede verificar la fuente: https://github.com/angular/builtwith.angularjs.org
Evitaría usar un filtro para separar las páginas. Debe dividir los elementos en páginas dentro del controlador.
Utilizo esta biblioteca de paginación de terceros y funciona bien. Puede hacer fuentes de datos locales / remotas y es muy configurable.
https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
<dir-pagination-controls
[max-size=""]
[direction-links=""]
[boundary-links=""]
[on-page-change=""]
[pagination-id=""]
[template-url=""]
[auto-hide=""]>
</dir-pagination-controls>
plunkr http://plnkr.co/edit/FUeWwDu0XzO51lyLAEIA?p=preview Scotty.NET para que use versiones más nuevas de angular, angular-ui y bootstrap.
Controlador
var todos = angular.module(''todos'', [''ui.bootstrap'']);
todos.controller(''TodoController'', function($scope) {
$scope.filteredTodos = [];
$scope.itemsPerPage = 30;
$scope.currentPage = 4;
$scope.makeTodos = function() {
$scope.todos = [];
for (i=1;i<=1000;i++) {
$scope.todos.push({ text:''todo ''+i, done:false});
}
};
$scope.figureOutTodosToDisplay = function() {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage);
var end = begin + $scope.itemsPerPage;
$scope.filteredTodos = $scope.todos.slice(begin, end);
};
$scope.makeTodos();
$scope.figureOutTodosToDisplay();
$scope.pageChanged = function() {
$scope.figureOutTodosToDisplay();
};
});
Componente UI Bootstrap
<pagination boundary-links="true"
max-size="3"
items-per-page="itemsPerPage"
total-items="todos.length"
ng-model="currentPage"
ng-change="pageChanged()"></pagination>
es una maravillosa elección
Una directiva para ayudar en la paginación de grandes conjuntos de datos mientras se requiere el mínimo de información de paginación real. Somos muy dependientes del servidor para "filtrar" los resultados en este esquema de paginación. La idea central es que solo queremos mantener la "página" activa de elementos, en lugar de mantener la lista completa de elementos en memoria y paginación en el lado del cliente.
ng-repetir paginación
<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>
<script>
var app=angular.module(''myApp'', []);
app.controller(''MyCtrl'', [''$scope'', ''$filter'', function ($scope, $filter) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [];
$scope.q = '''';
$scope.getData = function () {
return $filter(''filter'')($scope.data, $scope.q)
}
$scope.numberOfPages=function(){
return Math.ceil($scope.getData().length/$scope.pageSize);
}
for (var i=0; i<65; i++) {
$scope.data.push("Item "+i);
}
}]);
app.filter(''startFrom'', function() {
return function(input, start) {
start = +start; //parse to int
return input.slice(start);
}
});
</script>