在AngularJS中按多个特定模型属性进行过滤(OR关系)


107

在这里看看示例:http : //docs.angularjs.org/api/ng.filter : filter

您可以使用来按电话的任何属性进行<input ng-model="search">搜索,也可以使用来按名称进行搜索<input ng-model="search.name">,然后按名称对结果进行适当过滤(按预期方式输入电话号码不会返回任何结果)。

比方说,我有一个“名称”属性,“电话”属性,一个“秘密”性质的模型,我怎么会去通过过滤在“名称”和“电话”属性和没有 “秘密”属性?因此,从本质上讲,用户可以键入姓名或电话号码,并且ng-repeat可以正确过滤,但是即使用户键入的值等于“秘密”值的一部分,也不会返回任何内容。

谢谢。


呵呵,对于为什么将“名称”对象附加到输入字段ng-modelsearch.name在INPUT字段中指定ng-model)会导致对象被其name属性重复过滤,我真的感到困惑。对我来说,从直觉上讲,您应该只需name通过在ng-repeat过滤器中指定即可进行特定过滤:filter: friend.name而不是`写`<input ng-model =“ search.name”> ...
LazerSharks

Answers:


171

这是the

新的代码更整洁的代码,查询和搜索列表项都不区分大小写

主要思想是创建一个过滤器功能来实现此目的。

来自官方文件

函数:谓词函数可用于编写任意过滤器。为数组的每个元素调用该函数。最终结果是谓词为其返回true的那些元素的数组。

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

更新资料

有些人可能对现实世界中的性能有所担心,这是正确的。

在现实世界中,我们可能会从控制器中进行这种过滤。

这是显示如何执行此操作的详细信息

简而言之,我们添加ng-change了用于监视新搜索变化的输入

然后触发过滤功能。


1
@maxisam,您好,您能解释两条垂直线是什么意思吗?我不太确定该怎么读:item.brand.indexOf($scope.query)!=-1 || item.model.indexOf($scope.query)!=-1)
LazerSharks 2013年

15
|| 表示“或”。您可能想阅读Javascript的好部分。
maxisam

1
说起||,就尝试了一下,它的工作原理是:<tr ng-repeat =“智能手机中的智能手机|过滤器:电话||名称”>。第一个过滤器优先。
Jazzy

2
@kate angular.lowercase(item.brand).indexOf ...基本上,都是小写字母
maxisam 2014年

1
@maxisam。查询字符串也必须是小写字母,以便不区分大小写以正常工作。这是对工作箱不敏感的朋克叉plnkr.co/edit/auz02bvWm1Vw4eItSa5J?p=preview 感谢您的过滤器。
Leopold Kristjansson

78

您可以按照API参考中的说明将Object作为参数传递给过滤器表达式。该对象可以有选择地应用您感兴趣的属性,如下所示:

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

这是一个笨蛋

请注意...此示例可与AngularJS 1.1.5完美配合,但在1.0.7中并非总是如此。在此示例中,1.0.7将初始化,并过滤掉所有内容,然后在您开始使用输入时开始工作。行为就像输入中包含不匹配的值一样,即使它们开始时是空白。如果要保持稳定的发行版,请继续尝试此操作以解决您的问题,但是在某些情况下,可能需要使用@maxisam的解决方案,直到1.2.0发布为止。


26
如果您只有一个搜索框,那么看着您的朋克者将如何达到预期的效果。这是挑战...“或”部分。
silvster27年

2
这个答案是金,但不能回答这个问题。
Cyril CHAPON 2015年

1
您将如何仅使用一个输入字段(如表中的示例)来做到这一点:datatables.net
Flash

您如何在已发布的Plunker中获得过滤数据的计数?
穆罕默德Zeeshan Tahir

5

我从@maxisam的答案中得到了启发,并创建了自己的排序函数,尽管我会分享它(因为我很无聊)。

情况 我想过滤一系列汽车。选择要过滤的属性是名称,年份,价格和公里。物业价格和km是数字(因此使用.toString)。我也想控制大写字母(因此.toLowerCase)。我还希望能够将过滤器查询分解为不同的词(例如,给定过滤器2006 Acura,它会找到与年份匹配的2006和名称与Acura的匹配项)。

我传递给过滤器的功能

        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
您能否显示在视图侧如何在Angular中调用此过滤器?
twknab



2

这里有很多好的解决方案,但我建议您走另一条路。如果搜索是最重要的事情,并且视图上根本没有使用'secret'属性;我的方法是使用内置的角度滤镜及其所有优点,然后将模型简单地映射到新的对象数组。

问题示例:

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

现在,在html中,只需使用常规过滤器来搜索这两个属性。

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

1
我喜欢这种用于处理小对象的解决方案,但是如果您有大量带有大量嵌套内容的对象,则对所有内容进行映射可能会造成混淆/容易出错。+1虽然是满足基本需求的绝佳解决方案...希望这并不是那么复杂,仅针对少数几个属性(而不是全部)进行过滤!:/ ...也许将来Angular可以为此类过滤器添加一些内置功能...
twknab

2

在angularJs中使用filterBy的非常简单的方法

对于工作的plnkr,请点击此链接

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

这特别使用了单个属性来搜索多列而不是全部。

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

控制者

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

})();

缺点是它增加了一个第三方插件。重要提示。
mix3d

2

我简单地解决了这个问题:

<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

这是区分大小写的搜索,还可以将搜索分为单词以在每个模型中搜索。仅当找到空格时,它才会尝试将查询拆分为一个数组,然后搜索每个单词。

如果每个单词至少在一个模型中,则返回true。

$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

过滤器可以是具有字段的JavaScript对象,并且您可以将表达式表示为:

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

0

我喜欢在可能的情况下保持简单。我需要按国际分组,对所有列进行过滤,显示每个组的计数,如果不存在任何项目,则将其隐藏。

另外,我不想为这样的简单操作添加自定义过滤器。

        <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

我可能已经很晚了,但这就是我最终要做的。我做了一个非常普通的过滤器。

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

    })

然后像这样使用

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

您的搜索框像

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

其中name和device_id是dvs中的属性


-1

对于那些想要快速过滤对象的人来说,这是一个简单的解决方案:

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

数组过滤器使您可以模仿要过滤的对象。在上述情况下,以下类可以正常工作:

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

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

甲板可能看起来像这样:

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

  return {
    Cards: _cards
  };
};

而且,如果您要过滤对象的多个属性,只需用逗号分隔字段名称即可:

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

编辑:这是一个工作的plnkr,它提供了单个和多个属性过滤器的示例:

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


您将如何实施这种搜索?在此示例的表中,您可以键入单词的一部分,按空格键,然后在列中键入另一个单词的一部分,它仍然会进行相应过滤。datatables.net
Flash

除非我没有正确解决问题,否则我不知道为什么我的帖子被降级。您正确应用代码后,该代码才能工作。
瑞克

谢谢您的回信rick我不知道谁投了反对票,但我可以继续投票。但是,在该示例中,它与我提供的链接中的相似之处在于,它们具有搜索输入字段,并且在键入时会过滤掉。她的是我的原始帖子,某人也否决了它: stackoverflow.com/questions/42421941/angular-custom-search
Flash

1
我更新了plnkr,以显示文本框过滤器的工作方式。请注意,它是如何按预期过滤任何部分文本的。我相信这更接近您的链接示例。如果您需要多个过滤器(用于单独的数据块),那就是另一个问题。
里克(Rick)

@Rick我非常感谢您在本示例中投入时间,因为我目前正在试图弄清楚自己仅过滤2个属性,而不是对象中通过via重复的所有属性ng-repeat。但是,您的示例似乎有点复杂:您有什么方法可以将其简化吗?我知道问题本质上是在寻找一个只能过滤所选属性的搜索字段。在您的示例中,看起来我们正在过滤面值名称或数字,但不能同时过滤。如果我不理解您的示例,请告诉我!
twknab
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.