Cách hiển thị độ dài của dữ liệu lặp lại được lọc


438

Tôi có một mảng dữ liệu chứa nhiều đối tượng (định dạng JSON). Sau đây có thể được coi là nội dung của mảng này:

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

Bây giờ, tôi hiển thị các chi tiết này như:

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

Ở đây, truy vấn được mô hình hóa thành một trường đầu vào trong đó người dùng có thể hạn chế dữ liệu được hiển thị.

Bây giờ, tôi có một vị trí khác trong đó tôi hiển thị số người / người hiện tại đang hiển thị, tức là Showing {{data.length}} Persons

Điều tôi muốn làm là khi người dùng tìm kiếm một người và dữ liệu được hiển thị được lọc dựa trên truy vấn, thì Showing...personscũng thay đổi giá trị của những người đang được hiển thị. Nhưng nó không xảy ra. Nó luôn hiển thị tổng số người trong dữ liệu thay vì người được lọc - làm cách nào để tôi đếm được số lượng dữ liệu được lọc?

Câu trả lời:


746

Dành cho Angular 1.3+ (tín dụng cho @Tom)

Sử dụng biểu thức bí danh (Tài liệu: Angular 1.3.0: ngRepeat , cuộn xuống phần Đối số ):

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

Đối với Angular trước 1.3

Gán kết quả cho một biến mới (ví dụ filtered) và truy cập vào nó:

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

Hiển thị số lượng kết quả:

Showing {{filtered.length}} Persons

Fiddle một ví dụ tương tự . Tín dụng đi đến Pawel Kozlowski


42
Đây là câu trả lời đơn giản không lặp lại thực thi bộ lọc.
agmin

3
@Ben: Vâng. Bạn có thể truy cập nó bên trong bộ điều khiển bằng cách sử dụng $scope.filtered.length.
Wumms

2
Điều đó không làm việc cho tôi. Nhật ký undefined, có thể là do tại thời điểm đăng nhập, biến chưa được xác định. Vậy làm thế nào để tôi đảm bảo mã trong bộ điều khiển được chạy sau khi biến được xác định và bộ lọc được áp dụng trong dạng xem?
Ben

6
@Ben: Tôi đoán điều này sẽ lạc đề. Tôi muốn xem xét việc tạo bộ lọc tùy chỉnh, ví dụ jsfiddle , tuy nhiên, bạn cũng có thể xem nó bên trong bộ điều khiển:$scope.$watch('filtered', function() { console.log('filtered:', $scope.filtered); });
Wumms 18/03/2016

3
Phiên bản 1.3+ không hoạt động nếu tôi muốn thêm giới hạn : person in data | filter:query as filtered | limitTo:5. Vì vậy, tôi đã phải sử dụng phiên bản 1.3 trước:person in filtered = (data | filter: query) | limitTo: 5
benjovanic

332

Để đầy đủ, ngoài các câu trả lời trước (thực hiện tính toán những người có thể nhìn thấy bên trong bộ điều khiển), bạn cũng có thể thực hiện các tính toán đó trong mẫu HTML của mình như trong ví dụ bên dưới.

Giả sử danh sách người của bạn datathay đổi và bạn lọc mọi người bằng querymô hình, đoạn mã sau sẽ hoạt động cho bạn:

<p>Number of visible people: {{(data|filter:query).length}}</p>
<p>Total number of people: {{data.length}}</p>
  • {{data.length}} - in tổng số người
  • {{(data|filter:query).length}} - số lượng người được lọc

Lưu ý rằng giải pháp này hoạt động tốt nếu bạn muốn sử dụng dữ liệu được lọc chỉ một lần trong một trang. Tuy nhiên, nếu bạn sử dụng dữ liệu được lọc nhiều lần, ví dụ như để trình bày các mục và để hiển thị độ dài của danh sách được lọc, tôi sẽ đề xuất sử dụng biểu thức bí danh (được mô tả bên dưới) cho AngularJS 1.3+ hoặc giải pháp được đề xuất bởi @Wumms cho phiên bản AngularJS trước 1.3.

Tính năng mới trong Angular 1.3

Những người tạo AngularJS cũng nhận thấy rằng có vấn đề và trong phiên bản 1.3 (beta 17) họ đã thêm biểu thức "bí danh" sẽ lưu trữ kết quả trung gian của bộ lặp sau khi các bộ lọc được áp dụng, ví dụ

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

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

Các biểu hiện alias sẽ ngăn chặn nhiều vấn đề thực hiện bộ lọc.

Tôi hy vọng điều đó sẽ giúp.


4
Điều này có nghĩa là bộ lọc được thực thi hai lần?
Flash

9
Vâng, nó được thực hiện hai lần.
nathancahill

11
đảm bảo bạn đã đọc câu trả lời của @Wumms trước khi bạn quyết định sử dụng câu trả lời này (và bạn sẽ không) ...
epeleg

1
Mặc dù vậy, tôi thấy câu trả lời không có phần về biểu thức bí danh khi bạn đưa ra nhận xét của mình.
Adam Goodwin

2
Câu trả lời này hỗ trợ nhiều biểu thức lọc không giống như câu trả lời hàng đầu hiện tại. tức là){{(data|filter:query|filter:query2).length}}
chakena

45

Cách dễ nhất nếu bạn có

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

Độ dài dữ liệu được lọc

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

Điều này hữu ích nhất cho bất kỳ ai sử dụng chỉ thị góc cạnh dirils phân trang vì hàm răng cưa và thay thế ng-1.3 trước không được hỗ trợ.
pcnate

Điều này sẽ liệt kê dữ liệu hai lần?
Jeppe

36

ngRepeat tạo một bản sao của mảng khi nó áp dụng bộ lọc, vì vậy bạn không thể sử dụng mảng nguồn để chỉ tham chiếu các phần tử được lọc.

Trong trường hợp của bạn, có thể tốt hơn để áp dụng bộ lọc bên trong bộ điều khiển của bạn bằng $filterdịch vụ:

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

  $scope.filteredData = myNormalData;

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

  // ...
}

Và sau đó bạn sử dụng filteredDatatài sản trong quan điểm của bạn thay vào đó. Đây là một Plunker hoạt động: http://plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview


1
Những gì tôi hiểu là tôi sử dụng {{filteredData.length}}thay vì data.length. Tôi cũng hiểu rằng myInputModelmô hình được ánh xạ tới truy vấn đầu vào để lọc dữ liệu. valsẽ là văn bản được nhập vào đầu vào (về cơ bản là truy vấn) nhưng mỗi lần tôi gõ, nó sẽ thay đổi. Nhưng cái gì filterFilterở đây? Tôi có thể thêm rằng tôi đã tạo customFilter của riêng mình (trong đó tôi có thể chỉ định khóa nào của đối tượng cần xem xét để lọc).
109187

Đúng rồi. Cũng chỉ sử dụng ng-repeat="person in filteredData"vì không có ý nghĩa lọc nó hai lần. Với $filterdịch vụ, bạn có thể yêu cầu một bộ lọc cụ thể bằng cách chỉ suffixing nó với "Bộ lọc", ví dụ như: dateFilter, jsonFilter, vv Nếu bạn đang sử dụng bộ lọc riêng của bạn, chỉ cần sử dụng một thay vì chung chung filterFilter.
Josh David Miller

Điều gì về việc áp dụng nhiều bộ lọc cho một lần lặp lại, giả sử bạn có 2 lần thả xuống với các giá trị và một trường nhập văn bản?
giả kim

Bộ lọc chỉ là một chức năng, vì vậy bạn chỉ cần chuyển đầu ra của bộ lọc thứ nhất sang bộ lọc thứ hai.
Josh David Miller

29

Vì AngularJS 1.3, bạn có thể sử dụng bí danh:

item in items | filter:x as results

và ở đâu đó:

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

Từ tài liệu :

Bạn cũng có thể cung cấp một biểu thức bí danh tùy chọn, sau đó sẽ lưu kết quả trung gian của bộ lặp sau khi các bộ lọc được áp dụng. Thông thường, điều này được sử dụng để hiển thị một thông báo đặc biệt khi bộ lọc được kích hoạt trên bộ lặp, nhưng bộ kết quả được lọc trống.

Ví dụ: mục trong mục | bộ lọc: x vì kết quả sẽ lưu trữ đoạn của các mục lặp lại dưới dạng kết quả, nhưng chỉ sau khi các mục đã được xử lý qua bộ lọc.


Tôi không thể áp dụng $scope.$watchcho kết quả bí danh này. Bất kỳ lời khuyên cho $broadcasting resultsbiến bí danh ?
DeBear

25

Nó cũng hữu ích để lưu ý rằng bạn có thể lưu trữ nhiều cấp độ kết quả bằng cách nhóm các bộ lọc

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>

đây là một fiddle demo


13

Dưới đây là ví dụ hoạt động Xem trên 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
Vấn đề với cách tiếp cận này là bạn đang chạy bộ lọc hai lần: một lần trong ngRepeat và một lần trong bộ điều khiển.
Josh David Miller

Vâng, bạn nói đúng, bạn có thể đăng ví dụ làm việc của bạn dựa trên câu trả lời của bạn không, tôi muốn tìm hiểu thêm một số bộ lọc? Cảm ơn.
Maksym

2
Chắc chắn rồi. Đây là Plunker đang hoạt động: plnkr.co/edit/7c1l24rPkuKPOS5o2qtx?p=preview . Tôi chỉ chỉnh sửa của bạn.
Josh David Miller

10

Bạn có thể làm điều đó với 2 cách . Trong mẫu và trong Bộ điều khiển . Trong mẫu bạn có thể đặt mảng đã lọc của mình thành một biến khác, sau đó sử dụng nó như bạn muốn. Đây là cách làm:

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

Nếu bạn cần ví dụ, hãy xem các ví dụ / bản trình diễn được lọc của AngularJs

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.