Pagination sur une liste en utilisant ng-repeat

130

J'essaye d'ajouter des pages à ma liste. J'ai suivi le tutoriel AngularJS, celui sur les smartphones et j'essaye de n'afficher qu'un certain nombre d'objets. Voici mon fichier 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>

J'ai ajouté une balise de sélection avec certaines valeurs afin de limiter le nombre d'éléments qui seront affichés. Ce que je veux maintenant, c'est ajouter la pagination pour afficher les 5, 10, etc.

J'ai un contrôleur qui fonctionne avec ceci:

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

Et aussi j'ai un module pour récupérer les données des fichiers json.

angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
        return $resource('phones/:phoneId.json', {}, {
            query: {method: 'GET', params:{phoneId:'phones'}, isArray:true}
        });
    });
Tomarto
la source
1
Lorsque vous dites que vous souhaitez implémenter la page suivante et la page précédente, voulez-vous que la pagination se produise uniquement côté client ou côté serveur. Si le nombre d'enregistrements est trop élevé, vous devriez opter pour la pagination côté serveur. Dans n'importe quel scénario, vous devez commencer à maintenir "startIndex" - la limite ne fournirait que le nombre d'enregistrements sur la page, à part cela, vous devez savoir comment maintenir la page actuelle - cela peut être fait en maintenant startIndex.
Rutesh Makhijani
Je n'ai pas un grand nombre de disques. Ce que je voulais faire, c'est utiliser le contrôleur que j'ai déjà (PhoneListCtrl). Je ne sais pas si c'est côté serveur ou côté client. Désolé!
Tomarto
1
@RuteshMakhijani J'ai une exigence similaire avec un nombre élevé d'enregistrements, veuillez expliquer la raison de l'utilisation de la pagination côté serveur pour un nombre élevé d'enregistrements
Dinesh PR

Réponses:

215

Si vous n'avez pas trop de données, vous pouvez certainement faire la pagination en stockant simplement toutes les données dans le navigateur et en filtrant ce qui est visible à un certain moment.

Voici un exemple de pagination simple: http://jsfiddle.net/2ZzZB/56/

Cet exemple était sur la liste des violons sur le wiki angular.js github, ce qui devrait être utile: https://github.com/angular/angular.js/wiki/JsFiddle-Examples

EDIT: http://jsfiddle.net/2ZzZB/16/ à http://jsfiddle.net/2ZzZB/56/ (n'affichera pas "1 / 4.5" s'il y a 45 résultats)

Andrew Joslin
la source
1
Merci beaucoup! C'est exactement ce que je cherchais. J'ai vu cet exemple plus tôt mais cela n'a pas fonctionné. Maintenant, j'ai remarqué qu'il y avait une petite erreur de syntaxe. Il manque un crochet après la phrase «pour».
Tomarto
J'ai ajouté les crochets et l'ai mis à jour sur le wiki. Mais cela aurait dû fonctionner sans eux.
Andrew Joslin
1
Oh! ça ne fait rien. J'ajoute une if (input?)condition avant retour input.slice(start), merci Andy!
zx1986
1
Comme Bart, j'avais besoin de passer des informations de pagination dans une fonction d'appel pour obtenir des données paginables - c'est similaire mais différent et peut aider dans certains cas. plnkr.co/edit/RcSso3verGtXwToilJ5a
Steve Black
3
Salut, cette démo m'a été si utile pour un projet auquel je me suis impliqué. J'avais besoin d'ajouter l'option pour tout voir, ou pour basculer la pagination ainsi que pour afficher chaque page. J'ai donc prolongé la démo. Merci beaucoup. jsfiddle.net/juanmendez/m4dn2xrv
Juan Mendez
39

Je viens de créer un JSFiddle qui montre la pagination + la recherche + l'ordre par sur chaque colonne en utilisant Build with Twitter Bootstrap code: http://jsfiddle.net/SAWsA/11/

Spir
la source
2
Emploi super. Soyez bon d'aller plus loin et rendre les en-têtes de colonne dynamiques, c'est-à-dire obtenir toutes les valeurs de clé uniques du tableau json des éléments et lier cela à un ng-repeat au lieu de coder en dur les valeurs. Quelque chose comme ce que j'ai fait ici: jsfiddle.net/gavinfoley/t39ZP
GFoley83
avoir tout ce code dans le contrôleur le rend simplement moins réutilisable - telerik.com/help/silverlight / ... Semble angulaire est manquant: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Leblanc Meneses
1
C'est une très bonne solution, facile à adapter. Je l'ai utilisé dans un scénario complexe où le nombre de deux éléments liés avait atteint les milliers, et ce n'était vraiment pas une option pour refactoriser le code entier. Vous devriez mettre à jour la réponse avec du code expliquant les principes de base. Et peut-être mettre à niveau les versions AngularJS et Bootstrap dans le violon :)
davidkonrad
15

J'ai construit un module qui rend la pagination en mémoire incroyablement simple.

Il vous permet de paginer simplement en remplaçant ng-repeatpar dir-paginate, en spécifiant les éléments par page comme un filtre canalisé, puis en déposant les contrôles où vous le souhaitez sous la forme d'une seule directive,<dir-pagination-controls>

Pour prendre l'exemple original demandé par Tomarto, cela ressemblerait à ceci:

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

Il n'y a pas besoin de code de pagination spécial dans votre contrôleur. Tout est géré en interne par le module.

Démo: http://plnkr.co/edit/Wtkv71LIqUR4OhzhgpqL?p=preview

Source: dirPagination de GitHub

Michael Bromley
la source
JFI: Au lieu de dirPagination.tpl.html séparés, nous pouvons également inclure le code de pagination dans <dir-pagination-controls> <ul class = "pagination" ng-if = "1 <pages.length ||! AutoHide">. .. </ul> </dir-pagination-controls>
npcoder
5

Je sais que ce fil est vieux maintenant, mais j'y réponds pour garder les choses un peu à jour.

Avec Angular 1.4 et au-dessus, vous pouvez directement utiliser limitTo filter qui, en plus d'accepter le limitparamètre, accepte également unbegin paramètre.

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

Alors maintenant, vous n'aurez peut-être pas besoin d'utiliser une bibliothèque tierce pour réaliser quelque chose comme la pagination. J'ai créé un violon pour illustrer la même chose.

Bharat Gupta
la source
Le violon auquel vous avez lié n'utilise pas réellement le paramètre begin.
The Brawny Man
3

Consultez cette directive: https://github.com/samu/angular-table

Il automatise beaucoup le tri et la pagination et vous donne suffisamment de liberté pour personnaliser votre tableau / liste comme vous le souhaitez.

Samuel Müller
la source
À première vue, cela ressemblait exactement à ce dont j'avais besoin, mais je n'arrive pas à le faire fonctionner avec $ resource. On dirait que ma liste est toujours vide ici: github.com/ssmm/angular-table/blob/master/coffee/ ... ... je n'ai pas encore été en mesure de comprendre pourquoi. : /
Mike Desjardins
comment afficher Sno dans la première colonne car je ne peux pas utiliser $indexet mon tableau ne contient pas de valeurs incrémentielles
Dwigh
je l'ai fait: <td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>mais je ne sais pas si c'est la bonne voie
Dwigh
2

Voici un code de démonstration où il y a pagination + Filtrage avec 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>
Brahim LAMJAGUAR
la source