Paginierung einer Liste mit ng-repeat

130

Ich versuche, Seiten zu meiner Liste hinzuzufügen. Ich habe das AngularJS-Tutorial über Smartphones befolgt und versuche, nur eine bestimmte Anzahl von Objekten anzuzeigen. Hier ist meine HTML-Datei:

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

Ich habe ein Auswahl-Tag mit einigen Werten hinzugefügt, um die Anzahl der angezeigten Elemente zu begrenzen. Was ich jetzt möchte, ist das Hinzufügen der Paginierung, um die nächsten 5, 10 usw. anzuzeigen.

Ich habe einen Controller, der damit arbeitet:

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

Außerdem habe ich ein Modul, um die Daten aus den JSON-Dateien abzurufen.

angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
        return $resource('phones/:phoneId.json', {}, {
            query: {method: 'GET', params:{phoneId:'phones'}, isArray:true}
        });
    });
Tomarto
quelle
1
Wenn Sie sagen, dass Sie die nächste Seite und die vorherige Seite implementieren möchten, möchten Sie, dass die Paginierung nur auf Client- oder Serverseite erfolgt. Wenn die Anzahl der Datensätze zu hoch ist, sollten Sie sich für die serverseitige Paginierung entscheiden. In jedem Szenario müssen Sie mit der Pflege von "startIndex" beginnen - das Limit würde nur die Anzahl der Datensätze auf der Seite bereitstellen. Abgesehen davon müssen Sie einige Informationen zur Pflege der aktuellen Seite bereitstellen. Dies kann durch die Pflege von startIndex erfolgen.
Rutesh Makhijani
Ich habe nicht viele Datensätze. Ich wollte den Controller verwenden, den ich bereits habe (PhoneListCtrl). Ich weiß nicht, ob es Server- oder Client-Seite ist. Es tut uns leid!
Tomarto
1
@ RuteshMakhijani Ich habe eine ähnliche Anforderung mit einer hohen Anzahl von Datensätzen. Bitte erläutern Sie den Grund für die Verwendung der serverseitigen Paginierung für eine hohe Anzahl von Datensätzen
Dinesh PR

Antworten:

215

Wenn Sie nicht zu viele Daten haben, können Sie auf jeden Fall eine Paginierung durchführen, indem Sie einfach alle Daten im Browser speichern und filtern, was zu einem bestimmten Zeitpunkt sichtbar ist.

Hier ist ein einfaches Paginierungsbeispiel: http://jsfiddle.net/2ZzZB/56/

Dieses Beispiel befand sich auf der Liste der Geigen im Github-Wiki von angle.js, was hilfreich sein sollte: https://github.com/angular/angular.js/wiki/JsFiddle-Examples

BEARBEITEN: http://jsfiddle.net/2ZzZB/16/ bis http://jsfiddle.net/2ZzZB/56/ (zeigt nicht "1 / 4.5" an, wenn 45 Ergebnisse vorliegen)

Andrew Joslin
quelle
1
Vielen Dank! Es ist genau das, wonach ich gesucht habe. Ich habe dieses Beispiel früher gesehen, aber es hat nicht funktioniert. Jetzt ist mir aufgefallen, dass ein kleiner Syntaxfehler vorliegt. Nach dem Satz "für" fehlt eine Klammer.
Tomarto
Ich habe die Klammern hinzugefügt und im Wiki aktualisiert. Aber es hätte ohne sie funktionieren sollen.
Andrew Joslin
1
Oh! keine Ursache. Ich füge if (input?)vor der Rückkehr eine Bedingung hinzu input.slice(start), danke Andy!
zx1986
1
Wie Bart musste ich Paging-Informationen an eine aufrufende Funktion übergeben, um pagable Daten zu erhalten - sie sind ähnlich, aber unterschiedlich und können in einigen Fällen hilfreich sein. plnkr.co/edit/RcSso3verGtXwToilJ5a
Steve Black
3
Hallo, diese Demo war so praktisch für ein Projekt, an dem ich beteiligt war. Ich musste die Option hinzufügen, um alle anzuzeigen oder die Paginierung umzuschalten und jede Seite anzuzeigen. Also habe ich die Demo erweitert. Vielen Dank. jsfiddle.net/juanmendez/m4dn2xrv
Juan Mendez
39

Ich habe gerade eine JSFiddle erstellt, die Paginierung + Suche + Reihenfolge nach in jeder Spalte mit Build with Twitter Bootstrap- Code anzeigt : http://jsfiddle.net/SAWsA/11/

Spir
quelle
2
Beeindruckende Arbeit. Gehen Sie noch einen Schritt weiter und machen Sie die Spaltenüberschriften dynamisch, dh holen Sie sich alle eindeutigen Schlüsselwerte aus dem json-Array der Elemente und binden Sie diese an eine ng-Wiederholung, anstatt die Werte hart zu codieren. So etwas wie das, was ich hier gemacht habe: jsfiddle.net/gavinfoley/t39ZP
GFoley83
Wenn der gesamte Code im Controller vorhanden ist, ist er nur weniger wiederverwendbar - telerik.com/help/silverlight/… Scheint eckig zu sein: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Leblanc Meneses
1
Dies ist eine wirklich großartige Lösung, die sich leicht anpassen lässt. Verwendet es in einem komplexen Szenario, in dem die Anzahl von zwei gebundenen Elementen Tausende erreicht hatte, und es war wirklich keine Option, den gesamten Code umzugestalten. Sie sollten die Antwort mit einem Code aktualisieren, der die Grundprinzipien erklärt. Und vielleicht AngularJS und Bootstrap Versionen in der Geige
aktualisieren
15

Ich habe ein Modul erstellt, das die In-Memory-Paginierung unglaublich einfach macht.

Es ermöglicht Ihnen, Paginieren durch einfaches Austauschen ng-repeatmit dir-paginate, die Einzelteile pro Seite als verrohrt Filter spezifizieren, und fallen dann die Steuerelemente , wo man sich wie in Form einer einzigen Richtlinie,<dir-pagination-controls>

Um das ursprüngliche Beispiel von Tomarto zu nehmen, würde es so aussehen:

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

In Ihrem Controller ist kein spezieller Paginierungscode erforderlich. Alles wird intern vom Modul erledigt.

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

Quelle: dirPagination von GitHub

Michael Bromley
quelle
JFI: Anstelle von getrenntem dirPagination.tpl.html können wir den Paginierungscode auch in <dir-pagination-controls> <ul class = "pagination" ng-if = "1 <pages.length ||! AutoHide"> einfügen. .. </ ul> </
ir-pagination
5

Ich weiß, dass dieser Thread jetzt alt ist, aber ich beantworte ihn, um die Dinge ein bisschen auf dem neuesten Stand zu halten.

Mit Angular 1.4 und höher können Sie den Filter limitTo direkt verwenden , der neben dem Akzeptieren des limitParameters auch einen beginParameter akzeptiert .

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

Jetzt müssen Sie möglicherweise keine Bibliothek eines Drittanbieters verwenden, um eine Paginierung zu erzielen. Ich habe eine Geige geschaffen , um dasselbe zu veranschaulichen.

Bharat Gupta
quelle
Die Geige, mit der Sie verknüpft sind, verwendet den Parameter begin nicht.
Der bullige Mann
3

Überprüfen Sie diese Anweisung: https://github.com/samu/angular-table

Es automatisiert das Sortieren und Paginieren erheblich und gibt Ihnen genügend Freiheit, Ihre Tabelle / Liste nach Ihren Wünschen anzupassen.

Samuel Müller
quelle
Auf den ersten Blick sah das genau so aus, wie ich es brauchte, aber ich kann es scheinbar nicht mit $ resource zum Laufen bringen. Es sieht so aus, als würde meine Liste hier immer leer sein: github.com/ssmm/angular-table/blob/master/coffee/… ... konnte noch nicht herausfinden, warum. : /
Mike Desjardins
Wie zeige ich Sno in der ersten Spalte, da ich es nicht verwenden kann $indexund mein Array keine inkrementellen Werte enthält
Dwigh
Ich habe das getan: <td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>aber ich weiß nicht, ob es der richtige Weg ist
Dwigh
2

Hier ist ein Demo-Code, in dem Paginierung + Filterung mit AngularJS erfolgt:

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>
Brahim LAMJAGUAR
quelle