Paginacja na liście za pomocą ng-repeat

131

Próbuję dodać strony do mojej listy. Postępowałem zgodnie z tutorialem AngularJS, tym o smartfonach i próbuję wyświetlić tylko określoną liczbę obiektów. Oto mój plik 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>

Dodałem tag wyboru z niektórymi wartościami, aby ograniczyć liczbę elementów, które będą wyświetlane. Teraz chcę dodać paginację, aby wyświetlić następne 5, 10 itd.

Mam kontroler, który działa z tym:

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

Mam też moduł do pobierania danych z plików json.

angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
        return $resource('phones/:phoneId.json', {}, {
            query: {method: 'GET', params:{phoneId:'phones'}, isArray:true}
        });
    });
Tomarto
źródło
1
Kiedy mówisz, że chcesz zaimplementować następną stronę i poprzednią stronę, czy chcesz, aby paginacja odbywała się wyłącznie po stronie klienta, czy po stronie serwera. Jeśli liczba rekordów jest zbyt duża, powinieneś zdecydować się na paginację po stronie serwera. W każdym scenariuszu musisz zacząć utrzymywać "startIndex" - limit podałby tylko liczbę rekordów na stronie, poza tym musisz trochę jak utrzymywać bieżącą stronę - można to zrobić, utrzymując startIndex.
Rutesh Makhijani,
Nie mam dużej liczby rekordów. Chciałem użyć kontrolera, który już mam (PhoneListCtrl). Nie wiem, czy jest to strona serwera czy klienta. Przepraszam!
Tomarto
1
@RuteshMakhijani Mam podobne wymaganie z dużą liczbą rekordów, proszę wyjaśnić powód korzystania z paginacji po stronie serwera dla dużej liczby rekordów
Dinesh PR

Odpowiedzi:

216

Jeśli nie masz za dużo danych, zdecydowanie możesz zrobić paginację, po prostu przechowując wszystkie dane w przeglądarce i filtrując to, co jest widoczne w określonym czasie.

Oto prosty przykład paginacji: http://jsfiddle.net/2ZzZB/56/

Ten przykład był na liście skrzypiec na github wiki angular.js, co powinno być pomocne: https://github.com/angular/angular.js/wiki/JsFiddle-Examples

EDYTUJ: http://jsfiddle.net/2ZzZB/16/ do http://jsfiddle.net/2ZzZB/56/ (nie wyświetla „1 / 4.5”, jeśli jest 45 wyników)

Andrew Joslin
źródło
1
Dziękuję Ci bardzo! To jest dokładnie to, czego szukałem. Widziałem ten przykład wcześniej, ale nie zadziałał. Teraz zauważyłem mały błąd składniowy. Brak nawiasu po zdaniu „za”.
Tomarto
Dodałem nawiasy i zaktualizowałem na wiki. Ale powinno działać bez nich.
Andrew Joslin,
1
O! nieważne. Dodam if (input?)warunek przed zwrotem input.slice(start), dzięki Andy!
zx1986
1
Podobnie jak Bart, musiałem przekazać informacje stronicowania do funkcji wywołującej, aby uzyskać dane do stronicowania - jest podobny, ale inny i może w niektórych przypadkach pomóc. plnkr.co/edit/RcSso3verGtXwToilJ5a
Steve Black
3
Cześć, to demo przydało się w projekcie, w który się zaangażowałem. Musiałem dodać opcję przeglądania wszystkich lub przełączania paginacji, a także pokazywania każdej strony. Więc rozszerzyłem demo. wielkie dzięki. jsfiddle.net/juanmendez/m4dn2xrv
Juan Mendez
39

Właśnie utworzyłem JSFiddle, który pokazuje paginację + wyszukiwanie + porządek w każdej kolumnie przy użyciu kodu Bootstrap Build with Twitter : http://jsfiddle.net/SAWsA/11/

Spir
źródło
2
Wspaniała praca. Dobrze jest pójść o krok dalej i sprawić, by nagłówki kolumn były dynamiczne, tj. Pobrać wszystkie unikalne wartości kluczy z tablicy items json i powiązać je z powtórzeniem ng zamiast na sztywno zakodować wartości. Coś jak to, co tutaj zrobiłem: jsfiddle.net/gavinfoley/t39ZP
GFoley83
posiadanie całego tego kodu w kontrolerze sprawia, że ​​jest on mniej wielokrotnego użytku - telerik.com/help/silverlight/ ... Wydaje się, że brakuje tego kodu: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Leblanc Meneses
1
To naprawdę świetne rozwiązanie, łatwe w adaptacji. Użyłem go w złożonym scenariuszu, w którym liczba dwóch powiązanych elementów osiągnęła tysiące i tak naprawdę nie było opcji refaktoryzacji całego kodu. Powinieneś zaktualizować odpowiedź o kod wyjaśniający podstawowe zasady. A może zaktualizuj wersje AngularJS i Bootstrap w skrzypcach :)
davidkonrad
15

Zbudowałem moduł, który sprawia, że ​​paginacja w pamięci jest niezwykle prosta.

Pozwala na paginację, po prostu zastępując ng-repeatdir-paginate, określając elementy na stronie jako filtr potokowy, a następnie upuszczając kontrolki w dowolnym miejscu w formie pojedynczej dyrektywy,<dir-pagination-controls>

Aby wziąć oryginalny przykład zadany przez Tomarto, wyglądałoby to tak:

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

Nie ma potrzeby stosowania żadnego specjalnego kodu paginacji w kontrolerze. Całość jest obsługiwana wewnętrznie przez moduł.

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

Źródło: dirPagination of GitHub

Michael Bromley
źródło
JFI: Zamiast oddzielnego pliku dirPagination.tpl.html, możemy również dołączyć kod paginacji do <dir-pagination-controls> <ul class = "pagination" ng-if = "1 <pages.length ||! AutoHide">. .. </ul> </dir-pagination-controls>
npcoder
5

Wiem, że ten wątek jest teraz stary, ale odpowiadam na niego, aby trochę zaktualizować.

W Angular 1.4 i nowszych można bezpośrednio użyć filtra limitTo, który oprócz akceptacji limitparametru akceptuje również beginparametr.

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

Więc teraz możesz nie potrzebować żadnej biblioteki innej firmy, aby osiągnąć coś takiego jak paginacja. Stworzyłem skrzypce, aby to zilustrować.

Bharat Gupta
źródło
Skrzypce, z którymi się łączyłeś, w rzeczywistości nie używają parametru begin.
The Brawny Man
3

Sprawdź tę dyrektywę: https://github.com/samu/angular-table

Znacznie automatyzuje sortowanie i paginację oraz zapewnia wystarczającą swobodę dostosowywania tabeli / listy w dowolny sposób.

Samuel Müller
źródło
Na pierwszy rzut oka wyglądało to dokładnie na to, czego potrzebowałem, ale nie mogę go zmusić do pracy z zasobami $. Wygląda na to, że zawsze myśli, że moja lista jest tutaj pusta: github.com/ssmm/angular-table/blob/master/coffee/ ... ... nie udało mi się jeszcze ustalić, dlaczego. : /
Mike Desjardins
jak wyświetlić Sno w pierwszej kolumnie, ponieważ nie mogę użyć, $indexa moja tablica nie zawiera wartości przyrostowych
Dwigh
zrobiłem to: <td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>ale nie wiem, czy to jest właściwa droga
Dwigh
2

Oto kod demonstracyjny, w którym jest paginacja + filtrowanie za pomocą 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
źródło