Come fare il paging in AngularJS?

Ho un set di dati di circa 1000 elementi in memoria e sto tentando di creare un cercapersone per questo set di dati, ma non sono sicuro su come farlo.

Sto usando una funzione di filtro personalizzata per filtrare i risultati, e questo funziona bene, ma in qualche modo ho bisogno di ottenere il numero di pagine.

Qualche indizio?

Bootstrap UI angular – Direttiva di impaginazione

Controlla la direttiva di impaginazione dell’UI Bootstrap . Ho finito per usarlo piuttosto che ciò che è pubblicato qui in quanto ha abbastanza funzionalità per il mio uso corrente e ha una specifica di prova approfondita per accompagnarlo.

vista

    

controllore

 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); }); }); 

Ho fatto un plunker funzionante per riferimento.


Versione legacy:

vista

  

controllore

 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); }); }); 

Ho fatto un plunker funzionante per riferimento.

Di recente ho implementato il paging per il sito Built with Angular. Puoi controllare la fonte: https://github.com/angular/builtwith.angularjs.org

Eviterei di usare un filtro per separare le pagine. È necessario suddividere gli articoli in pagine all’interno del controller.

Ho dovuto implementare l’impaginazione diverse volte con Angular, ed era sempre un po ‘un dolore per qualcosa che sentivo potesse essere semplificato. Ho usato alcune delle idee presentate qui e altrove per creare un modulo di impaginazione che rende l’impaginazione semplice come:

 
  • {{ item }}
// then somewhere else on the page ....

Questo è tutto. Ha le seguenti caratteristiche:

  • Non è necessario alcun codice personalizzato nel controller per bind gli items della raccolta ai collegamenti di impaginazione.
  • Non sei obbligato a usare un tavolo o una griglia: puoi impaginare tutto ciò che puoi ripetere!
  • Delegati a ng-repeat , quindi puoi usare qualsiasi espressione che possa essere validamente usata in una ng-repeat , incluso il filtraggio, l’ordinamento, ecc.
  • Funziona tra i controller: la direttiva sui controlli di pagination-controls non ha bisogno di sapere nulla sul contesto in cui viene chiamata la direttiva paginate .

Demo: http://plnkr.co/edit/Wtkv71LIqUR4OhzhgpqL?p=preview

Per coloro che sono alla ricerca di una soluzione “plug and play”, penso che lo troverai utile.

Codice

Il codice è disponibile qui su GitHub e include una serie di test piuttosto buona:

https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination

Se sei interessato, ho anche scritto un breve pezzo con un po ‘di più informazioni sul design del modulo: http://www.michaelbromley.co.uk/blog/108/paginate-almost-anything-in-angularjs/

Ho appena creato un JSFiddle che mostra l’impaginazione + cerca + ordina per ogni colonna usando il codice btford: http://jsfiddle.net/SAWsA/11/

Ho aggiornato il plunkr di Scotty.NET http://plnkr.co/edit/FUeWwDu0XzO51lyLAEIA?p=preview in modo che utilizzi versioni più recenti di angular, angular-ui e bootstrap.

controllore

 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 dell'interfaccia utente Bootstrap

   

Questa è una pura soluzione javascript che ho avvolto come servizio angular per implementare la logica di impaginazione come nei risultati di ricerca di Google.

Dimostrazione di lavoro su CodePen su http://codepen.io/cornflourblue/pen/KVeaQL/

Dettagli e spiegazioni in questo post del 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 }; } } 

Ho estratto i bit rilevanti qui. Questo è un cercapersone tabulare “senza fronzoli”, quindi l’ordinamento o il filtraggio non è incluso. Sentiti libero di cambiare / aggiungere se necessario:

  //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 (ie our model) $scope.pages = new $window.Util.Pager($scope.ModelData); }; })(window.Controllers = window.Controllers || {}); 
  
Col1
« {{n + 1}} »

L’adattatore angular jQuery Mobile ha un filtro cercapersone da cui potresti partire.

Ecco un demo fiddle che lo usa (aggiungi più di 5 elementi e diventa paginato): http://jsfiddle.net/tigbro/Du2DY/

Ecco la fonte: https://github.com/tigbro/jquery-mobile-angular-adapter/blob/master/src/main/webapp/utils/paging.js

Io uso questa libreria di paginazione di terze parti e funziona bene. Può fare origini dati remote / locali ed è molto configurabile.

https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination

   

Sotto soluzione abbastanza semplice.

    

Ecco un esempio di jsfiddle

Per chiunque abbia difficoltà come me a creare un cercapersone per un tavolo, lo postò. Quindi, secondo te:

    
//And don't forget in your table:

Nei tuoi angularJ:

  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  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); }; }); 

impaginazione ripetuta

  
  • {{item}}
{{currentPage+1}}/{{numberOfPages()}}

Dal momento che Angular 1.4, il filtro limitTo accetta anche un secondo argomento opzionale begin

Dai documenti :

{{limitTo_expression | limitTo: limit: begin}}

inizio (facoltativo) stringa | numero
Indice al quale iniziare la limitazione. Come indice negativo, inizia indica un offset dalla fine dell’input. Il valore predefinito è 0.

Quindi non è necessario creare una nuova direttiva , Questo argomento può essere usato per impostare l’offset dell’impaginazione

 ng-repeat="item in vm.items| limitTo: vm.itemsPerPage: (vm.currentPage-1)*vm.itemsPerPage" 

I messaggi precedenti raccomandavano fondamentalmente come build un paging da soli. Se sei come me, e preferisci una direttiva finita, ne ho trovato uno fantastico chiamato ngTable . Supporta l’ordinamento, il filtraggio e l’impaginazione.

È una soluzione molto pulita, tutto ciò che serve nella tua vista:

  
{{user.name}} {{user.age}}

E nel controller:

 $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)); } }); 

Link a GitHub: https://github.com/esvit/ng-table/

C’è il mio esempio. Pulsante selezionato in mezzo alla lista Controller. config >>>

  $scope.pagination = {total: null, pages: [], config: {count: 10, page: 1, size: 7}}; 

Logica per impaginazione:

 /* 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); }); 

e la mia opinione su bootstap

  

È utile

Angular-Paging

è una scelta meravigliosa

Una direttiva per aiutare nel paging di set di dati di grandi dimensioni pur richiedendo il minimo indispensabile di informazioni di paging effettive. Siamo molto dipendenti dal server per “filtrare” i risultati in questo schema di paging. L’idea centrale è che vogliamo solo contenere la “pagina” triggers degli elementi, piuttosto che contenere l’intero elenco di elementi in memoria e paging sul lato client.

Vecchia domanda ma poiché penso che il mio approccio sia un po ‘diverso e meno complesso, lo condividerò e spero che qualcuno oltre a me lo trovi utile.

Quello che ho trovato per essere una soluzione facile e piccola alla paginazione è combinare una direttiva con un filtro che utilizza le stesse variabili di scope.

Per implementarlo aggiungi il filtro sull’array e aggiungi il directiv in questo modo

 
Name Price Quantity
{{item.Name}} {{item.Price}} {{item.Quantity}}

p_Size e p_Step sono variabili dell’ambito che possono essere personalizzate nell’ambito, altrimenti il ​​valore predefinito di p_Size è 5 e p_Step è 1.

Quando un passaggio è modificato nell’impaginazione, p_Step viene aggiornato e attiverà un nuovo filtro dal filtro cust_pagination. Il filtro cust_pagination taglia quindi l’array in base al valore p_Step come sotto e restituisce solo i record attivi selezionati nella sezione di paginazione

 var startIndex = nStep * nPageSize; var endIndex = startIndex + nPageSize; var arr = items.slice(startIndex, endIndex); return arr; 

DEMO Visualizza la soluzione completa in questo plunker

Vorrei poter commentare, ma dovrò lasciare questo qui:

La risposta di Scotty.NET e la ripetizione di user2176745 per le versioni successive sono entrambe ottime, ma entrambi mancano qualcosa su cui si interrompe la mia versione di AngularJS (v1.3.15):

non è definito in $ scope.makeTodos.

Come tale, la sostituzione con questa funzione lo risolve per versioni angolari più recenti.

 $scope.makeTodos = function() { var i; $scope.todos = []; for (i=1;i<=1000;i++) { $scope.todos.push({ text:'todo '+i, done:false}); } }; 

Panoramica : utilizzo della paginazione

  - ng-repeat - uib-pagination 

Visualizza :

 
Dispature Service Host Value
{{x.dispature}} {{x.service}} {{x.host}} {{x.value}}
Page: {{app.currentPage}} / {{numPages}}

Controller 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(); }]); 

Puoi farlo facilmente usando la direttiva UI Bootstrap.

Questa risposta è una modifica della risposta data da @ Scotty.NET, ho cambiato il codice perché la direttiva è deprecata ora.

Il seguente codice genera l’impaginazione:

 

    Per renderlo funzionale, usa questo nel tuo controller:

     $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(); 

    Fare riferimento a questo per ulteriori opzioni di impaginazione: Direttiva di impaginazione dell’interfaccia utente Bootstrap

    Vorrei aggiungere la mia soluzione che funziona con ngRepeat e i filtri che si utilizzano con esso senza utilizzare un $watch o un array affettato.

    I risultati del filtro verranno impaginati!

     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; }; }]); 

    Nell'HTML assicurati di applicare i filtri a ngRepeat prima del filtro di impaginazione.

     
    {{item}}