Impaginazione su un elenco usando ng-repeat


130

Sto cercando di aggiungere pagine al mio elenco. Ho seguito il tutorial di AngularJS, quello sugli smartphone e sto cercando di visualizzare solo un certo numero di oggetti. Ecco il mio file html:

  <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>

Ho aggiunto un tag di selezione con alcuni valori per limitare il numero di elementi che verranno visualizzati. Quello che voglio ora è aggiungere l'impaginazione per visualizzare i prossimi 5, 10, ecc.

Ho un controller che funziona con questo:

function PhoneListCtrl($scope, Phone){
    $scope.phones = Phone.query();
    $scope.orderProp = 'age';
    $scope.limit = 5;
}

E ho anche un modulo per recuperare i dati dai file json.

angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
        return $resource('phones/:phoneId.json', {}, {
            query: {method: 'GET', params:{phoneId:'phones'}, isArray:true}
        });
    });

1
Quando si dice che si desidera implementare la pagina successiva e la pagina precedente, si desidera che l'impaginazione avvenga esclusivamente sul lato client o sul lato server. Se il numero di record è troppo elevato, è necessario optare per l'impaginazione lato server. In qualsiasi scenario è necessario iniziare a mantenere "startIndex" - il limite fornirebbe solo il numero di record nella pagina, a parte questo è necessario in qualche modo mantenere la pagina corrente - questo può essere fatto mantenendo startIndex.
Rutesh Makhijani,

Non ho un numero elevato di record. Quello che volevo fare è usare il controller che ho già (PhoneListCtrl). Non so se è lato server o client. Scusa!
Tomarto

1
@RuteshMakhijani Ho un requisito simile con un numero elevato di record, spiega il motivo per cui è stato utilizzato l'impaginazione lato server per un numero elevato di record
Dinesh PR

Risposte:


215

Se non disponi di troppi dati, puoi sicuramente eseguire l'impaginazione semplicemente archiviando tutti i dati nel browser e filtrando ciò che è visibile in un determinato momento.

Ecco un semplice esempio di impaginazione: http://jsfiddle.net/2ZzZB/56/

Quell'esempio era nella lista dei violini nella wiki di github angular.js, che dovrebbe essere utile: https://github.com/angular/angular.js/wiki/JsFiddle-Examples

EDIT: http://jsfiddle.net/2ZzZB/16/ su http://jsfiddle.net/2ZzZB/56/ (non mostrerà "1 / 4.5" se ci sono 45 risultati)


1
Grazie mille! È esattamente quello che stavo cercando. Ho visto questo esempio prima ma non ha funzionato. Ora ho notato che c'è un piccolo errore di sintassi. Manca una parentesi dopo la frase "for".
Tomarto

Ho aggiunto le parentesi e l'ho aggiornato sul wiki. Ma avrebbe dovuto funzionare senza di loro.
Andrew Joslin,

1
Oh! non importa. Aggiungo una if (input?)condizione prima del ritorno input.slice(start), grazie Andy!
zx1986,

1
Come Bart, avevo bisogno di passare le informazioni di paging in una funzione di chiamata per ottenere dati di paging: sono simili ma diversi e potrebbero aiutare in alcuni casi. plnkr.co/edit/RcSso3verGtXwToilJ5a
Steve Black

3
Ciao, questa demo è stata così utile per un progetto che mi ha coinvolto. Avevo bisogno di aggiungere l'opzione per visualizzare tutto, o attivare l'impaginazione e mostrare ogni pagina. Quindi ho esteso la demo. molte grazie. jsfiddle.net/juanmendez/m4dn2xrv
Juan Mendez

39

Ho appena creato un JSFiddle che mostra l'impaginazione + ricerca + ordine su ogni colonna usando il codice Bootstrap Build with Twitter : http://jsfiddle.net/SAWsA/11/


2
Lavoro fantastico. Sii buono per fare un ulteriore passo avanti e rendere dinamici i titoli delle colonne, ovvero ottenere tutti i valori chiave univoci dall'array json di elementi e associarli a una ripetizione ng anziché codificare i valori. Qualcosa di simile a quello che ho fatto qui: jsfiddle.net/gavinfoley/t39ZP
GFoley83

avere tutto quel codice nel controller lo rende meno riutilizzabile - telerik.com/help/silverlight/… Sembra che manchi l' angolo: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Leblanc Meneses

1
Questa è davvero un'ottima soluzione, facile da adattare. Lo utilizzava in uno scenario complesso in cui la quantità di due elementi associati aveva raggiunto le migliaia e in realtà non era un'opzione per il refactoring dell'intero codice. È necessario aggiornare la risposta con un codice che spieghi i principi di base. E forse aggiornare le versioni di AngularJS e Bootstrap nel violino :)
davidkonrad

15

Ho creato un modulo che rende la paginazione in memoria incredibilmente semplice.

Ti consente di impaginare semplicemente sostituendolo ng-repeatcon dir-paginate, specificando gli elementi per pagina come filtro convogliato e quindi rilasciando i controlli dove preferisci sotto forma di una singola direttiva,<dir-pagination-controls>

Per prendere l'esempio originale richiesto da Tomarto, sarebbe simile al seguente:

<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>

Non è necessario alcun codice di impaginazione speciale nel controller. È tutto gestito internamente dal modulo.

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

Fonte: dirPagination di GitHub


JFI: Invece di dirPagination.tpl.html separato, possiamo anche includere il codice di paginazione all'interno di <dir-pagination-controls> <ul class = "pagination" ng-if = "1 <pages.length ||! AutoHide">. .. </ul> </dir-pagination-controls>
npcoder il

5

So che questo thread è vecchio ora, ma sto rispondendo per mantenere le cose un po 'aggiornate.

Con Angular 1.4 e versioni successive è possibile utilizzare direttamente limitTo filter che oltre ad accettare il limitparametro accetta anche un beginparametro.

Uso: {{ limitTo_expression | limitTo : limit : begin}}

Quindi ora potrebbe non essere necessario utilizzare alcuna libreria di terze parti per ottenere qualcosa come l'impaginazione. Ho creato un violino per illustrare lo stesso.


Il violino a cui ti sei collegato non utilizza effettivamente il parametro iniziale.
The Brawny Man,

3

Dai un'occhiata a questa direttiva: https://github.com/samu/angular-table

Automatizza molto l'ordinamento e l'impaginazione e ti dà abbastanza libertà per personalizzare il tuo tavolo / elenco come preferisci.


A prima vista sembrava esattamente ciò di cui avevo bisogno, ma non riesco a farlo funzionare con risorse $. Sembra che pensi sempre che la mia lista sia vuota qui: github.com/ssmm/angular-table/blob/master/coffee/… ... non sono ancora riuscito a capire perché. : /
Mike Desjardins,

come faccio a mostrare Sno nella prima colonna poiché non riesco a usare $indexe il mio array non contiene valori incrementali
Dwigh

ho fatto questo: <td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>ma non so se è la strada giusta
Dwigh,

2

Ecco un codice demo in cui è presente l'impaginazione + Filtro con 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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.