AçısalJS'de birden çok değer (VEYA işlemi) nasıl filtrelenir


135

filterAçısal kullanmak istiyorum ve birden çok değer için filtre istiyorum, değerlerden biri varsa o zaman görüntülenmelidir.

Örneğin bu yapıya sahibim:

Bir nesne movieözelliği olan genresve ben filtreye istiyorum Actionve Comedy.

Yapabileceğimi biliyorum filter:({genres: 'Action'} || {genres: 'Comedy'}), ancak dinamik olarak filtrelemek istersem ne yapmalıyım. Örneğinfilter: variableX

Nasıl belirlerim variableXiçinde $scopeben filtreye sahip türler bir dizi varken,?

Ben bir dize olarak inşa ve sonra bir yapabilir eval()ama eval () kullanmak istemiyorum ...


16
filter:({genres: 'Action'} || {genres: 'Comedy'})hatta işe yaradığından emin misin ? içeri girmiyor angular 1.3.16.
twmulloy

4
1.4.8 için aynı! sadece işe yaramaz ^ ^
Alex

Yanıtlar:


87

Sadece özel bir filtre oluştururdum. O kadar da zor değiller.

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

şablonu:

<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>

Burada Düzenle bağlantısı: Açısal Filtreler Oluşturma

GÜNCELLEME : İşte benim önerimin tam bir demosuna sahip bir keman .


o zaman dışarıda göstermek istediğim film nesnelerini döndürürüm?
JustGoscha

Üzgünüm geri dönmem biraz zaman aldı. Cevabımı somut bir örnekle güncelledim.
Xesued

Tamam, teşekkürler, bu arada ben kendim anladım, ama eminim daha sonra birine yardım edecek :)
JustGoscha

Ya böyle aktif ve pasif gibi iki değeri var sonra nasıl bu filtreyi kullanarak ayrı ayrı arama yapabilirsiniz. özel filtre yapmak istemiyoruz.
VjyV

80

Filtrelemek için bir denetleyici işlevi kullanabilirsiniz.

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
Endişelerin ayrılmasının yanı sıra, bunun önlenmesi için herhangi bir neden (performans açısından) var mı?
Sean Larkin

1
diğerleri arıyorsa javascript sürümü:$scope.filteredMovies = $filter('filter')($scope.movies, $scope.filterByGenres);
Evan

23

Burada özel bir filtre oluşturmak aşırıya kaçabilir, sadece aşağıdaki gibi birden çok değeriniz varsa, özel bir karşılaştırıcıyı iletebilirsiniz:

$scope.selectedGenres = "Action, Drama"; 

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

sonra filtrede:

filter:{name:selectedGenres}:containsComparator

1
Bana çok yardım etti. Teşekkürler
Hristo Enev

@chrismarx ng-modelGörünüm dosyasında açıklanan filtreye bağlanmak için ne olurdu ? (özür dilerim, hala burada öğreniyorum) - Cevabınızın basitliğini ve çalışmasını sağlamaya çalışıyorum, ancak benim <input>'lerini nasıl etiketleyeceğimden emin değilim ng-model. :)
twknab


18

Değerler dizisini kullanarak verileri filtreleyecek özel filtrenin uygulanması. Hem dizi hem de tek anahtar değeri ile birden fazla anahtar nesneyi destekleyecektir. Belirtildiği gibi inangularJS API AngularJS filtresi Doc , tek değerli birden fazla anahtar filtresini destekler, ancak özel filtrenin altında, angularJS ile aynı özelliği destekleyecek ve aynı zamanda değerler dizisini ve hem dizi hem de anahtar değerlerinin birleşimini destekleyecektir. Lütfen aşağıdaki kod snippet'ini bulun,

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;
}
}]);

Kullanımı:

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

Yukarıdaki "filterMutiple" özel filtresinin uygulanmasıyla ilgili bir örnek . ::: Keman Örneği :::


1
Doğru niyetiniz var gibi görünüyor, ancak örneğiniz beklendiği gibi çalışmıyor. Tablodaki çıktı oldukça tutarsız görünüyor.
Hultner

Bu iç içe nesnelerle JSON ile çalışmaz. Eğer olsaydı ideal olurdu. ayrıca length property undefinedkonsolda bir hata verir.
SinSync

Benim için çalışıyor, ancak listede aranan özniteliği bulamazsa tüm sonuçları döndürür, bu davranışı tersine çevirmek ve değer listede yoksa hiçbir sonucu döndürmek için nasıl yapabilirim?
Zakaria Belghiti

@ZakariaBelghiti Eğer sonuç döndürmek istemiyorsanız, kodu şu şekilde değiştirin: if (fData.length > 0){ this.filteredData = fData; } sadece: this.filteredData = fData;
pconnor88

@Gerfried Sanırım bu site aslında Stackoverflow'u kazıyor, bu yüzden cevabını çaldılar, başka bir şekilde değil
Chris

13

Nesneler Dizisine filtre uygulamak istiyorsanız,

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

Bireysel mülk, o mülk için verilen belirli bir filtreye göre filtrelenecektir.

Ancak tek tek Mülke göre filtreleme ve tüm mülkler için küresel olarak filtreleme gibi bir şey istiyorsanız, bunun gibi bir şey yapabilirsiniz.

<tr ng-repeat="supp in $data | filter : filterObject |  filter : search">
"FilterObject", tek bir mülkü aramak için bir nesnedir ve "Ara" tüm mülklerde küresel olarak arama yapar.

~ Atul


Bu benim için iyi çalıştı ve diğerlerine göre daha iyi bir çözümdü.
Snaver

9

Üzerinde biraz zaman geçirdim ve @chrismarx sayesinde, açısalın varsayılanının filterFilterkendi karşılaştırıcınızı geçirmenize izin verdiğini gördüm . Birden çok değer için düzenlenen karşılaştırıcı şöyledir:

  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;
    }
  };

DRY için özel bir filtre yapmak istiyorsak:

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);
      };
    });

Ve sonra istediğimiz her yerde kullanabiliriz:

$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>

Sonunda bir plunkr .

Not: Beklenen dizi yalnızca String , Number vb. Gibi basit nesneler içermelidir .


Teşekkürler bu bana yardımcı oldu. Tek bir değer filterWithOr kontrol etmek için: {name: 'Jack'} benimle aynı olursa herkes ihtiyacını ...
Juan

7

Eğer searchField filtreyi kullanabilirsiniz 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
Ayrıca koleksiyonda angular.filter <tr ng-repeat = "obj'in" where "ifadesini de kullanabilirsiniz | where: {id: 1}"> {{obj.name}} </tr>
hcarreras

1
searchBurada durur.
Akash

1
Bunu denedim ve hem açısal uygulamamdaki modülü hem de dizin
HTML'imdeki komut dosyasını ayarladım

7

ngIfDurum izin veriyorsa da kullanabilirsiniz :

<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
Güzel ve basit bir çözüm!
Leopoldo Sanczyk

7

Bulduğum en hızlı çözüm, açısalfilterBy filtreden gelen filtreyi kullanmaktır, örneğin:

<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>

Bunun tersi, açısal filtrenin hala aktif olarak geliştirilen ve sürdürülen oldukça popüler bir kütüphane (GitHub'da ~ 2.6k yıldız) olmasıdır, bu yüzden projenize bağımlılık olarak eklemeniz iyi olacaktır.


1
En iyi cevap. Teşekkürler.
Daniel Gruszczyk

4

Aradığın şey olduğuna inanıyorum:

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

1
Sadece dizileri birleştirir ve birliği döndürmez.
muaaz

Uygulamayı yanlış anlamadığım sürece bunun nasıl bir sorun olduğunu göremiyorum.
jKlaus

2

Lütfen bunu dene

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

Biri film ve biri tür için olmak üzere iki diziniz olduğunu varsayalım

Filtreyi şu şekilde kullanın: filter:{genres: genres.type}

Burada tür ve dizi olan türlerin tür için değeri vardır


1

Bunu dizeler VE işlevsellik için yazdım (bunun soru olmadığını biliyorum, ama aradım ve buraya geldim), belki genişletilebilir.

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;
    });  
  };
});

Kullanımı:

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


1

Benzer bir durum yaşadım. Özel filtre yazmak benim için çalıştı. Bu yardımcı olur umarım!

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

İşte benim örnek nasıl tablo jsfiddle için filtre ve yönerge oluşturmak

yönerge get list (datas) ve filtreli tablo oluşturma

<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>

sana yardım edersem zevk


1

Partiye katılmak için çok geç ama belki birine yardımcı olabilir:

Bunu iki adımda yapabiliriz, ilk önce birinci mülke göre filtreleyin ve sonra ikinci filtreyle birleştirin:

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

Birden fazla özellik filtresi ile çalışan kemanı görün


0

SEÇENEK 1: Açısal sağlanan filtre karşılaştırıcı parametresini kullanma

// 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);

SEÇENEK 2: Açısal sağlanan filtre negatifliğini kullanma

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

Çözümüm

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

VS 2015'te kontrol edildi, sözdizimi almıyor ve ayrıca çalışmıyor
WholeLifeLearner

-15

en iyi cevap:

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

5
Bu sadece 'Komedi'yi filtrelemekle kalmıyor mu?
user1135469

2
Bunu denedim ve sadece 'Komedi' ye filtre ediyor, 'Eylem'e değil.
Ben
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.