การแบ่งหน้าในรายการโดยใช้ 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>

ฉันได้เพิ่มแท็กเลือกด้วยค่าบางอย่างเพื่อ จำกัด จำนวนรายการที่จะแสดง สิ่งที่ฉันต้องการตอนนี้คือเพิ่มเลขหน้าเพื่อแสดง 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}
        });
    });

1
เมื่อคุณบอกว่าคุณต้องการใช้หน้าถัดไปและหน้าก่อนหน้าคุณต้องการให้การแบ่งหน้าเกิดขึ้นเฉพาะในฝั่งไคลเอ็นต์หรือฝั่งเซิร์ฟเวอร์ หากจำนวนบันทึกสูงเกินไปคุณควรเลือกใช้การแบ่งหน้าฝั่งเซิร์ฟเวอร์ ภายใต้สถานการณ์ใด ๆ ที่คุณต้องเริ่มรักษา "startIndex" - ขีด จำกัด จะให้เฉพาะจำนวนระเบียนบนหน้าเท่านั้นนอกเหนือจากนี้คุณต้องมีวิธีการดูแลรักษาหน้าปัจจุบันซึ่งสามารถทำได้โดยการดูแล startIndex
Rutesh Makhijani

ฉันไม่มีประวัติจำนวนมาก สิ่งที่ฉันต้องการทำคือใช้คอนโทรลเลอร์ที่ฉันมีอยู่แล้ว (PhoneListCtrl) ฉันไม่รู้ว่าเป็นฝั่งเซิร์ฟเวอร์หรือไคลเอนต์ ขออภัย!
Tomarto

1
@RuteshMakhijani ฉันมีข้อกำหนดที่คล้ายกันซึ่งมีระเบียนจำนวนมากโปรดอธิบายเหตุผลที่อยู่เบื้องหลังการใช้การแบ่งหน้าฝั่งเซิร์ฟเวอร์สำหรับระเบียนจำนวนมาก
Dinesh PR

คำตอบ:


215

หากคุณมีข้อมูลไม่มากเกินไปคุณสามารถแบ่งหน้าได้อย่างแน่นอนเพียงแค่จัดเก็บข้อมูลทั้งหมดในเบราว์เซอร์และกรองสิ่งที่มองเห็นได้ในช่วงเวลาหนึ่ง

นี่คือตัวอย่างการแบ่งหน้าง่ายๆ: http://jsfiddle.net/2ZzZB/56/

ตัวอย่างนั้นอยู่ในรายชื่อซอบนวิกิ angular.js github ซึ่งน่าจะเป็นประโยชน์: 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

ฉันเพิ่มวงเล็บและอัปเดตในวิกิ แต่มันควรจะใช้งานได้หากไม่มีพวกเขา
Andrew Joslin

1
โอ้! ไม่เป็นไร. ฉันเพิ่มif (input?)เงื่อนไขก่อนส่งคืนinput.slice(start)ขอบคุณแอนดี้!
zx1986

1
เช่นเดียวกับ Bart ฉันต้องส่งข้อมูลการเพจไปยังฟังก์ชันการโทรเพื่อรับข้อมูลที่แบ่งหน้าได้ซึ่งคล้ายกัน แต่แตกต่างกันและอาจช่วยได้ในบางกรณี plnkr.co/edit/RcSso3verGtXwToilJ5a
Steve Black

3
สวัสดีการสาธิตนี้มีประโยชน์มากสำหรับโครงการที่ฉันมีส่วนร่วม ฉันต้องการเพิ่มตัวเลือกเพื่อดูทั้งหมดหรือสลับการแบ่งหน้ารวมทั้งแสดงแต่ละหน้า ผมจึงขยายการสาธิต ขอบคุณมาก. jsfiddle.net/juanmendez/m4dn2xrv
Juan Mendez

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/… ดูเหมือนว่าเชิงมุมจะหายไป: QueryableDomainServiceCollectionView, VirtualQueryableCollectionView, HierarchicalDataCollectionView
Leblanc Meneses

1
นี่เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมและปรับตัวได้ง่าย ใช้ในสถานการณ์ที่ซับซ้อนซึ่งจำนวนของสององค์ประกอบที่ถูกผูกไว้มีจำนวนถึงหลักพันและมันไม่ใช่ตัวเลือกในการ refactor โค้ดทั้งหมด คุณควรอัปเดตคำตอบด้วยรหัสที่อธิบายหลักการพื้นฐาน และอาจอัปเกรด AngularJS และ Bootstrap เวอร์ชันในซอ :)
davidkonrad

15

ฉันได้สร้างโมดูลที่ทำให้การแบ่งหน้าในหน่วยความจำง่ายมาก

ช่วยให้คุณสามารถแบ่งเลขหน้าได้โดยเพียงแค่แทนที่ng-repeatโดยdir-paginateระบุรายการต่อหน้าเป็นตัวกรองแบบไปป์แล้ววางการควบคุมลงที่ใดก็ได้ที่คุณต้องการในรูปแบบของคำสั่งเดียว<dir-pagination-controls>

ในการใช้ตัวอย่างต้นฉบับที่ Tomarto ถามมันจะมีลักษณะดังนี้:

<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

5

ฉันรู้ว่าเธรดนี้เก่าแล้ว แต่ฉันกำลังตอบคำถามนี้เพื่อให้ข้อมูลอัปเดตอยู่เสมอ

ด้วย Angular 1.4 ขึ้นไปคุณสามารถใช้ตัวกรองlimitToได้โดยตรงซึ่งนอกเหนือจากการยอมรับlimitพารามิเตอร์ยังยอมรับbeginพารามิเตอร์

การใช้งาน: {{ limitTo_expression | limitTo : limit : begin}}

ดังนั้นตอนนี้คุณอาจไม่จำเป็นต้องใช้ไลบรารีของบุคคลที่สามใด ๆ เพื่อบรรลุบางอย่างเช่นการแบ่งหน้า ฉันได้สร้างซอขึ้นมาเพื่อแสดงให้เห็นถึงสิ่งเดียวกัน


ซอที่คุณเชื่อมโยงไม่ได้ใช้พารามิเตอร์เริ่มต้นจริงๆ
The Brawny Man

3

ตรวจสอบคำสั่งนี้: https://github.com/samu/angular-table

การเรียงลำดับและการแบ่งหน้าโดยอัตโนมัติเป็นจำนวนมากและให้อิสระเพียงพอในการปรับแต่งตาราง / รายการของคุณตามที่คุณต้องการ


เมื่อมองแวบแรกดูเหมือนว่าสิ่งที่ฉันต้องการ แต่ดูเหมือนว่าฉันไม่สามารถใช้งานได้โดยใช้ทรัพยากร $ ดูเหมือนว่ามักจะคิดว่ารายการของฉันว่างเปล่าที่นี่: github.com/ssmm/angular-table/blob/master/coffee/… ... ยังไม่สามารถหาสาเหตุได้ : /
Mike Desjardins

ฉันจะแสดง Sno ในคอลัมน์แรกได้อย่างไรเนื่องจากฉันไม่สามารถใช้$indexและอาร์เรย์ของฉันไม่มีค่าที่เพิ่มขึ้น
Dwigh

ฉันทำสิ่งนี้<td at-sortable at-attribute="index">{{sortedAndPaginatedList.indexOf(item) + 1}}</td>แต่ฉันไม่รู้ว่ามันเป็นวิธีที่ถูกต้องหรือไม่
Dwigh

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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.