Разбиение на страницы в списке с помощью ng-repeat

130

Я пытаюсь добавить страницы в свой список. Я следовал руководству по AngularJS, посвященному смартфонам, и пытаюсь отобразить только определенное количество объектов. Вот мой 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>

Я добавил тег select с некоторыми значениями, чтобы ограничить количество отображаемых элементов. Сейчас я хочу добавить разбиение на страницы для отображения следующих 5, 10 и т. Д.

У меня есть контроллер, который работает с этим:

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

А также у меня есть модуль для извлечения данных из файлов json.

angular.module('phonecatServices', ['ngResource']).
    factory('Phone', function($resource){
        return $resource('phones/:phoneId.json', {}, {
            query: {method: 'GET', params:{phoneId:'phones'}, isArray:true}
        });
    });
Tomarto
источник
1
Когда вы говорите, что хотите реализовать следующую страницу и предыдущую страницу, хотите ли вы, чтобы разбивка на страницы происходила исключительно на стороне клиента или на стороне сервера. Если количество записей слишком велико, вам следует выбрать разбиение на страницы на стороне сервера. В любом сценарии вам нужно начать поддерживать "startIndex" - ограничение будет предоставлять только количество записей на странице, кроме этого вам нужно кое-как поддерживать текущую страницу - это можно сделать, поддерживая startIndex.
Rutesh Makhijani
У меня не так много записей. Я хотел использовать уже имеющийся у меня контроллер (PhoneListCtrl). Я не знаю, на стороне сервера или на стороне клиента. Сожалею!
Tomarto
1
@RuteshMakhijani У меня аналогичное требование с большим количеством записей, пожалуйста, объясните причину использования разбивки на страницы на стороне сервера для большого количества записей
Динеш PR

Ответы:

215

Если у вас не слишком много данных, вы определенно можете выполнить разбиение на страницы, просто сохранив все данные в браузере и отфильтровав то, что видно в определенное время.

Вот простой пример разбивки на страницы: http://jsfiddle.net/2ZzZB/56/

Этот пример был в списке скрипок на github wiki angular.js, что должно быть полезно: https://github.com/angular/angular.js/wiki/JsFiddle-Examples

РЕДАКТИРОВАТЬ: http://jsfiddle.net/2ZzZB/16/ до http://jsfiddle.net/2ZzZB/56/ (не будет отображаться «1 / 4.5», если будет 45 результатов)

Эндрю Джослин
источник
1
Большое спасибо! Это именно то, что я искал. Я видел этот пример раньше, но он не работал. Теперь я заметил небольшую синтаксическую ошибку. После предложения "for" отсутствует скобка.
Tomarto
Я добавил скобки и обновил его в вики. Но все должно было работать и без них.
Эндрю Джослин,
1
ой! неважно. Я добавляю if (input?)условие перед возвратом input.slice(start), спасибо Энди!
zx1986
1
Как и Барт, мне нужно было передать информацию о подкачке в вызывающую функцию, чтобы получить данные с разбивкой на страницы - это похоже, но отличается и в некоторых случаях может помочь. plnkr.co/edit/RcSso3verGtXwToilJ5a
Стив Блэк
3
Привет, эта демонстрация мне очень пригодилась для проекта, в котором я участвовал. Мне нужно было добавить возможность просматривать все или переключать разбиение на страницы, а также отображать каждую страницу. Итак, я расширил демо. большое спасибо. jsfiddle.net/juanmendez/m4dn2xrv
Хуан Мендес,
39

Я только что сделал JSFiddle, который показывает разбивку на страницы + поиск + порядок по каждому столбцу, используя Build with Twitter Bootstrap code: http://jsfiddle.net/SAWsA/11/

Спир
источник
2
Хорошая работа. Будьте готовы сделать еще один шаг и сделать заголовки столбцов динамическими, т.е. получить все уникальные значения ключей из массива элементов json и привязать их к ng-repeat вместо жесткого кодирования значений. Что-то вроде того, что я сделал здесь: jsfiddle.net/gavinfoley/t39ZP
GFoley83
наличие всего этого кода в контроллере делает его менее пригодным для повторного использования - telerik.com/help/silverlight/ ... Кажется, что angular отсутствует: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Леблан Менесес
1
Это действительно отличное решение, которое легко адаптировать. Использовал его в сложном сценарии, когда количество двух связанных элементов достигало тысяч, и на самом деле это не было вариантом для рефакторинга всего кода. Вам следует обновить ответ кодом, объясняющим основные принципы. И, возможно, обновите версии AngularJS и Bootstrap в скрипке :)
davidkonrad
15

Я создал модуль, который невероятно упрощает разбиение на страницы в памяти.

Он позволяет выполнять разбиение на страницы, просто заменяя их ng-repeatна dir-paginate, указывая элементы на странице в виде конвейерного фильтра, а затем отбрасывая элементы управления в любом месте в виде одной директивы,<dir-pagination-controls>

Если взять исходный пример, заданный Томарто, он будет выглядеть так:

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

В вашем контроллере нет необходимости в специальном коде разбивки на страницы. Все это обрабатывается внутри модуля.

Демо: http://plnkr.co/edit/Wtkv71LIqUR4OhzhgpqL?p=preview

Источник: dirPagination на GitHub

Майкл Бромли
источник
JFI: вместо разделенного dirPagination.tpl.html мы также можем включить код разбивки на страницы внутри <dir-pagination-controls> <ul class = "pagination" ng-if = "1 <pages.length ||! AutoHide">. .. </ul> </dir-pagination-controls>
npcoder
5

Я знаю, что эта ветка сейчас устарела, но я отвечаю на нее, чтобы держать вещи немного в курсе.

В Angular 1.4 и выше вы можете напрямую использовать фильтр limitTo, который помимо принятия limitпараметра также принимает beginпараметр.

Использование: {{ limitTo_expression | limitTo : limit : begin}}

Так что теперь вам может не понадобиться использовать какую-либо стороннюю библиотеку для достижения чего-то вроде разбивки на страницы. Я создал скрипку, чтобы проиллюстрировать то же самое.

Бхарат Гупта
источник
Скрипка, с которой вы связались, на самом деле не использует параметр begin.
The Brawny Man
3

Ознакомьтесь с этой директивой: https://github.com/samu/angular-table

Он во многом автоматизирует сортировку и разбиение на страницы и дает вам достаточно свободы для настройки таблицы / списка, как вы хотите.

Сэмюэл Мюллер
источник
На первый взгляд это выглядело именно так, как мне нужно, но я не могу заставить его работать с ресурсом $. Похоже, он всегда думает, что мой список здесь пуст: github.com/ssmm/angular-table/blob/master/coffee/ ... ... пока не могу понять, почему. : /
Mike Desjardins
как мне показать Sno в первом столбце, поскольку я не могу использовать, $indexи мой массив не содержит дополнительных значений
Дуай
Я сделал это: <td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>но я не знаю, правильный ли это путь
Дуай
2

Вот демонстрационный код, где есть пагинация + фильтрация с помощью 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>
Брахим ЛАМДЖАГУАР
источник