【问题标题】:Filtering by Multiple Specific Model Properties in AngularJS (in OR relationship)按 AngularJS 中的多个特定模型属性过滤(在 OR 关系中)
【发布时间】:2012-10-24 08:16:34
【问题描述】:

看看这里的例子:http://docs.angularjs.org/api/ng.filter:filter

您可以使用<input ng-model="search"> 按任何电话属性进行搜索,也可以使用<input ng-model="search.name"> 仅按姓名进行搜索,结果会按姓名适当过滤(输入电话号码不会返回任何结果,正如预期的那样)。

假设我有一个具有“name”属性、“phone”属性和“secret”属性的模型,我将如何通过 both“name”和“ phone”属性和不是“秘密”属性?所以本质上,用户可以输入姓名或电话号码,ng-repeat 会正确过滤,但即使用户输入的值等于“秘密”值的一部分,它也不会返回任何内容。

谢谢。

【问题讨论】:

  • 嗯,我真的很困惑为什么将“名称”对象附加到输入字段的 ng-model(在 INPUT 字段的 search.name 中指定 search.name)会导致对象被他们的name 属性重复过滤? IE。对我来说,直观地说,您应该能够通过在 ng-repeat 过滤器中指定 filter: friend.name 来专门过滤 name,而不是写成 `...

标签: angularjs


【解决方案1】:

这里是plunker

New plunker with cleaner code & where both the query and search list items are case insensitive

主要思想是创建一个过滤器函数来实现这个目的。

来自official doc

function:谓词函数可用于编写任意过滤器。 为数组的每个元素调用该函数。最终结果是 谓词返回 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;
};

更新

有些人可能会担心现实世界中的表现,这是正确的。

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

这里是post 的详细信息,展示了如何做到这一点。

简而言之,我们将ng-change添加到输入以监控新的搜索变化

然后触发过滤功能。

【讨论】:

  • 嗨@maxisam,你能解释一下双竖线是什么意思吗?我不太确定如何阅读这一行:item.brand.indexOf($scope.query)!=-1 || item.model.indexOf($scope.query)!=-1)
  • ||表示或。您可能想阅读 Javascript,好的部分。
  • 说到 ||,刚刚试了一下,效果很好:。第一个过滤器优先。
  • @kate angular.lowercase(item.brand).indexOf ... 基本上都是小写
  • @maxisam。查询字符串也需要小写,这样不区分大小写才能正常工作。这是一个不区分大小写的 Fork of you plunkerplnkr.co/edit/auz02bvWm1Vw4eItSa5J?p=preview 感谢过滤器。
【解决方案2】:

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

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

这是Plunker

请注意...这个示例在 AngularJS 1.1.5 中运行良好,但在 1.0.7 中并不总是如此。在此示例中,1.0.7 将初始化所有过滤掉的内容,然后在您开始使用输入时工作。它的行为就像输入中包含不匹配的值,即使它们开始为空白。如果您想继续使用稳定版本,请继续尝试针对您的情况进行此操作,但在某些情况下可能需要在 1.2.0 发布之前使用@maxisam 的解决方案。

【讨论】:

  • 看看你的plunker,如果你只有一个搜索框,如何达到你想要的效果。这是挑战...... OR 部分。
  • 这个答案是黄金,但不能回答问题。
  • 如果只有一个输入字段,如表中的这个例子,你会怎么做:datatables.net
  • 您如何获得已发布 Plunker 中过滤数据的计数?
【解决方案3】:

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

情况 我想过滤一系列汽车。要过滤的选定属性是名称、年份、价格和公里。房产价格和公里数是数字(因此使用.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;
    };

【讨论】:

  • 您能否展示一下,在视图方面,您如何在 Angular 中调用此过滤器?
【解决方案4】:

希望这个答案会有所帮助,Multiple Value Filter

这个fiddle中的工作示例

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

【讨论】:

    【解决方案5】:

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

    <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
    • 我不知道为什么我的帖子被降级,除非我没有正确解决这个问题。当您正确应用代码时,该代码将起作用。
    • 感谢您的回复 rick 我不知道谁投了反对票,但我可以继续投票支持。但是,在该示例中,这与我提供的链接中的链接有何相似之处,其中他们有一个搜索输入字段,并且在他们键入时将其过滤掉。她的帖子是我的原始帖子,也有人投了反对票:stackoverflow.com/questions/42421941/angular-custom-search
    • 我更新了 plnkr 以展示文本框过滤器的工作方式。请注意它如何按预期过滤任何部分文本。我相信这更接近您的链接示例。如果您需要多个过滤器(用于单独的数据片段),那就另当别论了。
    • @Rick 我非常感谢您花时间在这个示例中,因为我目前正试图弄清楚自己只过滤 2 个属性,而不是通过 ng-repeat 重复的对象中的所有属性。但是,您的示例似乎有点复杂:有什么方法可以将其归结为吗?我知道这个问题本质上是在寻找一个只能过滤选定属性的搜索字段。在您的示例中,看起来我们正在过滤面值名称或数字,但不能同时过滤两者。如果我对您的示例的理解有误,请告诉我!
    【解决方案6】:

    我喜欢尽可能保持简单。我需要按国际分组,过滤所有列,显示每个组的计数,如果不存在项目则隐藏组。

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

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

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        如果您愿意使用第三方库,带有一组不错的过滤器的“Angular Filters”可能会很有用:

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

        collection | filterBy: [prop, nested.prop, etc..]: search
        

        【讨论】:

          【解决方案9】:

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

          问题示例:

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

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

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

          【讨论】:

          • 我喜欢这种处理小对象的解决方案,但是如果您有一大组包含大量嵌套内容的对象,映射所有内容可能会令人困惑/容易出错。 +1 虽然对于基本需求的一个很好的解决方案......希望这不是那么复杂,只过滤几个属性而不是全部! :/ ...也许将来 Angular 可以为这种过滤器添加一些内置功能...
          【解决方案10】:

          Filter 可以是一个带有字段的 JavaScript 对象,你可以有如下表达式:

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

          【讨论】:

            【解决方案11】:

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

            【讨论】:

            • 缺点是它增加了一个第三方插件。重要的是要大声疾呼。
            【解决方案12】:

            我可能迟到了,但这就是我最终要做的。我做了一个非常通用的过滤器。

            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 中的属性

            【讨论】:

              【解决方案13】:

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

              <div ng-repeat="Object in List | filter: (FilterObj.FilterProperty1 ? {'ObjectProperty1': FilterObj.FilterProperty1} : '') | filter:(FilterObj.FilterProperty2 ? {'ObjectProperty2': FilterObj.FilterProperty2} : '')">
              

              【讨论】:

                猜你喜欢
                相关资源
                最近更新 更多
                热门标签