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 () ...

JustGoscha
sumber
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.

Xesued
sumber
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>
jlareau
sumber
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
chrismarx
sumber
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
Anda perlu membaca ini - docs.angularjs.org/api/ng/filter/filter
chrismarx
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 :::

Nirmal Kumar VeluPillai
sumber
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

pengguna1941574
sumber
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.

s.alem
sumber
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 -->
a8m
sumber
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>
cyberwombat
sumber
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.

Priidu Neemre
sumber
1
Sejauh ini jawaban terbaik. Terima kasih.
Daniel Gruszczyk
4

Saya yakin inilah yang Anda cari:

<div>{{ (collection | fitler1:args) + (collection | filter2:args) }}</div>
jKlaus
sumber
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;
    }
}]);
rajeshpanwar
sumber
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

Amit Yadav
sumber
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>
Uri
sumber
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>
hari nair
sumber
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

Jasmin Kurtic
sumber
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

Ali Adravi
sumber
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'});
Deepak Acharya
sumber
-3

Solusi saya

ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"
Wilson Di Mateo
sumber
diperiksa pada VS 2015, itu tidak mendapatkan sintaks dan tidak bekerja juga
WholeLifeLearner
-15

jawaban terbaik adalah:

filter:({genres: 'Action', genres: 'Comedy'}
Chinaxing
sumber
5
Apakah ini bukan hanya filter di 'Komedi'?
user1135469
2
Saya mencoba ini dan hanya memfilter pada 'Komedi', bukan pada 'Aksi'.
Ben