So filtern Sie mehrere Werte (ODER-Verknüpfung) in angleJS

135

Ich möchte den filterWinkel verwenden und nach mehreren Werten filtern. Wenn einer der Werte vorhanden ist, sollte er angezeigt werden.

Ich habe zum Beispiel diese Struktur:

Ein Objekt moviewelches die Eigenschaft , genresund ich möchte Filter für Actionund Comedy.

Ich weiß, dass ich es kann filter:({genres: 'Action'} || {genres: 'Comedy'}), aber was tun, wenn ich es dynamisch filtern möchte? Z.Bfilter: variableX

Wie stelle ich variableXdas ein $scope, wenn ich eine Reihe von Genres habe, die ich filtern muss?

Ich könnte es als String konstruieren und dann einen machen, eval()aber ich möchte eval () nicht verwenden ...

JustGoscha
quelle
16
Bist du sicher, dass das filter:({genres: 'Action'} || {genres: 'Comedy'})überhaupt funktioniert? es geht nicht rein angular 1.3.16.
Twmulloy
4
Gleiches gilt für 1.4.8! es funktioniert einfach nicht ^^
Alex

Antworten:

87

Ich würde nur einen benutzerdefinierten Filter erstellen. Sie sind nicht so schwer.

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

Vorlage:

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

Bearbeiten Sie hier den Link: Erstellen von Winkelfiltern

UPDATE : Hier ist eine Geige , die eine genaue Demo meines Vorschlags enthält.

Xesued
quelle
Also gebe ich im Out die Filmobjekte zurück, die ich anzeigen möchte?
JustGoscha
Es tut mir leid, dass ich eine Weile gebraucht habe, um zurück zu kommen. Ich habe meine Antwort mit einem konkreten Beispiel aktualisiert.
Xesued
ok, danke, in der Zwischenzeit habe ich es selbst herausgefunden, aber es wird sicher später jemandem helfen :)
JustGoscha
Entweder habe ich zwei Werte wie aktiv und inaktiv. Wie kann ich dann mit diesem Filter separat suchen? Wir möchten keinen benutzerdefinierten Filter erstellen.
VjyV
80

Sie können eine Controller-Funktion zum Filtern verwenden.

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
quelle
1
Gibt es neben der Trennung von Bedenken einen Grund (in Bezug auf die Leistung), warum dies vermieden werden würde?
Sean Larkin
1
Javascript-Version, wenn andere danach suchen:$scope.filteredMovies = $filter('filter')($scope.movies, $scope.filterByGenres);
Evan
23

Das Erstellen eines benutzerdefinierten Filters kann hier zu viel des Guten sein. Sie können einfach einen benutzerdefinierten Komparator übergeben, wenn Sie über mehrere Werte verfügen:

$scope.selectedGenres = "Action, Drama"; 

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

dann im Filter:

filter:{name:selectedGenres}:containsComparator
Chrismarx
quelle
1
Hat mir viel geholfen. Vielen Dank
Hristo Enev
@chrismarx Was wäre das ng-modelin der Ansichtsdatei, um mit dem beschriebenen Filter zu verknüpfen? (sorry, das Lernen noch hier) - Ich mag die Einfachheit Ihrer Antwort und versucht , es zu bekommen arbeiten , aber nicht sicher , wie meine beschriften <input>ist ng-model. :)
Twknab
Sie müssen dies lesen - docs.angularjs.org/api/ng/filter/filter
chrismarx
18

Hier ist die Implementierung eines benutzerdefinierten Filters, der die Daten mithilfe eines Array von Werten filtert. Er unterstützt mehrere Schlüsselobjekte mit einem Array und einem einzelnen Wert von Schlüsseln. Wie bereits erwähnt, unterstützt der AngularJS-Filter inangularJS den Mehrfachschlüsselfilter mit einem einzigen Wert. Der unten stehende benutzerdefinierte Filter unterstützt jedoch dieselbe Funktion wie angleJS und unterstützt auch ein Array von Werten und eine Kombination aus Array und Einzelwert von Schlüsseln.

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

Verwendung:

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

Hier ist ein Geigenbeispiel mit der Implementierung des oben genannten benutzerdefinierten Filters "filterMutiple" . ::: Geigenbeispiel :::

Nirmal Kumar VeluPillai
quelle
1
Sie scheinen die richtige Absicht zu haben, aber Ihr Beispiel scheint nicht wie erwartet zu funktionieren. Die Ausgabe in der Tabelle scheint eher inkonsistent zu sein.
Hultner
Dies funktioniert nicht mit JSONs mit verschachtelten Objekten. Wäre ideal gewesen, wenn es so wäre. Außerdem wird ein length property undefinedFehler in der Konsole ausgelöst.
SinSync
Es funktioniert für mich, gibt jedoch alle Ergebnisse zurück, wenn das gesuchte Attribut in der Liste nicht gefunden wird. Wie kann ich dieses Verhalten invertieren und kein Ergebnis zurückgeben, wenn der Wert nicht in der Liste vorhanden ist?
Zakaria Belghiti
@ ZakariaBelghiti Wenn Sie keine Ergebnisse zurückgeben möchten, ändern Sie den Code: if (fData.length > 0){ this.filteredData = fData; } zu nur: this.filteredData = fData;
pconnor88
@Gerfried Ich denke, dass Site tatsächlich Stackoverflow kratzt, also haben sie seine Antwort gestohlen, nicht umgekehrt
Chris
13

Wenn Sie nach einem Array von Objekten filtern möchten, können Sie angeben

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

Einzelne Eigenschaften werden nach bestimmten Filtern gefiltert, die für diese Eigenschaft angegeben wurden.

Wenn Sie jedoch nach einzelnen Eigenschaften filtern und global nach allen Eigenschaften filtern möchten, können Sie so etwas tun.

<tr ng-repeat="supp in $data | filter : filterObject |  filter : search">
Wobei "filterObject" ein Objekt zum Durchsuchen einer einzelnen Eigenschaft ist und "Search" in jeder Eigenschaft global sucht.

~ Atul

user1941574
quelle
Dies funktionierte gut für mich und war eine bessere Lösung als andere, die vorschlugen, die Filterung auf eine Funktion zu verlagern, da AngularJS beim Filtern nach Zeichenfolgen teilweise Textübereinstimmungen durchführt.
Snaver
9

Ich habe einige Zeit damit verbracht und dank @chrismarx habe ich gesehen, dass filterFilterSie mit der Standardeinstellung von Angular Ihren eigenen Komparator übergeben können. Hier ist der bearbeitete Komparator für mehrere Werte:

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

Und wenn wir einen benutzerdefinierten Filter für DRY erstellen möchten:

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

Und dann können wir es überall verwenden, wo wir wollen:

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

Zum Schluss noch ein Plunkr .

Hinweis: Das erwartete Array sollte nur einfache Objekte wie String , Number usw. enthalten.

an alem
quelle
Danke das hat mir geholfen. So suchen Sie nach einem Filter mit einem einzigen WertWithOr: {name: 'Jack'} Wenn jemand dasselbe braucht wie ich ...
Juan
7

Sie können den searchField-Filter von angle.filter verwenden

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
quelle
3
Sie können auch "where" von angle.filter <tr ng-repeat = "obj in collection | where: {id: 1}"> {{obj.name}} </ tr>
hcarreras
1
die searchHaltestellen hier.
Akash
1
Ich habe dies versucht und sowohl das Modul in meiner Winkel-App als auch das Skript in meinem Index-HTML eingerichtet, aber ich kann immer noch nach
ALLEN
7

Sie können auch verwenden, ngIfwenn die Situation dies zulässt:

<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
quelle
1
Schöne und einfache Lösung!
Leopoldo Sanczyk
7

Die schnellste Lösung, die ich gefunden habe, ist die Verwendung des filterByFilters aus dem Winkelfilter , zum Beispiel:

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

Der Vorteil ist , dass Winkel-Filter ist eine ziemlich beliebte Bibliothek (~ 2.6k Sterne auf GitHub) , die immer noch aktiv entwickelt und gepflegt wird , so ist es in Ordnung es zu einem Projekt als Abhängigkeit hinzuzufügen sein sollte.

Priidu Neemre
quelle
1
Mit Abstand die beste Antwort. Vielen Dank.
Daniel Gruszczyk
4

Ich glaube, das ist es, wonach Sie suchen:

<div>{{ (collection | fitler1:args) + (collection | filter2:args) }}</div>
jKlaus
quelle
1
Es verkettet nur die Arrays und gibt keine Union zurück.
Muaaz
Wenn ich die Implementierung nicht falsch verstanden habe, sehe ich nicht, wie das ein Problem ist.
jKlaus
2

Bitte versuchen Sie dies

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

Nehmen wir an, Sie haben zwei Arrays, eines für Filme und eines für Genres

Verwenden Sie den Filter einfach als: filter:{genres: genres.type}

Hier haben Genres als Array und Typ einen Wert für das Genre

Amit Yadav
quelle
1

Ich habe dies für Zeichenfolgen UND Funktionalität geschrieben (ich weiß, dass es nicht die Frage ist, aber ich habe danach gesucht und bin hierher gekommen), vielleicht kann es erweitert werden.

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

Verwendung:

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

Ich hatte eine ähnliche Situation. Das Schreiben eines benutzerdefinierten Filters hat bei mir funktioniert. Hoffe das hilft!

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

Hier ist mein Beispiel, wie Filter und Direktiven für die Tabelle jsfiddle erstellt werden

Direktive Get List (Daten) und erstellen Sie eine Tabelle mit Filtern

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

Es ist mir ein Vergnügen, wenn ich Ihnen helfe

Jasmin Kurtic
quelle
1

Es ist zu spät, um an der Party teilzunehmen, aber vielleicht kann es jemandem helfen:

Wir können dies in zwei Schritten tun: zuerst nach der ersten Eigenschaft filtern und dann nach dem zweiten Filter verketten:

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

Sehen Sie sich die funktionierende Geige mit dem Filter für mehrere Eigenschaften an

Ali Adravi
quelle
0

OPTION 1: Verwenden des von Angular bereitgestellten Filterkomparatorparameters

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

OPTION 2: Verwenden der von Angular bereitgestellten Filternegation

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

Meine Lösung

ng-repeat="movie in movies | filter: {'Action'} + filter: {'Comedy}"
Wilson Di Mateo
quelle
Auf VS 2015 überprüft, bekommt es nicht die Syntax und es funktioniert auch nicht
WholeLifeLearner
-15

Die beste Antwort ist:

filter:({genres: 'Action', genres: 'Comedy'}
Chinaxing
quelle
5
Filtert dies nicht nur nach "Comedy"?
user1135469
2
Ich habe es versucht und es filtert nur nach "Comedy", nicht nach "Action".
Ben