Фильтровать по нескольким столбцам с помощью ng-repeat

Мне интересно, есть ли простой способ в Angular для фильтрации таблицы с использованием ng-repeat в определенных столбцах с использованием логики or, а не and. Прямо сейчас мой фильтр ищет все в таблице (10 + столбцы данных), когда ему действительно нужно только фильтровать по 2 столбцам данных (ID и Name).

Мне удалось получить его, чтобы посмотреть только на те 2 столбца при фильтрации (с помощью объекта в выражении фильтра в соответствии с документами и посмотрев этот ответ SO), но он использует логику and, которая слишком специфична. Я бы хотел, чтобы он использовал логику or, но у меня проблемы.

Мой HTML

<input type="text" ng-model="filterText" />
<table>
      <tr ng-repeat="item in data"><td>{{ item.id }}</td><td>{{ item.name }}</td>...</tr>
</table>

Моя логика фильтра:

$filter('filter')(data, {id:$scope.filterText, name:$scope.filterText})

Фильтрация работает, но опять же, она пересекает совпадающие столбцы, а не объединение. Спасибо!

Ответы

Ответ 1

Я понял это - мне пришлось написать собственный собственный фильтр. Вот мое решение:

var filteredData;

filteredData = $filter('filter')(data, function(data) {
  if ($scope.filter) {
    return data.id.toString().indexOf($scope.filter) > -1 || data.name.toString().indexOf($scope.filter) > -1;
  } else {
    return true;
  }
});

Ответ 2

Не сложно создать настраиваемый фильтр, который позволит вам иметь столько аргументов, сколько захотите. Ниже приведен пример фильтра с одним и двумя аргументами, но вы можете добавить столько, сколько вам нужно.

Пример JS:

var app = angular.module('myApp',[]);
app.filter('myTableFilter', function(){
  // Just add arguments to your HTML separated by :
  // And add them as parameters here, for example:
  // return function(dataArray, searchTerm, argumentTwo, argumentThree) {
  return function(dataArray, searchTerm) {
      // If no array is given, exit.
      if (!dataArray) {
          return;
      }
      // If no search term exists, return the array unfiltered.
      else if (!searchTerm) {
          return dataArray;
      }
      // Otherwise, continue.
      else {
           // Convert filter text to lower case.
           var term = searchTerm.toLowerCase();
           // Return the array and filter it by looking for any occurrences of the search term in each items id or name. 
           return dataArray.filter(function(item){
              var termInId = item.id.toLowerCase().indexOf(term) > -1;
              var termInName = item.name.toLowerCase().indexOf(term) > -1;
              return termInId || termInName;
           });
      } 
  }    
});

Затем в вашем HTML:

<tr ng-repeat="item in data | myTableFilter:filterText">

Или если вы хотите использовать несколько аргументов:

<tr ng-repeat="item in data | myTableFilter:filterText:argumentTwo:argumentThree">

Ответ 3

Используйте это для поиска по всем столбцам (может быть медленным): поиск. $ AngularJS API: фильтр

Any Column Search:
<input ng-model="search.$"> 
<table>
<tr ng-repeat="friendObj in friends | filter:search:strict">
...

Ответ 4

Чтобы расширить отличный ответ от @charlietfl, здесь настраивается фильтр, который фильтрует один столбец (свойство), который динамически передается функции, а не жестко закодирован. Это позволит вам использовать фильтр в разных таблицах.

var app=angular.module('myApp',[]);        
app.filter('filterByProperty', function () {
        /* array is first argument, each addiitonal argument is prefixed by a ":" in filter markup*/
        return function (dataArray, searchTerm, propertyName) {
            if (!dataArray) return;
            /* when term is cleared, return full array*/
            if (!searchTerm) {
                return dataArray
            } else {
                /* otherwise filter the array */
                var term = searchTerm.toLowerCase();
                return dataArray.filter(function (item) {
                    return item[propertyName].toLowerCase().indexOf(term) > -1;
                });
            }
        }
    });

Теперь на стороне разметки

<input type="text" ng-model="filterText" />

<table>
  <tr ng-repeat="item in data |filterByProperty:filterText:'name'"><td>{{ item.id }}</td><td>{{ item.name }}</td>...</tr>
</table>

Ответ 5

Я создал этот фильтр для выполнения поиска в нескольких полях:

var find = function () {
    return function (items,array) {
        var model  = array.model;
        var fields = array.fields;
        var clearOnEmpty = array.clearOnEmpty || false;
        var filtered = [];

        var inFields = function(row,query) {
            var finded = false;
            for ( var i in fields ) {
                var field = row[fields[i]];
                if ( field != undefined ) {
                    finded = angular.lowercase(row[fields[i]]).indexOf(query || '') !== -1;
                }
                if ( finded ) break;
            }
            return finded;
        };

        if ( clearOnEmpty && model == "" ) return filtered;

        for (var i in items) {
            var row = items[i];                
            var query = angular.lowercase(model);

            if (query.indexOf(" ") > 0) {
                var query_array = query.split(" ");
                var x;
                for (x in query_array) {
                    query = query_array[x];
                    var search_result = true;
                    if ( !inFields(row,query) ) {
                        search_result = false;
                        break;
                    }
                }
            } else {
                search_result = inFields(row,query);
            }                
            if ( search_result ) {
                filtered.push(row);
            }
        }
        return filtered;
    };
};   

Как использовать:

<tr repeat="item in colletion
                    | find: {
                        model : model, // Input model
                        fields : [     // Array of fields to filter
                            'FIELD1',
                            'FIELD2',
                            'FIELD3'
                        ],
                        clearOnEmpty: true // Clear rows on empty model (not obligatory)
                    } "></tr>

Ответ 6

Легко Мы можем сделать этот тип После написания кода в соответствии с этим вы легко создадите еще один фильтр поля....

var myApp = angular.module('myApp',[]);

myApp.filter('myfilter',myfilter);

function myfilter(){
   return function (items, filters) {
        
        if (filters == null) {
            return items;
        }

        var filtered = [];
        //Apply filter
        angular.forEach(items, function (item) { 
            if ((filters.Name == '' || angular.lowercase(item.Name).indexOf(angular.lowercase(filters.Name)) >= 0) 
               )
            {
                filtered.push(item);
            }

        });
        return filtered;
    };
}

myApp.controller('mycontroller',['$scope',function($scope){
  $scope.filters={Name:'',MathsMarks:''};
  $scope.students=[];
  var i=0;
  for(i=0;i<5;i++){
    var item={Name:'',Marks:[]};
  
    item.Name='student' + i;  
    item.Marks.push({Maths:50-i,Science:50 +i});
    
    $scope.students.push(item);
  }

}]);
<html ng-app='myApp'>
  <head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
</head>
  <body ng-controller='mycontroller'>
    <input type='text' name='studentName' ng-model="filters.Name" placeholder='Enter Student Name'>
    <div ng-repeat="student in students | myfilter: filters">
      Name : {{student.Name}} Marks == >
      <span ng-repeat="m in student.Marks">Maths:{{m.Maths}} Science:{{m.Science}}</span>
      </div>
  </body>
</html>

Ответ 7

Вот мое решение, это очень лениво, он будет искать по всем строкам в массиве на первом уровне, вы можете обновить это, чтобы вкрадце пойти по дереву, но это должно быть достаточно хорошо...

app.filter('filterAll', function () {

    return function (dataArray, searchTerm, propertyNames) {
        if (!dataArray) return;    

        if (!searchTerm) {
            return dataArray;
        } else {



            if (propertyNames == undefined) {
                propertyNames = [];

                for (var property in dataArray[0]) {
                    if(typeof dataArray[0][property] == "string" && 
                        property != "$$hashKey" && 
                        property != "UnitName" )
                        propertyNames.push(property);
                }
            }

            console.log("propertyNames", propertyNames);

            var term = searchTerm.toLowerCase();
            return dataArray.filter(function (item) {
                var found = false;
                propertyNames.forEach(function(val) {
                    if (!found) {
                        if (item[val] != null && item[val].toLowerCase().indexOf(term) > -1)
                            found = true;
                    } 
                });
                return found;
            });
        }
    }
});