Lọc theo nhiều thuộc tính mô hình cụ thể trong AngularJS (trong mối quan hệ OR)


107

Hãy xem ví dụ ở đây: http://docs.angularjs.org/api/ng.filter:filter

Bạn có thể tìm kiếm theo bất kỳ thuộc tính nào của điện thoại bằng cách sử dụng <input ng-model="search">và bạn có thể tìm kiếm chỉ theo tên bằng cách sử dụng <input ng-model="search.name">, và kết quả được lọc theo tên một cách thích hợp (nhập số điện thoại không trả lại bất kỳ kết quả nào, như mong đợi).

Giả sử tôi có một mô hình có thuộc tính "name", thuộc tính "phone" và thuộc tính "secret", làm cách nào để lọc theo cả thuộc tính "name" và "phone" chứ không phải thuộc tính "secret" ? Vì vậy, về bản chất, người dùng có thể nhập tên hoặc số điện thoại và ng-repeatbộ lọc sẽ lọc chính xác, nhưng ngay cả khi người dùng nhập giá trị bằng một phần của giá trị "bí mật", nó sẽ không trả về bất kỳ thứ gì.

Cảm ơn.


Huh, tôi thực sự bối rối là tại sao việc gắn một đối tượng "tên" vào trường đầu vào ng-model(chỉ định search.nametrong trường INPUT ng-model) sẽ dẫn đến việc các đối tượng lặp lại được lọc theo thuộc tính của chúng name? Tức là bằng trực giác đối với tôi, bạn sẽ có thể cụ thể lọc theo chỉ namebằng cách xác định trong bạn ng-repeatlọc: filter: friend.name, thay vì `viết '<input ng mô hình = "search.name"> ...
LazerSharks

Câu trả lời:


171

Đây là plunker

Plunker mới với mã rõ ràng hơn và trong đó cả truy vấn và mục danh sách tìm kiếm đều không phân biệt chữ hoa chữ thường

Ý tưởng chính là tạo một chức năng bộ lọc để đạt được mục đích này.

Từ tài liệu chính thức

chức năng: Một chức năng vị từ có thể được sử dụng để viết các bộ lọc tùy ý. Hàm được gọi cho mỗi phần tử của mảng. Kết quả cuối cùng là một mảng các phần tử mà vị từ trả về true.

<input ng-model="query">

<tr ng-repeat="smartphone in smartphones | filter: search "> 

$scope.search = function(item) {
    if (!$scope.query || (item.brand.toLowerCase().indexOf($scope.query) != -1) || (item.model.toLowerCase().indexOf($scope.query.toLowerCase()) != -1) ){
        return true;
    }
    return false;
};

Cập nhật

Một số người có thể lo lắng về hiệu suất trong thế giới thực, điều này đúng.

Trong thế giới thực, chúng tôi có thể sẽ thực hiện bộ lọc kinda này từ bộ điều khiển.

Đây là bài viết chi tiết hướng dẫn cách làm.

tóm lại, chúng tôi thêm ng-changevào đầu vào để theo dõi thay đổi tìm kiếm mới

và sau đó kích hoạt chức năng lọc.


1
Xin chào @maxisam, bạn có thể giải thích ý nghĩa của các đường thẳng kép không? Tôi không thực sự chắc chắn làm thế nào để đọc dòng này:item.brand.indexOf($scope.query)!=-1 || item.model.indexOf($scope.query)!=-1)
LazerSharks

15
|| nghĩa là HOẶC. Bạn có thể muốn đọc Javascript, những phần hay.
maxisam

1
Nói về ||, chỉ cần thử cái này và nó hoạt động: <tr ng-repeat = "smartphone trong smartphone | filter: phone || name">. Bộ lọc đầu tiên được ưu tiên.
Jazzy

2
@kate angular.lowercase (item.brand) .indexOf ... về cơ bản, chỉ thấp hơn trường hợp tất cả mọi thứ
maxisam

1
@maxisam. Chuỗi truy vấn cũng cần phải là chữ thường để phân biệt chữ hoa chữ thường hoạt động chính xác. Đây là một Fork của bạn plunker với sự phân biệt chữ hoa chữ thường. plnkr.co/edit/auz02bvWm1Vw4eItSa5J?p=preview Cảm ơn bộ lọc.
Leopold Kristjansson

78

Bạn có thể chuyển một Đối tượng làm tham số cho biểu thức bộ lọc của mình, như được mô tả trong Tham chiếu API . Đối tượng này có thể áp dụng một cách chọn lọc các thuộc tính mà bạn quan tâm, như vậy:

<input ng-model="search.name">
<input ng-model="search.phone">
<input ng-model="search.secret">
<tr ng-repeat="user in users | filter:{name: search.name, phone: search.phone}">

Đây là một Plunker

Lưu ý ... ví dụ này hoạt động tốt với AngularJS 1.1.5, nhưng không phải lúc nào cũng tốt trong 1.0.7. Trong ví dụ này, 1.0.7 sẽ khởi tạo với mọi thứ được lọc ra, sau đó hoạt động khi bạn bắt đầu sử dụng các đầu vào. Nó hoạt động giống như các đầu vào có các giá trị không khớp, mặc dù chúng bắt đầu trống. Nếu bạn muốn duy trì các bản phát hành ổn định, hãy tiếp tục và thử điều này cho tình huống của bạn, nhưng một số trường hợp có thể muốn sử dụng giải pháp của @ maxisam cho đến khi 1.2.0 được phát hành.


26
Nhìn vào chiếc máy của bạn như thế nào sẽ đạt được hiệu quả mong muốn nếu bạn chỉ có một hộp tìm kiếm. Đây là thử thách ... phần HOẶC.
silvster27

2
Câu trả lời này là vàng nhưng chỉ không trả lời câu hỏi.
Cyril CHAPON

1
Bạn sẽ thực hiện như thế nào với chỉ một trường đầu vào như trong ví dụ này trong bảng: datatables.net
Flash

Làm cách nào để bạn đếm được dữ liệu đã lọc trong Plunker đã đăng?
Muhammad Zeeshan Tahir

5

Tôi lấy cảm hứng từ câu trả lời của @ maxisam và tạo ra chức năng sắp xếp của riêng mình và tôi muốn chia sẻ nó (vì tôi chán).

Tình huống tôi muốn lọc qua một loạt các ô tô. Các thuộc tính được chọn để lọc là tên, năm, giá và km. Giá tài sản và km là số (do đó sử dụng .toString). Tôi cũng muốn kiểm soát các chữ hoa (do đó .toLowerCase). Ngoài ra, tôi muốn có thể chia truy vấn bộ lọc của mình thành các từ khác nhau (ví dụ: với bộ lọc 2006 Acura, nó tìm thấy các kết quả phù hợp với 2006 với năm và Acura với tên).

Chức năng tôi chuyển sang bộ lọc

        var attrs = [car.name.toLowerCase(), car.year, car.price.toString(), car.km.toString()],
            filters = $scope.tableOpts.filter.toLowerCase().split(' '),
            isStringInArray = function (string, array){
                for (var j=0;j<array.length;j++){
                    if (array[j].indexOf(string)!==-1){return true;}
                }
                return false;
            };

        for (var i=0;i<filters.length;i++){
            if (!isStringInArray(filters[i], attrs)){return false;}
        }
        return true;
    };

1
Bạn có thể chỉ ra cách bạn gọi bộ lọc này trong Angular không?
twknab 27/02/17



2

Có rất nhiều giải pháp tốt ở đây nhưng tôi khuyên bạn nên đi theo con đường khác với điều này. Nếu tìm kiếm là điều quan trọng nhất và thuộc tính 'bí mật' hoàn toàn không được sử dụng trên chế độ xem; cách tiếp cận của tôi cho điều này là sử dụng bộ lọc góc tích hợp với tất cả các lợi ích của nó và chỉ cần ánh xạ mô hình tới một mảng đối tượng mới.

Ví dụ từ câu hỏi:

$scope.people = members.map(function(member) { 
                              return { 
                                name: member.name, 
                                phone: member.phone
                              }});

Bây giờ, trong html chỉ cần sử dụng bộ lọc thông thường để tìm kiếm cả hai thuộc tính này.

<div ng-repeat="member in people | filter: searchString">

1
Tôi thích giải pháp này để xử lý các đối tượng nhỏ, nhưng nếu bạn có một tập hợp các đối tượng lớn với nhiều thứ lồng vào nhau, việc lập bản đồ mọi thứ có thể gây nhầm lẫn / dễ tạo ra lỗi. +1 mặc dù cho một giải pháp tuyệt vời cho các nhu cầu cơ bản ... ước gì điều này không quá phức tạp để chỉ lọc một vài thuộc tính thay vì tất cả! : / ... có thể trong tương lai Angular có thể thêm một số chức năng được tích hợp sẵn cho các bộ lọc loại này ...
twknab

2

Cách tiếp cận khá thẳng bằng cách sử dụng filterBy in angleJs

Để làm việc plnkr theo liên kết này

http://plnkr.co/edit/US6xE4h0gD5CEYV0aMDf?p=preview

Điều này đã đặc biệt sử dụng một thuộc tính duy nhất để tìm kiếm dựa trên nhiều cột nhưng không phải tất cả.

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="angular.js@1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
    <script data-require="angular-filter@0.5.2" data-semver="0.5.2" src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.2/angular-filter.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="myCtrl as vm">
  <input type="text" placeholder="enter your search text" ng-model="vm.searchText" />
   <table>
     <tr ng-repeat="row in vm.tableData | filterBy: ['col1','col2']: vm.searchText">
       <td>{{row.col1}}</td>
       <td>{{row.col2}}</td>
       <td>{{row.col3}}</td>
     </tr>
   </table>
   <p>This will show filter from <b>two columns</b> only(col1 and col2) . Not from all. Whatever columns you add into filter array they
   will be searched. all columns will be used by default if you use <b>filter: vm.searchText</b></p>
  </body>
</html>

người điều khiển

// Code goes here
(function(){

  var myApp = angular.module('myApp',['angular.filter']);

  myApp.controller('myCtrl', function($scope){
    var vm= this;
    vm.x = 20;

    vm.tableData = [
      {
        col1: 'Ashok',
        col2: 'Tewatia',
        col3: '12'
      },{
        col1: 'Babita',
        col2: 'Malik',
        col3: '34'
      },{
        col1: 'Dinesh',
        col2: 'Tewatia',
        col3: '56'
      },{
        col1: 'Sabita',
        col2: 'Malik',
        col3: '78'
      }
      ];
  })

})();

Nhược điểm là nó thêm một plugin của bên thứ ba. Quan trọng là gọi ra.
mix3d

2

Tôi đã giải quyết điều này một cách đơn giản:

<div ng-repeat="Object in List | filter: (FilterObj.FilterProperty1 ? {'ObjectProperty1': FilterObj.FilterProperty1} : '') | filter:(FilterObj.FilterProperty2 ? {'ObjectProperty2': FilterObj.FilterProperty2} : '')">

1

http://plnkr.co/edit/A2IG03FLYnEYMpZ5RxEm?p=preview

Đây là một tìm kiếm phân biệt chữ hoa chữ thường cũng tách tìm kiếm của bạn thành các từ để tìm kiếm trong từng mô hình. Chỉ khi nó tìm thấy một khoảng trắng, nó sẽ cố gắng chia truy vấn thành một mảng và sau đó tìm kiếm từng từ.

Nó trả về true nếu mọi từ có ít nhất một trong các mô hình.

$scope.songSearch = function (row) {
    var query = angular.lowercase($scope.query);
    if (query.indexOf(" ") > 0) {
        query_array = query.split(" ");
        search_result = false;
        for (x in query_array) {
            query = query_array[x];
            if (angular.lowercase(row.model1).indexOf(query || '') !== -1 || angular.lowercase(row.model2).indexOf(query || '') !== -1 || angular.lowercase(row.model3).indexOf(query || '') !== -1){
                search_result = true;
            } else {
                search_result = false;
                break;
            }
        }
        return search_result;
    } else {
        return (angular.lowercase(row.model1).indexOf(query || '') !== -1 || angular.lowercase(row.model2).indexOf(query || '') !== -1 || angular.lowercase(row.model3).indexOf(query || '') !== -1);
    }
};

1

Bộ lọc có thể là một đối tượng JavaScript với các trường và bạn có thể có biểu thức như sau:

ng-repeat= 'item in list | filter :{property:value}'

0

Tôi thích giữ là đơn giản khi có thể. Tôi cần nhóm theo Quốc tế, lọc trên tất cả các cột, hiển thị số lượng cho mỗi nhóm và ẩn nhóm nếu không có mục nào tồn tại.

Thêm vào đó, tôi không muốn thêm bộ lọc tùy chỉnh chỉ cho những thứ đơn giản như thế này.

        <tbody>
            <tr ng-show="fusa.length > 0"><td colspan="8"><h3>USA ({{fusa.length}})</h3></td></tr>
            <tr ng-repeat="t in fusa = (usa = (vm.assignmentLookups | filter: {isInternational: false}) | filter: vm.searchResultText)">
                <td>{{$index + 1}}</td>
                <td ng-bind-html="vm.highlight(t.title, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.genericName, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.mechanismsOfAction, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.diseaseStateIndication, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.assignedTo, vm.searchResultText)"></td>
                <td ng-bind-html="t.lastPublished | date:'medium'"></td>
            </tr>
        </tbody>
        <tbody>
            <tr ng-show="fint.length > 0"><td colspan="8"><h3>International ({{fint.length}})</h3></td></tr>
            <tr ng-repeat="t in fint = (int = (vm.assignmentLookups | filter: {isInternational: true}) | filter: vm.searchResultText)">
                <td>{{$index + 1}}</td>
                <td ng-bind-html="vm.highlight(t.title, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.genericName, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.mechanismsOfAction, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.diseaseStateIndication, vm.searchResultText)"></td>
                <td ng-bind-html="vm.highlight(t.assignedTo, vm.searchResultText)"></td>
                <td ng-bind-html="t.lastPublished | date:'medium'"></td>
            </tr>
        </tbody>

0

Tôi có thể đến rất muộn nhưng đây là những gì tôi đã làm. Tôi đã thực hiện một bộ lọc rất chung chung.

angular.module('app.filters').filter('fieldFilter', function() {
        return function(input, clause, fields) {
            var out = [];
            if (clause && clause.query && clause.query.length > 0) {
                clause.query = String(clause.query).toLowerCase();
                angular.forEach(input, function(cp) {
                    for (var i = 0; i < fields.length; i++) {
                        var haystack = String(cp[fields[i]]).toLowerCase();
                        if (haystack.indexOf(clause.query) > -1) {
                            out.push(cp);
                            break;
                        }
                    }
                })
            } else {
                angular.forEach(input, function(cp) {
                    out.push(cp);
                })
            }
            return out;
        }

    })

Sau đó sử dụng nó như thế này

<tr ng-repeat-start="dvs in devices |  fieldFilter:search:['name','device_id']"></tr>

Hộp tìm kiếm của bạn giống như

<input ng-model="search.query" class="form-control material-text-input" type="text">

trong đó name và device_id là thuộc tính trong dvs


-1

Đây là giải pháp đơn giản cho những ai muốn lọc nhanh một đối tượng:

<select>
  <option ng-repeat="card in deck.Cards | filter: {Type: 'Face'}">{{card.Name}}</option>
</select>

Bộ lọc mảng cho phép bạn bắt chước đối tượng mà bạn đang cố gắng lọc. Trong trường hợp trên, các lớp sau sẽ hoạt động tốt:

var card = function(name, type) {
  var _name = name;
  var _type = type;

  return {
    Name: _name,
    Type: _type
  };
};

Và bộ bài có thể trông như thế nào:

var deck = function() {
  var _cards = [new card('Jack', 'Face'),
                new card('7', 'Numeral')];

  return {
    Cards: _cards
  };
};

Và nếu bạn muốn lọc nhiều thuộc tính của đối tượng, chỉ cần phân tách các tên trường bằng dấu phẩy:

<select>
  <option ng-repeat="card in deck.Cards | filter: {Type: 'Face', Name: 'Jack'}">{{card.Name}}</option>
</select>

CHỈNH SỬA: Đây là một plnkr đang hoạt động cung cấp ví dụ về các bộ lọc thuộc tính đơn và nhiều thuộc tính:

http://embed.plnkr.co/i0wCx6l1WPYljk57SXzV/


Bạn sẽ triển khai loại tìm kiếm này như thế nào? Trong ví dụ này trong bảng của họ, bạn có thể nhập một phần của từ, nhấn phím cách và nhập một phần của từ khác vào một cột và nó vẫn lọc theo đó. datatables.net
Flash

Tôi không biết tại sao bài viết của tôi bị hạ cấp trừ khi tôi không giải quyết câu hỏi đúng cách. Mã hoạt động khi bạn áp dụng đúng cách.
Rick

Cảm ơn bạn đã trả lời rick Tôi không biết ai đã bỏ phiếu nhưng tôi có thể tiếp tục và bỏ phiếu lại. Tuy nhiên, trong ví dụ đó như thế nào thì tương tự như trong liên kết mà tôi đã cung cấp, nơi họ có trường nhập tìm kiếm và khi họ nhập, nó sẽ lọc ra. Hers là bài đăng ban đầu của tôi mà ai đó cũng đã bình chọn nó: stackoverflow.com/questions/42421941/angular-custom-search
Flash

1
Tôi đã cập nhật plnkr để hiển thị cách bộ lọc hộp văn bản có thể hoạt động. Lưu ý cách nó lọc trên bất kỳ phần văn bản nào như mong đợi. Tôi tin rằng điều này gần với ví dụ được liên kết của bạn. Nếu bạn cần nhiều bộ lọc (cho các phần dữ liệu riêng biệt) thì đó là một câu hỏi khác.
Rick

@Rick Tôi thực sự đánh giá cao việc bạn dành thời gian cho ví dụ này, vì tôi hiện đang cố gắng tìm ra bản thân mình để chỉ lọc 2 thuộc tính thay vì tất cả các thuộc tính trong một đối tượng đang được lặp lại ng-repeat. Tuy nhiên, ví dụ của bạn có vẻ hơi phức tạp: có cách nào bạn có thể đun sôi nó không? Tôi biết câu hỏi về cơ bản là tìm kiếm một trường tìm kiếm duy nhất có thể lọc các thuộc tính đã chọn. Trong ví dụ của bạn, có vẻ như chúng tôi đang lọc tên hoặc số theo mệnh giá, nhưng không lọc cả hai. Nếu tôi hiểu ví dụ của bạn không chính xác, vui lòng cho tôi biết!
twknab
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.