Paginação em uma lista usando ng-repeat


130

Estou tentando adicionar páginas à minha lista. Segui o tutorial do AngularJS, sobre smartphones e estou tentando exibir apenas um certo número de objetos. Aqui está o meu arquivo 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>

Adicionei uma tag de seleção com alguns valores para limitar o número de itens que serão exibidos. O que eu quero agora é adicionar a paginação para exibir os próximos 5, 10, etc.

Eu tenho um controlador que funciona com isso:

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

E também tenho um módulo para recuperar os dados dos arquivos json.

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

1
Quando você diz que deseja implementar a página seguinte e a página anterior, deseja que a paginação ocorra exclusivamente no lado do cliente ou no servidor. Se o número de registros for muito alto, você deverá optar pela paginação no servidor. Em qualquer cenário, você precisa começar a manter "startIndex" - o limite forneceria apenas o número de registros na página, além disso, você precisará saber como manter a página atual - isso pode ser feito mantendo o startIndex.
Rutesh Makhijani

Eu não tenho um número alto de registros. O que eu queria fazer era usar o controlador que eu já tenho (PhoneListCtrl). Não sei se é do lado do servidor ou do cliente. Desculpe!
Tomarto

1
@RuteshMakhijani eu tenho uma exigência semelhante com elevado número de registros, por favor, explique a razão por trás usando a paginação do lado do servidor para o elevado número de registros
Dinesh PR

Respostas:


215

Se você não tiver muitos dados, você pode definitivamente fazer a paginação apenas armazenando todos os dados no navegador e filtrando o que é visível em um determinado momento.

Aqui está um exemplo simples de paginação: http://jsfiddle.net/2ZzZB/56/

Esse exemplo estava na lista de violações no wiki do angular.js no github, o que deve ser útil: https://github.com/angular/angular.js/wiki/JsFiddle-Examples

EDIT: http://jsfiddle.net/2ZzZB/16/ para http://jsfiddle.net/2ZzZB/56/ (não mostrará "1 / 4.5" se houver 45 resultados)


1
Muito obrigado! É exatamente o que eu estava procurando. Eu vi esse exemplo anteriormente, mas não funcionou. Agora notei que há um pequeno erro de sintaxe. Um colchete está ausente após a sentença "for".
Tomarto 20/07/12

Eu adicionei os colchetes e atualizei no wiki. Mas deveria ter funcionado sem eles.
Andrew Joslin

1
ah! deixa pra lá. Eu adiciono uma if (input?)condição antes de retornar input.slice(start), obrigado Andy!
zx1986

1
Como Bart, eu precisava passar informações de paginação para uma função de chamada para obter dados pagináveis ​​- é semelhante, mas diferente e pode ajudar em alguns casos. plnkr.co/edit/RcSso3verGtXwToilJ5a
Steve Preto

3
Olá, esta demonstração foi muito útil para um projeto em que me envolvi. Eu precisava adicionar a opção para visualizar tudo ou alternar a paginação, além de mostrar cada página. Então eu estendi a demo. Muito obrigado. jsfiddle.net/juanmendez/m4dn2xrv
Juan Mendez

39

Acabei de criar um JSFiddle que mostra a paginação + pesquisa + ordem em cada coluna usando o código de inicialização do Build with Twitter : http://jsfiddle.net/SAWsA/11/


2
Trabalho incrível. Lembre-se de dar um passo adiante e dinamizar os cabeçalhos das colunas, ou seja, obter todos os valores-chave exclusivos da matriz json dos itens e vincular isso a uma repetição ng em vez de codificar os valores. Algo como o que eu fiz aqui: jsfiddle.net/gavinfoley/t39ZP
GFoley83

ter todo esse código no controlador apenas o torna menos reutilizável - telerik.com/help/silverlight/… Parece angular: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Leblanc Meneses

1
Esta é realmente uma ótima solução, fácil de adaptar. Usou-o em um cenário complexo em que a quantidade de dois elementos vinculados havia atingido os milhares e realmente não era uma opção para refatorar todo o código. Você deve atualizar a resposta com algum código que explique os princípios básicos. E talvez atualizar AngularJS e versões Bootstrap no violino :)
davidkonrad

15

Criei um módulo que torna a paginação na memória incrivelmente simples.

Ele permite que você pagine simplesmente substituindo ng-repeatpordir-paginate , especificando os itens por página como um filtro canalizado e soltando os controles onde quiser, na forma de uma única diretiva,<dir-pagination-controls>

Para pegar o exemplo original solicitado por Tomarto, seria assim:

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

Não há necessidade de qualquer código de paginação especial no seu controlador. Tudo é tratado internamente pelo módulo.

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

Fonte: dirPagination do GitHub


JFI: Em vez de dirPagination.tpl.html separado, também podemos incluir o código de paginação dentro de <control-pagination-controls> <ul class = "pagination" ng-if = "1 <pages.length ||! AutoHide">. .. </ul> </dir-pagination-controls>
npcoder 18/01/18

5

Eu sei que esta discussão é antiga agora, mas estou respondendo para manter as coisas um pouco atualizadas.

Com o Angular 1.4 e superior, você pode usar diretamente o filtro limitTo, que além de aceitar o limitparâmetro também aceita umbegin parâmetro.

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

Portanto, agora você pode não precisar usar nenhuma biblioteca de terceiros para obter algo como paginação. Eu criei um violino para ilustrar o mesmo.


O violino ao qual você vinculou não usa o parâmetro begin.
The Brawny Man

3

Confira esta diretiva: https://github.com/samu/angular-table

Ele automatiza muito a classificação e a paginação e oferece liberdade suficiente para personalizar sua tabela / lista da maneira que você desejar.


À primeira vista, parecia exatamente o que eu precisava, mas parece que não consigo fazê-lo funcionar com recursos $. Parece que sempre acha que minha lista está vazia aqui: github.com/ssmm/table-table/blob/master/coffee/… ... ainda não foi capaz de descobrir o porquê. : /
Mike Desjardins

Como posso mostrar Sno na primeira coluna já que não posso usar $indexe minha matriz não contém valores incrementais
Dwigh

eu fiz isso: <td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>mas eu não sei se é o caminho certo
Dwigh

2

Aqui está um código de demonstração em que há paginação + Filtragem com 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>
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.