Filtern nach mehreren spezifischen Modelleigenschaften in AngularJS (in ODER-Beziehung)


107

Schauen Sie sich das Beispiel hier an: http://docs.angularjs.org/api/ng.filter:filter

Sie können nach einer der Telefoneigenschaften <input ng-model="search">suchen, indem Sie verwenden , und Sie können nur nach dem Namen suchen, indem Sie verwenden. <input ng-model="search.name">Die Ergebnisse werden entsprechend nach Namen gefiltert (wenn Sie eine Telefonnummer eingeben, werden erwartungsgemäß keine Ergebnisse zurückgegeben).

Lassen Sie uns sagen , dass ich ein Modell mit einem „Namen“ Eigenschaft haben, ein „Telefon“ Eigenschaft und ein „Geheimnis“ Eigenschaft, wie würde ich mich über das Filtern von sowohl der „Name“ und „Telefon“ Eigenschaften und nicht das „Geheimnis“ Eigenschaft ? Im Wesentlichen kann der Benutzer also einen Namen oder eine Telefonnummer eingeben und dieng-repeat würde korrekt filtern, aber selbst wenn der Benutzer einen Wert eingibt, der einem Teil eines "geheimen" Werts entspricht, wird nichts zurückgegeben.

Vielen Dank.


Huh, ich bin wirklich verwirrt darüber, warum das Anhängen eines "Namen" -Objekts an die Eingabefelder ng-model( search.namein den INPUT-Feldern angegeben ng-model) dazu führen würde, dass die zu wiederholenden Objekte nach ihrer nameEigenschaft gefiltert werden . Das heißt, intuitiv für mich, sollten Sie in der Lage sein, spezifisch zu filtern, indem Sie einfach namein Ihrem ng-repeatFilter filter: friend.nameangeben : anstatt "zu schreiben" <input ng-model = "search.name"> ...
LazerSharks

Antworten:


171

Hier ist der Plunker

Neuer Plunker mit sauberem Code und bei dem sowohl die Abfrage- als auch die Suchlistenelemente die Groß- und Kleinschreibung nicht berücksichtigen

Die Hauptidee besteht darin, eine Filterfunktion zu erstellen, um diesen Zweck zu erreichen.

Aus dem offiziellen Dokument

Funktion: Mit einer Prädikatfunktion können beliebige Filter geschrieben werden. Die Funktion wird für jedes Element des Arrays aufgerufen. Das Endergebnis ist ein Array der Elemente, für die das Prädikat true zurückgegeben hat.

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

Aktualisieren

Einige Leute haben möglicherweise Bedenken hinsichtlich der Leistung in der realen Welt, was richtig ist.

In der realen Welt würden wir diesen Filter wahrscheinlich vom Controller aus ausführen.

Hier ist das Detail Post zeigt , wie es geht.

Kurz gesagt, wir fügen hinzu ng-change Eingaben zur Überwachung neuer Suchänderungen hinzu

und dann Filterfunktion auslösen.


1
Hallo @maxisam, kannst du erklären, was die doppelten vertikalen Linien bedeuten? Ich bin mir nicht sicher, wie ich diese Zeile lesen soll:item.brand.indexOf($scope.query)!=-1 || item.model.indexOf($scope.query)!=-1)
LazerSharks

15
|| bedeutet ODER. Vielleicht möchten Sie Javascript lesen, die guten Teile.
Maxisam

1
Apropos ||, habe es gerade versucht und es funktioniert: <tr ng-repeat = "Smartphone in Smartphones | Filter: Telefon || Name">. Der erste Filter hat Vorrang.
Jazzy

2
@ Kate Angular.Lowercase (item.brand) .indexOf ... im Grunde nur Kleinbuchstaben alles
Maxisam

1
@ Maxisam. Die Abfragezeichenfolge muss ebenfalls klein geschrieben sein, damit die Groß- und Kleinschreibung nicht richtig funktioniert. Hier ist eine Gabel von Ihnen Plunker mit Arbeitsunempfindlichkeit. plnkr.co/edit/auz02bvWm1Vw4eItSa5J?p=preview Vielen Dank für den Filter.
Leopold Kristjansson

78

Sie können ein Objekt als Parameter an Ihren Filterausdruck übergeben, wie in der API-Referenz beschrieben . Dieses Objekt kann die Eigenschaften, an denen Sie interessiert sind, selektiv anwenden, z.

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

Hier ist ein Plunker

Heads up ... dieses Beispiel funktioniert hervorragend mit AngularJS 1.1.5, aber nicht immer so gut in 1.0.7. In diesem Beispiel wird 1.0.7 mit allem herausgefiltert initialisiert und funktioniert dann, wenn Sie die Eingaben verwenden. Es verhält sich so, als ob die Eingaben nicht übereinstimmende Werte enthalten, obwohl sie leer beginnen. Wenn Sie auf stabilen Releases bleiben möchten, probieren Sie dies für Ihre Situation aus. In einigen Szenarien möchten Sie jedoch möglicherweise die Lösung von @ maxisam verwenden, bis 1.2.0 veröffentlicht wird.


26
Wenn Sie sich Ihren Plunker ansehen, wie würde der gewünschte Effekt erzielt, wenn Sie nur ein Suchfeld hätten. Dies ist die Herausforderung ... der OP-Teil.
silvster27

2
Diese Antwort ist Gold, beantwortet aber die Frage einfach nicht.
Cyril CHAPON

1
Wie würden Sie es mit nur einem Eingabefeld machen, wie in diesem Beispiel in der Tabelle: datatables.net
Flash

Wie würden Sie die gefilterten Daten im veröffentlichten Plunker zählen?
Muhammad Zeeshan Tahir

5

Ich habe mich von der Antwort von @ maxisam inspiriert und meine eigene Sortierfunktion erstellt, und ich würde sie gerne teilen (weil mir langweilig ist).

Situation Ich möchte durch eine Reihe von Autos filtern. Die ausgewählten zu filternden Eigenschaften sind Name, Jahr, Preis und km. Der Immobilienpreis und km sind Zahlen (daher die Verwendung von .toString). Ich möchte auch für Großbuchstaben steuern (daher.toLowerCase ) . Außerdem möchte ich meine Filterabfrage in verschiedene Wörter aufteilen können (z. B. findet der Filter 2006 Acura Übereinstimmungen 2006 mit dem Jahr und Acura mit dem Namen).

Funktion übergebe ich an Filter

        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
Können Sie zeigen, wie Sie diesen Filter auf der Ansichtsseite in Angular aufrufen?
Twknab



2

Hier gibt es eine Reihe guter Lösungen, aber ich würde vorschlagen, damit den anderen Weg zu gehen. Wenn die Suche das Wichtigste ist und die "geheime" Eigenschaft in der Ansicht überhaupt nicht verwendet wird; Mein Ansatz hierfür wäre, den eingebauten Winkelfilter mit all seinen Vorteilen zu verwenden und das Modell einfach einem neuen Array von Objekten zuzuordnen.

Beispiel aus der Frage:

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

Verwenden Sie jetzt in HTML einfach den regulären Filter, um diese beiden Eigenschaften zu durchsuchen.

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

1
Ich mag diese Lösung für den Umgang mit kleinen Objekten, aber wenn Sie eine große Menge von Objekten mit vielen verschachtelten Dingen haben, kann die Zuordnung alles verwirrend / leicht fehleranfällig sein. +1 für eine großartige Lösung für Grundbedürfnisse ... wünschte, dies wäre nicht so kompliziert, nur nach wenigen Eigenschaften anstatt nach allen zu filtern! : / ... vielleicht könnte Angular in Zukunft einige eingebaute Funktionen für Filter dieser Art hinzufügen ...
twknab

2

Ziemlich einfacher Ansatz mit filterBy in eckigen Js

Für die Arbeit plnkr folgen Sie diesem Link

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

Dies hat speziell eine einzelne Eigenschaft verwendet, um nach mehreren Spalten zu suchen, aber nicht nach allen.

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

Regler

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

})();

Nachteil ist, dass ein weiteres Plugin von Drittanbietern hinzugefügt wird. Wichtig zu rufen.
mix3d

2

Ich habe das einfach gelöst:

<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

Hier ist eine Suche mit Groß- und Kleinschreibung, bei der Ihre Suche auch in Wörter unterteilt wird, die auch in jedem Modell gesucht werden sollen. Erst wenn ein Leerzeichen gefunden wird, wird versucht, die Abfrage in ein Array aufzuteilen und dann jedes Wort zu durchsuchen.

Es gibt true zurück, wenn jedes Wort mindestens in einem der Modelle enthalten ist.

$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

Filter kann ein JavaScript-Objekt mit Feldern sein und Sie können folgenden Ausdruck haben:

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

0

Ich mag es einfach zu halten, wenn es möglich ist. Ich musste nach International gruppieren, nach allen Spalten filtern, die Anzahl für jede Gruppe anzeigen und die Gruppe ausblenden, wenn keine Elemente vorhanden waren.

Außerdem wollte ich keinen benutzerdefinierten Filter nur für so etwas Einfaches hinzufügen.

        <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

Ich bin vielleicht sehr spät dran, aber das habe ich letztendlich getan. Ich habe einen sehr allgemeinen Filter gemacht.

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

    })

Dann benutze es so

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

Ihr Suchfeld ist wie

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

Dabei sind Name und Geräte-ID Eigenschaften in DVDs


-1

Hier ist eine einfache Lösung für diejenigen, die einen schnellen Filter für ein Objekt wünschen:

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

Mit dem Array-Filter können Sie das Objekt nachahmen, das Sie filtern möchten. Im obigen Fall würden die folgenden Klassen gut funktionieren:

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

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

Und wo das Deck aussehen könnte:

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

  return {
    Cards: _cards
  };
};

Wenn Sie mehrere Eigenschaften des Objekts filtern möchten, trennen Sie die Feldnamen einfach durch ein Komma:

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

BEARBEITEN: Hier ist ein funktionierendes plnkr, das ein Beispiel für einzelne und mehrere Eigenschaftsfilter bietet:

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


Wie würden Sie diese Art der Suche implementieren? In diesem Beispiel in ihrer Tabelle können Sie einen Teil eines Wortes eingeben, die Leertaste drücken und einen Teil eines anderen Wortes in eine Spalte eingeben, und es wird weiterhin entsprechend gefiltert. datatables.net
Flash

Ich weiß nicht, warum mein Beitrag herabgestuft wurde, es sei denn, ich habe die Frage nicht richtig beantwortet. Der Code funktioniert, wenn Sie ihn richtig anwenden.
Rick

danke für deine antwort rick ich weiß nicht wer abgewählt hat aber ich kann weitermachen und es wieder abstimmen. Wie ist das in diesem Beispiel jedoch ähnlich dem in dem Link, den ich bereitgestellt habe, wo sie ein Sucheingabefeld haben und während sie es eingeben, herausfiltern. Ihr ursprünglicher Beitrag war jemand, der ihn ebenfalls abgelehnt hatte: stackoverflow.com/questions/42421941/angular-custom-search
Flash

1
Ich habe das plnkr aktualisiert, um zu zeigen, wie ein Textfeldfilter funktionieren könnte. Beachten Sie, wie erwartungsgemäß nach Teiltext gefiltert wird. Ich glaube, das kommt Ihrem verknüpften Beispiel näher. Wenn Sie mehrere Filter benötigen (für separate Daten), ist dies eine andere Frage.
Rick

@Rick Ich schätze es sehr, dass Sie sich Zeit für dieses Beispiel nehmen, da ich gerade versuche, herauszufinden, dass nur 2 Eigenschaften gefiltert werden und nicht alle Eigenschaften innerhalb eines Objekts, über die wiederholt wird ng-repeat. Ihr Beispiel scheint jedoch etwas kompliziert zu sein: Gibt es eine Möglichkeit, es zu reduzieren? Ich weiß, dass die Frage im Wesentlichen nach einem einzelnen Suchfeld sucht, das nur nach ausgewählten Eigenschaften filtern kann. In Ihrem Beispiel wird anscheinend entweder nach Nennwertnamen oder nach Zahlen gefiltert, aber nicht nach beiden. Wenn ich Ihr Beispiel nicht richtig verstehe, lassen Sie es mich bitte wissen!
Twknab
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.