วิธีแสดงความยาวของข้อมูล ng-repeat ที่กรองแล้ว


438

ฉันมีอาร์เรย์ข้อมูลที่มีวัตถุจำนวนมาก (รูปแบบ JSON) ข้อมูลต่อไปนี้สามารถสันนิษฐานได้ว่าเป็นเนื้อหาของอาร์เรย์นี้:

var data = [
  {
    "name": "Jim",
    "age" : 25
  },
  {
    "name": "Jerry",
    "age": 27
  }
];

ตอนนี้ฉันแสดงรายละเอียดเหล่านี้เป็น:

<div ng-repeat="person in data | filter: query">
</div

ที่นี่แบบสอบถามถูกสร้างแบบจำลองไปยังช่องใส่ที่ผู้ใช้สามารถ จำกัด ข้อมูลที่แสดง

ตอนนี้ฉันมีตำแหน่งอื่นที่ฉันแสดงจำนวนคน / คนที่กำลังแสดงอยู่ในปัจจุบันเช่น Showing {{data.length}} Persons

สิ่งที่ฉันต้องการทำคือเมื่อผู้ใช้ค้นหาบุคคลและข้อมูลที่แสดงนั้นถูกกรองตามคิวรีผู้ใช้Showing...personsยังเปลี่ยนค่าของบุคคลที่กำลังแสดงอยู่ในปัจจุบัน แต่มันไม่ได้เกิดขึ้น จะแสดงจำนวนบุคคลทั้งหมดในข้อมูลแทนที่จะเป็นข้อมูลที่กรองแล้วฉันจะรับข้อมูลที่กรองได้อย่างไร

คำตอบ:


746

สำหรับเชิงมุม 1.3+ (เครดิตถึง @Tom)

ใช้นิพจน์นามแฝง (เอกสาร: Angular 1.3.0: ngRepeatเลื่อนลงไปที่ส่วนอาร์กิวเมนต์ ):

<div ng-repeat="person in data | filter:query as filtered">
</div>

สำหรับเชิงมุมก่อนหน้า 1.3

กำหนดผลลัพธ์ให้กับตัวแปรใหม่ (เช่นfiltered) และเข้าถึง:

<div ng-repeat="person in filtered = (data | filter: query)">
</div>

แสดงจำนวนผลลัพธ์:

Showing {{filtered.length}} Persons

ซอตัวอย่างที่คล้ายกัน เครดิตไปที่Pawel Kozlowski


42
นี่คือคำตอบง่ายๆที่ไม่ได้เรียกใช้ตัวกรองซ้ำ
agmin

3
@Ben: ใช่ $scope.filtered.lengthคุณสามารถเข้าถึงได้ภายในการควบคุมการใช้
Wumms

2
นั่นไม่ได้ผลสำหรับฉัน บันทึกundefinedอาจเป็นเพราะในขณะที่ทำการบันทึกตัวแปรยังไม่ได้กำหนดไว้ ดังนั้นฉันจะมั่นใจได้อย่างไรว่าโค้ดในคอนโทรลเลอร์ทำงานหลังจากกำหนดตัวแปรและตัวกรองถูกนำไปใช้ในมุมมอง?
Ben

6
@Ben: ฉันเดาว่านี่จะปิดหัวข้อ ฉันจะพิจารณาสร้างตัวกรองแบบกำหนดเองเช่นjsfiddleอย่างไรก็ตามคุณสามารถดูได้ในตัวควบคุม:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms

3
เวอร์ชัน 1.3+ ไม่ทำงานหากฉันต้องการเพิ่ม limitTo: person in data | filter:query as filtered | limitTo:5limitTo: ดังนั้นฉันต้องใช้รุ่น 1.3 ก่อนหน้านี้:person in filtered = (data | filter: query) | limitTo: 5
benjovanic

332

เพื่อความสมบูรณ์นอกเหนือจากคำตอบก่อนหน้า (ทำการคำนวณคนที่มองเห็นได้ภายในคอนโทรลเลอร์) คุณยังสามารถทำการคำนวณนั้นในเทมเพลต HTML ของคุณดังตัวอย่างด้านล่าง

สมมติว่ารายชื่อคนของคุณอยู่ในdataตัวแปรและคุณกรองคนโดยใช้queryโมเดลรหัสต่อไปนี้จะทำงานให้คุณ:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - พิมพ์จำนวนผู้คนทั้งหมด
  • {{(data|filter:query).length}} - พิมพ์จำนวนคนที่กรอง

โปรดทราบว่าโซลูชันนี้ใช้งานได้ดีหากคุณต้องการใช้ข้อมูลที่ถูกกรองเพียงครั้งเดียวในหน้าเว็บ อย่างไรก็ตามหากคุณใช้ข้อมูลที่ถูกกรองมากกว่าหนึ่งครั้งเช่นเพื่อนำเสนอรายการและเพื่อแสดงความยาวของรายการที่ถูกกรองฉันขอแนะนำให้ใช้นิพจน์นามแฝง (อธิบายไว้ด้านล่าง) สำหรับ AngularJS 1.3+หรือวิธีแก้ปัญหาที่เสนอโดย@Wumms for AngularJS เวอร์ชัน 1.3

คุณสมบัติใหม่ในเชิงมุม 1.3

ผู้สร้าง AngularJS ยังสังเกตเห็นว่าปัญหาและในรุ่น1.3 (เบต้า 17)พวกเขาเพิ่มการแสดงออก "นามแฝง" ซึ่งจะเก็บผลลัพธ์กลางของ repeater หลังจากตัวกรองถูกนำไปใช้เช่น

<div ng-repeat="person in data | filter:query as results">
    <!-- template ... -->
</div>

<p>Number of visible people: {{results.length}}</p>

การแสดงออกนามแฝงจะป้องกันปัญหาการดำเนินการกรองหลาย

ฉันหวังว่าจะช่วย


4
สิ่งนี้หมายความว่าตัวกรองถูกดำเนินการสองครั้งหรือไม่
แฟลช

9
ใช่มันถูกดำเนินการสองครั้ง
nathancahill

11
ให้แน่ใจว่าคุณอ่าน @ ตอบคำถามก่อนที่คุณจะตัดสินใจใช้อันนี้ (และคุณจะไม่) ...
epeleg

1
ไม่เป็นไรฉันเห็นคำตอบไม่ได้มีส่วนที่เกี่ยวกับการแสดงออกนามแฝงเมื่อคุณแสดงความคิดเห็นของคุณ
Adam Goodwin

2
คำตอบนี้รองรับการแสดงออกหลายตัวกรองซึ่งแตกต่างจากคำตอบด้านบน เช่น){{(data|filter:query|filter:query2).length}}
chakeda

45

วิธีที่ง่ายที่สุดถ้าคุณมี

<div ng-repeat="person in data | filter: query"></div>

ความยาวข้อมูลที่กรอง

<div>{{ (data | filter: query).length }}</div>

สิ่งนี้มีประโยชน์มากที่สุดสำหรับทุกคนที่ใช้คำสั่ง dir-paginate เชิงมุมเนื่องจากไม่ได้ใช้นามแฝงและทางเลือก pre-ng-1.3
pcnate

นี่จะแจกแจงข้อมูลสองครั้งหรือไม่
Jeppe

36

ngRepeat สร้างสำเนาของอาร์เรย์เมื่อใช้ตัวกรองดังนั้นคุณไม่สามารถใช้อาร์เรย์ต้นทางเพื่ออ้างอิงเฉพาะองค์ประกอบที่กรอง

ในกรณีของคุณอาจใช้ตัวกรองภายในคอนโทรลเลอร์ของคุณโดยใช้$filterบริการดีกว่า:

function MainCtrl( $scope, filterFilter ) {
  // ...

  $scope.filteredData = myNormalData;

  $scope.$watch( 'myInputModel', function ( val ) {
    $scope.filteredData = filterFilter( myNormalData, val );
  });

  // ...
}

แล้วคุณใช้filteredDataคุณสมบัติในมุมมองของคุณแทน นี่คือ Plunker ที่ใช้งานได้: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview


1
สิ่งที่ผมเข้าใจคือว่าผมใช้แทน{{filteredData.length}} data.lengthฉันยังเข้าใจว่าmyInputModelเป็นรูปแบบที่แมปไปยังแบบสอบถามป้อนข้อมูลซึ่งกรองข้อมูล valจะเป็นข้อความที่พิมพ์ในอินพุต (โดยทั่วไปแบบสอบถาม) แต่ทุกครั้งที่ฉันพิมพ์จะมีการเปลี่ยนแปลง แต่ที่filterFilterนี่คืออะไร ฉันอาจเพิ่มว่าฉันได้สร้าง customFilter ของตัวเองแล้ว (ซึ่งฉันสามารถระบุคีย์ของวัตถุที่ต้องพิจารณาสำหรับการกรอง)
user109187

ถูกตัอง. นอกจากนี้ยังใช้เพียงng-repeat="person in filteredData"เพราะไม่มีความรู้สึกกรองสองครั้ง ด้วยการ$filterบริการที่คุณสามารถขอตัวกรองที่เฉพาะเจาะจงโดยเพียงแค่ suffixing กับ "ตัวกรอง" เช่น: dateFilter, jsonFilterฯลฯ filterFilterหากคุณกำลังใช้ตัวกรองของคุณเองเพียงแค่ใช้ที่หนึ่งแทนการทั่วไป
Josh David Miller

สิ่งที่เกี่ยวกับการใช้ตัวกรองหลายตัวกับหนึ่งซ้ำ ng บอกว่าคุณมี 2 แบบเลื่อนลงที่มีค่าและช่องใส่ข้อความหนึ่งช่อง?
เล่นแร่แปรธาตุ

ตัวกรองเป็นเพียงฟังก์ชั่นดังนั้นคุณแค่ผ่านเอาต์พุตของตัวกรองแรกไปที่ตัวกรองที่สอง
Josh David Miller

29

เนื่องจาก AngularJS 1.3 คุณสามารถใช้นามแฝง:

item in items | filter:x as results

และบางแห่ง:

<span>Total {{results.length}} result(s).</span>

จากเอกสาร :

คุณสามารถจัดเตรียมนิพจน์นามแฝงซึ่งเป็นทางเลือกซึ่งจะจัดเก็บผลลัพธ์ขั้นกลางของตัวทำซ้ำหลังจากที่ใช้ตัวกรองแล้ว โดยทั่วไปจะใช้เพื่อแสดงข้อความพิเศษเมื่อมีการใช้งานตัวกรองใน repeater แต่ชุดผลลัพธ์ที่กรองจะว่างเปล่า

ตัวอย่างเช่น: รายการในรายการ | ตัวกรอง: x เนื่องจากผลลัพธ์จะเก็บชิ้นส่วนของรายการที่ทำซ้ำเป็นผลลัพธ์ แต่หลังจากประมวลผลรายการผ่านตัวกรองแล้วเท่านั้น


ฉันไม่สามารถใช้$scope.$watchกับผลลัพธ์ที่เป็นนามแฝงนี้ได้ มีคำแนะนำสำหรับ$broadcastการใช้resultsตัวแปรaliased หรือไม่?
DeBraid

25

นอกจากนี้ยังมีประโยชน์ที่จะต้องทราบว่าคุณสามารถเก็บผลลัพธ์ได้หลายระดับด้วยการจัดกลุ่มตัวกรอง

all items: {{items.length}}
filtered items: {{filteredItems.length}}
limited and filtered items: {{limitedAndFilteredItems.length}}
<div ng-repeat="item in limitedAndFilteredItems = (filteredItems = (items | filter:search) | limitTo:25)">...</div>

นี่คือซอสาธิต


13

นี่คือตัวอย่างการใช้งานดูที่ Plunker

  <body ng-controller="MainCtrl">
    <input ng-model="search" type="text">
    <br>
    Showing {{data.length}} Persons; <br>
    Filtered {{counted}}
    <ul>
      <li ng-repeat="person in data | filter:search">
        {{person.name}}
      </li>
    </ul>
  </body>

<script> 
var app = angular.module('angularjs-starter', [])

app.controller('MainCtrl', function($scope, $filter) {
  $scope.data = [
    {
      "name": "Jim", "age" : 21
    }, {
      "name": "Jerry", "age": 26
    }, {
      "name": "Alex",  "age" : 25
    }, {
      "name": "Max", "age": 22
    }
  ];

  $scope.counted = $scope.data.length; 
  $scope.$watch("search", function(query){
    $scope.counted = $filter("filter")($scope.data, query).length;
  });
});


4
ปัญหาของวิธีนี้คือคุณใช้งานตัวกรองสองครั้ง: ครั้งเดียวใน ngRepeat และอีกครั้งในตัวควบคุม
Josh David Miller

ใช่คุณพูดถูกคุณสามารถโพสต์ตัวอย่างการทำงานของคุณตามคำตอบของคุณฉันต้องการเรียนรู้เพิ่มเติมตัวกรองอีกเล็กน้อยหรือไม่ ขอบคุณ
Maksym

2
แน่ใจ นี่คือการทำงาน Plunker นี้: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview ฉันเพิ่งแก้ไขของคุณ
Josh David Miller

10

คุณสามารถทำมันได้ด้วย2 วิธี ในแม่แบบและในการควบคุม ในเทมเพลตคุณสามารถตั้งค่าอาร์เรย์ที่ถูกกรองเป็นตัวแปรอื่นจากนั้นใช้ตามที่คุณต้องการ นี่คือวิธีที่จะทำ:

<ul>
  <li data-ng-repeat="user in usersList = (users | gender:filterGender)" data-ng-bind="user.name"></li>
</ul>
 ....
<span>{{ usersList.length | number }}</span>

หากคุณต้องการตัวอย่างดูAngularJs นับตัวอย่าง / การสาธิต

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