Cara memfilter beberapa nilai (operasi OR) dalam angularJS


135

Saya ingin menggunakan filterdalam sudut dan ingin memfilter untuk beberapa nilai, jika memiliki salah satu dari nilai maka harus ditampilkan.

Saya punya contoh struktur ini:

Objek movieyang memiliki properti genresdan saya ingin memfilter untuk Actiondan Comedy.

Saya tahu saya bisa melakukannya filter:({genres: 'Action'} || {genres: 'Comedy'}), tetapi apa yang harus saya lakukan jika saya ingin memfilternya secara dinamis. Misalnyafilter: variableX

Bagaimana cara mengatur variableXdi $scope, ketika saya memiliki array genre yang harus saya filter?

Saya dapat membangunnya sebagai string dan kemudian melakukan eval()tetapi saya tidak ingin menggunakan eval () ...


16
apakah kamu yakin itu filter:({genres: 'Action'} || {genres: 'Comedy'})bekerja? itu tidak di angular 1.3.16.
twmulloy

4
sama untuk 1.4.8! itu hanya tidak berfungsi ^^
Alex

Jawaban:


87

Saya hanya akan membuat filter khusus. Mereka tidak terlalu sulit.

angular.module('myFilters', []).
  filter('bygenre', function() {
    return function(movies,genres) {
      var out = [];
      // Filter logic here, adding matches to the out var.
      return out;
    }
  });

templat:

<h1>Movies</h1>

<div ng-init="movies = [
          {title:'Man on the Moon', genre:'action'},
          {title:'Meet the Robinsons', genre:'family'},
          {title:'Sphere', genre:'action'}
       ];" />
<input type="checkbox" ng-model="genrefilters.action" />Action
<br />
<input type="checkbox" ng-model="genrefilters.family" />Family
<br />{{genrefilters.action}}::{{genrefilters.family}}
<ul>
    <li ng-repeat="movie in movies | bygenre:genrefilters">{{movie.title}}: {{movie.genre}}</li>
</ul>

Sunting di sini adalah tautannya: Membuat Filter Sudut

UPDATE : Ini adalah biola yang memiliki demo yang tepat dari saran saya.


jadi di luar saya mengembalikan objek film yang ingin saya tampilkan?
JustGoscha

Maaf aku butuh waktu untuk kembali. Saya memperbarui jawaban saya dengan contoh nyata.
Xesued

ok, terima kasih, sementara itu saya menemukan
jawabannya

Entah saya memiliki dua nilai seperti aktif dan tidak aktif lalu bagaimana saya bisa mencari menggunakan filter ini secara terpisah. kami tidak ingin membuat filter khusus.
VjyV

80

Anda dapat menggunakan fungsi pengontrol untuk memfilter.

function MoviesCtrl($scope) {

    $scope.movies = [{name:'Shrek', genre:'Comedy'},
                     {name:'Die Hard', genre:'Action'},
                     {name:'The Godfather', genre:'Drama'}];

    $scope.selectedGenres = ['Action','Drama'];

    $scope.filterByGenres = function(movie) {
        return ($scope.selectedGenres.indexOf(movie.genre) !== -1);
    };

}

HTML:

<div ng-controller="MoviesCtrl">
    <ul>
        <li ng-repeat="movie in movies | filter:filterByGenres">
            {{ movie.name }} {{ movie.genre }}
        </li>
    </ul>
</div>

1
Selain pemisahan kekhawatiran, apakah ada alasan (kinerja bijaksana) bahwa ini akan dihindari?
Sean Larkin

1
versi javascript jika orang lain mencarinya:$scope.filteredMovies = $filter('filter')($scope.movies, $scope.filterByGenres);
Evan

23

Membuat filter khusus mungkin berlebihan di sini, Anda bisa meneruskan komparator kustom, jika Anda memiliki nilai kelipatan seperti:

$scope.selectedGenres = "Action, Drama"; 

$scope.containsComparator = function(expected, actual){  
  return actual.indexOf(expected) > -1;
};

lalu di filter:

filter:{name:selectedGenres}:containsComparator

1
Banyak membantu saya. Terima kasih
Hristo Enev

@ chrismarx Apa yang ng-modelada di file tampilan untuk ditautkan ke filter yang dijelaskan? (maaf, masih belajar di sini) - Aku seperti kesederhanaan jawaban Anda dan mencoba untuk mendapatkannya bekerja tetapi tidak yakin bagaimana untuk label saya <input>'s ng-model. :)
twknab


18

Berikut ini adalah implementasi filter kustom, yang akan memfilter data menggunakan array nilai. Ini akan mendukung objek multi-kunci dengan array dan nilai kunci tunggal. Seperti yang disebutkan di dalam segitigaJS API AngularJS filter Doc mendukung beberapa filter kunci dengan nilai tunggal, tetapi filter kustom di bawah ini akan mendukung fitur yang sama seperti angularJS dan juga mendukung berbagai nilai dan kombinasi dari kedua array dan nilai kunci tunggal. Silakan temukan cuplikan kode di bawah ini,

myApp.filter('filterMultiple',['$filter',function ($filter) {
return function (items, keyObj) {
    var filterObj = {
        data:items,
        filteredData:[],
        applyFilter : function(obj,key){
            var fData = [];
            if (this.filteredData.length == 0)
                this.filteredData = this.data;
            if (obj){
                var fObj = {};
                if (!angular.isArray(obj)){
                    fObj[key] = obj;
                    fData = fData.concat($filter('filter')(this.filteredData,fObj));
                } else if (angular.isArray(obj)){
                    if (obj.length > 0){
                        for (var i=0;i<obj.length;i++){
                            if (angular.isDefined(obj[i])){
                                fObj[key] = obj[i];
                                fData = fData.concat($filter('filter')(this.filteredData,fObj));    
                            }
                        }

                    }
                }
                if (fData.length > 0){
                    this.filteredData = fData;
                }
            }
        }
    };
    if (keyObj){
        angular.forEach(keyObj,function(obj,key){
            filterObj.applyFilter(obj,key);
        });
    }
    return filterObj.filteredData;
}
}]);

Pemakaian:

arrayOfObjectswithKeys | filterMultiple:{key1:['value1','value2','value3',...etc],key2:'value4',key3:[value5,value6,...etc]}

Berikut adalah contoh biola dengan penerapan filter kustom "filterMutiple" di atas . ::: Contoh Fiddle :::


1
Anda tampaknya memiliki niat yang benar tetapi teladan Anda tampaknya tidak berfungsi seperti yang diharapkan. Output dalam tabel tampaknya agak tidak konsisten.
Hultner

Ini tidak berfungsi dengan JSON dengan objek bersarang. Akan ideal jika itu terjadi. juga itu memunculkan length property undefinedkesalahan di konsol.
SinSync

Ini berfungsi untuk saya tetapi mengembalikan semua hasil jika tidak menemukan atribut yang dicari dalam daftar, bagaimana saya bisa membalikkan perilaku ini dan tidak mengembalikan hasil jika nilainya tidak ada dalam daftar?
Zakaria Belghiti

@ZakariaBelghiti jika Anda ingin mengembalikan tidak ada hasil, maka ubah kode: if (fData.length > 0){ this.filteredData = fData; } menjadi: this.filteredData = fData;
pconnor88

@ Gerfried Saya pikir situs itu benar-benar mengikis Stackoverflow, jadi mereka mencuri jawabannya, bukan sebaliknya
Chris

13

Jika Anda ingin memfilter pada Array of Objects maka Anda dapat memberikan

filter:({genres: 'Action', key :value }.

Properti individu akan disaring oleh filter tertentu yang diberikan untuk properti itu.

Tetapi jika Anda ingin sesuatu seperti filter oleh Properti individu dan filter global untuk semua properti maka Anda dapat melakukan sesuatu seperti ini.

<tr ng-repeat="supp in $data | filter : filterObject |  filter : search">
Di mana "filterObject" adalah objek untuk mencari properti individu dan "Pencarian" akan mencari di setiap properti secara global.

~ Atul


Ini bekerja dengan baik untuk saya dan merupakan solusi yang lebih baik daripada yang lain menyarankan pembongkaran pemfilteran ke suatu fungsi karena AngularJS cocok dengan sebagian teks ketika memfilter pada string.
Snaver

9

Saya telah meluangkan waktu untuk itu dan terima kasih kepada @ chrismarx, saya melihat bahwa standar angular filterFiltermemungkinkan Anda untuk melewati komparator Anda sendiri. Berikut komparator yang diedit untuk beberapa nilai:

  function hasCustomToString(obj) {
        return angular.isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
  }
  var comparator = function (actual, expected) {
    if (angular.isUndefined(actual)) {
      // No substring matching against `undefined`
      return false;
    }
    if ((actual === null) || (expected === null)) {
      // No substring matching against `null`; only match against `null`
      return actual === expected;
    }
    // I edited this to check if not array
    if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
      // Should not compare primitives against objects, unless they have custom `toString` method
      return false;
    }
    // This is where magic happens
    actual = angular.lowercase('' + actual);
    if (angular.isArray(expected)) {
      var match = false;
      expected.forEach(function (e) {
        e = angular.lowercase('' + e);
        if (actual.indexOf(e) !== -1) {
          match = true;
        }
      });
      return match;
    } else {
      expected = angular.lowercase('' + expected);
      return actual.indexOf(expected) !== -1;
    }
  };

Dan jika kita ingin membuat filter khusus untuk KERING:

angular.module('myApp')
    .filter('filterWithOr', function ($filter) {
      var comparator = function (actual, expected) {
        if (angular.isUndefined(actual)) {
          // No substring matching against `undefined`
          return false;
        }
        if ((actual === null) || (expected === null)) {
          // No substring matching against `null`; only match against `null`
          return actual === expected;
        }
        if ((angular.isObject(expected) && !angular.isArray(expected)) || (angular.isObject(actual) && !hasCustomToString(actual))) {
          // Should not compare primitives against objects, unless they have custom `toString` method
          return false;
        }
        console.log('ACTUAL EXPECTED')
        console.log(actual)
        console.log(expected)

        actual = angular.lowercase('' + actual);
        if (angular.isArray(expected)) {
          var match = false;
          expected.forEach(function (e) {
            console.log('forEach')
            console.log(e)
            e = angular.lowercase('' + e);
            if (actual.indexOf(e) !== -1) {
              match = true;
            }
          });
          return match;
        } else {
          expected = angular.lowercase('' + expected);
          return actual.indexOf(expected) !== -1;
        }
      };
      return function (array, expression) {
        return $filter('filter')(array, expression, comparator);
      };
    });

Dan kemudian kita dapat menggunakannya di mana saja yang kita inginkan:

$scope.list=[
  {name:'Jack Bauer'},
  {name:'Chuck Norris'},
  {name:'Superman'},
  {name:'Batman'},
  {name:'Spiderman'},
  {name:'Hulk'}
];


<ul>
  <li ng-repeat="item in list | filterWithOr:{name:['Jack','Chuck']}">
    {{item.name}}
  </li>
</ul>

Akhirnya di sini adalah sebuah plunkr .

Catatan: Array yang diharapkan hanya boleh berisi objek sederhana seperti String , Number dll.


Terima kasih, ini membantu saya. Untuk memeriksa filter nilai tunggalWithOr: {name: 'Jack'} Jika ada yang membutuhkan yang sama dengan saya ...
Juan

7

Anda dapat menggunakan filter searchField dari angular.filter

JS:

$scope.users = [
 { first_name: 'Sharon', last_name: 'Melendez' },
 { first_name: 'Edmundo', last_name: 'Hepler' },
 { first_name: 'Marsha', last_name: 'Letourneau' }
];

HTML:

<input ng-model="search" placeholder="search by full name"/> 
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
  {{ user.first_name }} {{ user.last_name }}
</th>
<!-- so now you can search by full name -->

3
Anda juga dapat menggunakan "where" dari angular.filter <tr ng-repeat = "obj dalam koleksi | where: {id: 1}"> {{obj.name}} </tr>
hcarreras

1
search
Akash

1
Saya mencoba ini dan mengatur modul di aplikasi sudut saya dan script di HTML indeks saya, tetapi saya masih bisa mencari SEMUA bidang, bukan hanya yang saya tentukan :(
twknab

7

Anda juga dapat menggunakan ngIfjika situasinya memungkinkan:

<div ng-repeat="p in [
 { name: 'Justin' }, 
 { name: 'Jimi' }, 
 { name: 'Bob' }
 ]" ng-if="['Jimi', 'Bob'].indexOf(e.name) > -1">
 {{ p.name }} is cool
</div>

1
Solusi yang bagus dan sederhana!
Leopoldo Sanczyk

7

Solusi tercepat yang saya temukan adalah menggunakan filterBy filter dari angular-filter , misalnya:

<input type="text" placeholder="Search by name or genre" ng-model="ctrl.search"/>   
<ul>
  <li ng-repeat="movie in ctrl.movies | filterBy: ['name', 'genre']: ctrl.search">
    {{movie.name}} ({{movie.genre}}) - {{movie.rating}}
  </li>
</ul>

Sisi baiknya adalah filter sudut adalah pustaka yang cukup populer (~ bintang 2.6k di GitHub) yang masih dikembangkan dan dipelihara secara aktif, jadi sebaiknya menambahkannya ke proyek Anda sebagai dependensi.


1
Sejauh ini jawaban terbaik. Terima kasih.
Daniel Gruszczyk

4

Saya yakin inilah yang Anda cari:

<div>{{ (collection | fitler1:args) + (collection | filter2:args) }}</div>

1
Itu hanya menggabungkan array dan tidak mengembalikan serikat.
muaaz

Kecuali saya salah mengerti implementasi, saya gagal melihat bagaimana itu menjadi masalah.
jKlaus

2

Silakan coba ini

var m = angular.module('yourModuleName');
m.filter('advancefilter', ['$filter', function($filter){
    return function(data, text){
        var textArr = text.split(' ');
        angular.forEach(textArr, function(test){
            if(test){
                  data = $filter('filter')(data, test);
            }
        });
        return data;
    }
}]);

2

Mari kita asumsikan Anda memiliki dua array, satu untuk film dan satu untuk genre

Cukup gunakan filter sebagai: filter:{genres: genres.type}

Di sini genre menjadi array dan tipe memiliki nilai untuk genre


1

Saya menulis ini untuk string DAN fungsionalitas (saya tahu ini bukan pertanyaan, tetapi saya mencarinya dan tiba di sini), mungkin itu dapat diperluas.

String.prototype.contains = function(str) {
  return this.indexOf(str) != -1;
};

String.prototype.containsAll = function(strArray) {
  for (var i = 0; i < strArray.length; i++) {
    if (!this.contains(strArray[i])) {
      return false;
    }
  }
  return true;
}

app.filter('filterMultiple', function() {
  return function(items, filterDict) {
    return items.filter(function(item) {
      for (filterKey in filterDict) {
        if (filterDict[filterKey] instanceof Array) {
          if (!item[filterKey].containsAll(filterDict[filterKey])) {
            return false;
          }
        } else {
          if (!item[filterKey].contains(filterDict[filterKey])) {
            return false;
          }
        }
      }
      return true;
    });  
  };
});

Pemakaian:

<li ng-repeat="x in array | filterMultiple:{key1: value1, key2:[value21, value22]}">{{x.name}}</li>


1

Saya memiliki situasi yang serupa. Menulis filter khusus berfungsi untuk saya. Semoga ini membantu!

JS:

App.filter('searchMovies', function() {
    return function (items, letter) {
        var resulsts = [];
        var itemMatch = new RegExp(letter, 'i');
        for (var i = 0; i < items.length; i++) {
            var item = items[i];
            if ( itemMatch.test(item.name) || itemMatch.test(item.genre)) {
                results.push(item);
            }
        }
        return results;
    };
});

HTML:

<div ng-controller="MoviesCtrl">
    <ul>
        <li ng-repeat="movie in movies | searchMovies:filterByGenres">
            {{ movie.name }} {{ movie.genre }}
        </li>
    </ul>
</div>

1

Berikut adalah contoh saya cara membuat filter dan arahan untuk table jsfiddle

direktif dapatkan daftar (data) dan buat tabel dengan filter

<div ng-app="autoDrops" ng-controller="HomeController">
<div class="row">
    <div class="col-md-12">
        <h1>{{title}}</h1>
        <ng-Multiselect array-List="datas"></ng-Multiselect>
    </div>
</div>
</div>

dengan senang hati jika saya membantu Anda


1

Terlambat untuk bergabung dengan pesta tetapi mungkin bisa membantu seseorang:

Kita bisa melakukannya dalam dua langkah, filter pertama dengan properti pertama dan kemudian digabungkan dengan filter kedua:

$scope.filterd = $filter('filter')($scope.empList, { dept: "account" });
$scope.filterd = $scope.filterd.concat($filter('filter')($scope.empList, { dept: "sales" }));  

Lihat biola yang berfungsi dengan beberapa filter properti


0

OPSI 1: Menggunakan parameter komparator filter yang disediakan Angular

// declaring a comparator method
$scope.filterBy = function(actual, expected) {
    return _.contains(expected, actual); // uses underscore library contains method
};

var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];

// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')(employees, {name: ['a','c']}, $scope.filterBy);

OPSI 2: Menggunakan negasi filter yang disediakan Angular

var employees = [{name: 'a'}, {name: 'b'}, {name: 'c'}, {name: 'd'}];

// filter employees with name matching with either 'a' or 'c'
var filteredEmployees = $filter('filter')($filter('filter')(employees, {name: '!d'}), {name: '!b'});

-3

Solusi saya

ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"

diperiksa pada VS 2015, itu tidak mendapatkan sintaks dan tidak bekerja juga
WholeLifeLearner

-15

jawaban terbaik adalah:

filter:({genres: 'Action', genres: 'Comedy'}

5
Apakah ini bukan hanya filter di 'Komedi'?
user1135469

2
Saya mencoba ini dan hanya memfilter pada 'Komedi', bukan pada 'Aksi'.
Ben
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.