Filtrage par de multiples propriétés spécifiques du modèle dans AngularJS (dans ou en relation)

regardez l'exemple ici: http://docs.angularjs.org/api/ng.filter:filter

vous pouvez rechercher par n'importe laquelle des propriétés de téléphone en utilisant <input ng-model="search"> et vous pouvez rechercher par le nom seulement en utilisant <input ng-model="search.name"> , et les résultats sont filtrés de manière appropriée par le nom (taper un numéro de téléphone ne renvoie pas de résultats, comme prévu).

disons que j'ai un modèle avec une propriété "nom", "téléphone" de la propriété, et une propriété "secrète", comment faire pour filtrer par à la fois les propriétés" nom "et" téléphone "et et non la propriété" secrète"? Ainsi, essentiellement, l'utilisateur pourrait taper un nom ou un numéro de téléphone et le ng-repeat filtrerait correctement, mais même si l'utilisateur tapait une valeur qui équivalait à une partie d'une valeur "secrète", il ne retournerait rien.

Merci.

102
demandé sur Talha Awan 2012-11-04 08:36:53

12 réponses

voici le plunker

Nouvelle plunker avec un nettoyant le code et où à la fois la requête et de recherche, les éléments de la liste sont insensibles à la casse

l'idée Principale est de créer une fonction de filtre pour atteindre ce but.

à Partir de officiel doc

fonction: une fonction prédicate peut être utilisée pour écrire des filtres arbitraires. Le la fonction est appelée pour chaque élément du tableau. Le résultat final est un tableau des éléments pour lesquels le prédicat est retourné vrai.

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

mise à Jour

certaines personnes pourraient avoir une préoccupation sur la performance dans le monde réel, ce qui est correct.

dans le monde réel, on ferait probablement ce genre de filtre de controller.

Voici le détail post montrant comment le faire.

en bref, nous ajoutons ng-change à la saisie pour la surveillance de la nouvelle recherche

et puis déclencher la fonction de filtre.

164
répondu maxisam 2017-03-22 15:04:38

vous pouvez passer un objet comme paramètre à votre expression de filtre, comme décrit dans le référence API . Cet objet peut appliquer sélectivement les propriétés qui vous intéressent, comme ceci:

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

voici un Plunker

attention...cet exemple fonctionne très bien avec AngularJS 1.1.5, mais pas toujours aussi bien en 1.0.7. Dans cet exemple 1.0.7 va initialiser avec tout filtré, puis travailler quand vous commencez à utiliser les entrées. Il se comporte comme si les entrées avaient des valeurs non-correspondantes, même si elles commencent vides. Si vous voulez rester sur les versions stables, allez-y et essayez ceci pour votre situation, mais certains scénarios peuvent vouloir utiliser la solution de @maxisam jusqu'à ce que la version 1.2.0 soit libérée.

74
répondu Anson 2013-06-19 14:15:46

je me suis inspiré de la réponse de @maxisam et j'ai créé ma propre fonction de tri et je pensais la partager (parce que je m'ennuie).

Situation Je veux filtrer à travers un tableau de voitures. Les propriétés à filtrer sont le nom, l'année, le prix et le km. Le prix de la propriété et le km sont des nombres (d'où l'utilisation de .toString ). Je veux aussi contrôler les majuscules (d'où .toLowerCase ). Aussi je veux être capable de diviser ma requête de filtre en différents mots (par exemple, étant donné le filtre Acura 2006, il trouve des correspondances 2006 avec l'année et Acura avec le nom).

fonction que je passe au filtre

        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;
    };
5
répondu NicolasMoise 2013-12-20 15:39:07

si vous êtes ouvert à l'utilisation de bibliothèques tierces, 'filtres angulaires' avec une belle collection de filtres peut être utile:

https://github.com/a8m/angular-filter#filterby

collection | filterBy: [prop, nested.prop, etc..]: search
5
répondu Khashayar 2015-08-24 00:07:57

Espère que cette réponse sera aider, Plusieurs de Filtre de la Valeur

et exemple de travail dans ce violon

arrayOfObjectswithKeys | filterMultiple:{key1:['value1','value2','value3',...etc],key2:'value4',key3:[value5,value6,...etc]}
3
répondu Nirmal Kumar VeluPillai 2017-05-23 11:55:06

il y a un tas de bonnes solutions ici, mais je suggère d'aller dans l'autre sens. Si la recherche est la chose la plus importante et la propriété "secrète" n'est pas utilisée sur la vue du tout; mon approche pour cela serait d'utiliser le filtre angulaire intégré avec tous ses avantages et simplement mapper le modèle à un nouveau tableau d'objets.

exemple tiré de la question:

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

maintenant, en html il suffit d'utiliser le filtre régulier pour rechercher à la fois ces propriétés.

<div ng-repeat="member in people | filter: searchString">
2
répondu Siddharth Singh 2016-02-21 00:42:31

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

Voici une recherche sensible à la casse qui sépare également votre recherche en mots à rechercher dans chaque modèle ainsi. Ce n'est que lorsqu'il trouve un espace qu'il essaiera de diviser la requête en un tableau et ensuite de rechercher chaque mot.

Elle renvoie true si chaque mot est au moins dans l'un des modèles.

$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
répondu Tom Quinlan 2015-08-17 09:02:08

Assez simple approche à l'aide de filterBy dans angularJs

pour travailler plnkr suivez ce lien

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

cette méthode a spécialement utilisé une propriété unique pour effectuer une recherche par colonne multiple, mais pas toutes.

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

contrôleur

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

})();
1
répondu CredibleAshok 2017-05-03 07:13:00

j'aime garder est simple quand c'est possible. J'avais besoin de grouper par International, filtrer sur toutes les colonnes, afficher le nombre pour chaque groupe et cacher le groupe si aucun élément n'existait.

Plus Je ne voulais pas ajouter un filtre personnalisé juste pour quelque chose de simple comme ceci.

        <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
répondu Louis Rebolloso 2015-08-10 20:00:48

filtre peut être un objet JavaScript avec des champs et vous pouvez avoir l'expression comme:

ng-repeat= 'item in list | filter :{property:value}'
0
répondu Gholamreza Fathpour 2017-01-17 02:26:25

Voici une solution simple pour ceux qui veulent un filtre rapide contre un objet:

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

le filtre de tableau vous permet d'imiter l'objet que vous essayez de filtrer. Dans le cas ci-dessus, les classes suivantes fonctionneraient très bien:

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

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

et où le pont pourrait ressembler:

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

  return {
    Cards: _cards
  };
};

et si vous voulez filtrer plusieurs propriétés de l'objet, séparez simplement les noms de champs par une virgule:

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

EDIT: Voici un plnkr fonctionnel qui fournit un exemple de filtres de propriétés simples et multiples:

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

0
répondu Rick 2017-02-27 14:31:58

je suis peut-être très tard, mais c'est ce que j'ai fait. J'ai fait un très filtre général.

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

    })

alors utilisez - le comme ceci

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

Votre zone de recherche de l'être comme

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

où nom et device_id sont des propriétés dans dvs

0
répondu Raj Sharma 2018-05-16 10:18:41