Фильтрация с помощью нескольких конкретных свойств модели в AngularJS (в отношении OR)

Посмотрите на пример здесь: http://docs.angularjs.org/api/ng.filter:filter

Вы можете выполнить поиск по любому из свойств телефона с помощью <input ng-model="search"> а поиск по просто имени - <input ng-model="search.name">, и результаты соответствующим образом отфильтрованы. по имени (ввод номера телефона не дает никаких результатов, как ожидалось).

Пусть говорят, у меня есть модель со свойством "имя", свойство "телефон", и "секретно" собственности, как бы я идти о фильтрации со стороны как "имя" и "телефон" свойства, и не "секрет" собственность? Таким образом, по сути, пользователь может ввести имя или номер телефона, и ng-repeat будет фильтровать правильно, но даже если пользователь введет значение, равное части "секретного" значения, он ничего не вернет.

Благодарю.

Ответ 1

Вот plunker

Новый плункер с чистым кодом и где оба элемента запроса и списка поиска нечувствительны к регистру

Основная идея - создать функцию фильтрации для достижения этой цели.

От официальный документ

Функция

: функция предиката может использоваться для записи произвольных фильтров. Функция вызывается для каждого элемента массива. Конечным результатом является массив из тех элементов, которые предикат возвратил 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 для ввода новых изменений поиска

а затем запустить функцию фильтра.

Ответ 2

Вы можете передать объект в качестве параметра в выражение фильтра, как описано в Справочном руководстве по API. Этот объект может выборочно применять интересующие вас свойства, например:

<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

Heads up... этот пример отлично работает с AngularJS 1.1.5, но не всегда в 1.0.7. В этом примере 1.0.7 будет инициализироваться всем отфильтрованным, а затем работать, когда вы начнете использовать входы. Он ведет себя так же, как входы имеют несогласованные значения в них, хотя они начинаются с пустого. Если вы хотите оставаться на стабильных выпусках, продолжайте и попробуйте это для своей ситуации, но некоторые сценарии могут захотеть использовать решение @maxisam до выпуска 1.2.0.

Ответ 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;
    };

Ответ 4

Если вы открыты для использования сторонних библиотек, "Angular Filters" с хорошим набором фильтров могут быть полезны:

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

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

Ответ 6

Здесь есть множество хороших решений, но я бы предложил пойти на другой маршрут с этим. Если поиск является самым важным, и секретное свойство вообще не используется в представлении; мой подход для этого заключается в использовании встроенного фильтра angular со всеми его преимуществами и просто сопоставления модели с новым массивом объектов.

Пример из вопроса:

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

Теперь в html просто используйте регулярный фильтр для поиска обоих этих свойств.

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

Ответ 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

Довольно прямой подход с использованием filterBy в angularJs

Для работы plnkr выполните следующую ссылку

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

Это специально использовало одно свойство для поиска по нескольким столбцам, но не для всех.

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="[email protected]" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
    <script data-require="[email protected]" 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'
      }
      ];
  })

})();

Ответ 9

Здесь простое решение для тех, кто хочет быстрый фильтр против объекта:

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

EDIT: Здесь работает plnkr, который предоставляет пример одиночных и множественных фильтров свойств:

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

Ответ 10

Мне нравится держать, когда это возможно. Мне нужно было группировать International, фильтровать по всем столбцам, отображать счетчик для каждой группы и скрывать группу, если не было элементов.

Плюс я не хотел добавлять настраиваемый фильтр только для чего-то простого.

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

Ответ 11

Фильтр может быть объектом JavaScript с полями, и вы можете иметь выражение как:

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

Ответ 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} : '')">