фильтровать несколько полей, используя один ввод в AngularJS

У меня есть объект JSON, который выглядит следующим образом

[{
    "id": 1,
    "firstName": "Jennifer",
    "middleName": null,
    "lastName": "Aniston",
    "address": "New York City",
}, {
    "id": 2,
    "firstName": "Angelina",
    "middleName": null,
    "lastName": "Jolie",
    "address": "Beverley Hills",
}, {
    "id": 3,
    "firstName": "Emma",
    "middleName": null,
    "lastName": "Watson",
    "address": "London",
}]

Я заполняю эти данные, используя ng-repeat.

<td ng-repeat="row in list | filter:filterBeauties">
{{row.firstName}} {{row.lastName}}
</td>

Теперь у меня есть поле ввода, которое я хотел бы использовать для фильтрации этих имен. Я хотел бы использовать одно и то же поле ввода для фильтрации firstName, а затем фильтрации lastName и не фильтровать ничего другого (например, адрес).

<input type="text" placeholder="Filter" ng-model="filterBeauties.firstName">

Любая идея, как я могу этого достичь?


person Kuldeep Daftary    schedule 07.01.2014    source источник
comment
(имя и фамилия) или хотите (имя или фамилия)   -  person michael    schedule 07.01.2014
comment
имя и фамилия. Поэтому, если я наберу Дженнифер Энистон в поле ввода, он должен отфильтроваться до Дженнифер Энистон.   -  person Kuldeep Daftary    schedule 07.01.2014
comment
хорошо, я думаю, это можно сделать, только написав собственный фильтр, потому что вам нужно проанализировать входной параметр запроса...   -  person michael    schedule 07.01.2014
comment
Я понимаю, что вы хотите сделать, но с точки зрения архитектуры я бы предложил иметь в вашем представлении firstAndLastName и указать, что ваша модель поиска будет на этом.   -  person Chris Story    schedule 07.01.2014
comment
@ChrisStory, ты имеешь в виду, что я должен изменить бэкэнд?   -  person Kuldeep Daftary    schedule 07.01.2014
comment
Да. Вы явно хотите, чтобы ваше представление делало что-то еще. Вы можете сделать метод для этого, чтобы возвращать вам массив JSON по-разному. Сейчас я работаю над вашим пользовательским фильтром.   -  person Chris Story    schedule 07.01.2014


Ответы (5)


Попробуйте эту скрипту.

По сути, я создал подструктуру для фильтрации в отображаемой структуре данных и фильтрации только по этому свойству (например, «filterTerms»):

HTML:

<div ng-controller="MyCtrl">
   <input type="text" ng-model="search.filterTerms">
   <table border="1">
      <tr ng-repeat="row in list | filter:search">
         <td>{{row.firstName}} {{row.lastName}}</td>
      </tr>
   </table>
</div>

JavaScript:

var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.list = [{
    "id": 1,
    "address": "New York City",
    "firstName": "Jennifer",
    "middleName": null,
    "lastName": "Aniston",
    "filterTerms": {
        "firstName": "Jennifer",
        "middleName": null,
        "lastName": "Aniston",
    }
}, {
    "id": 1,
    "address": "New York City",
    "firstName": "Jennifer",
    "middleName": null,
    "lastName": "Leela",
    "filterTerms": {
        "firstName": "Jennifer",
        "middleName": null,
        "lastName": "Leela",            
    }
}, {
    "id": 2,
    "address": "Beverley Hills",
    "firstName": "Angelina",
    "middleName": null,
    "lastName": "Jolie",
    "filterTerms": {
        "firstName": "Angelina",
        "middleName": null,
        "lastName": "Jolie",            
    }
}, {
    "id": 3,
    "address": "London",
    "firstName": "Emma",
    "middleName": null,
    "lastName": "Watson",
    "filterTerms": {
        "firstName": "Emma",
        "middleName": null,
        "lastName": "Watson",            
    }
}];
}

Вы можете упростить это еще больше для этого случая, поместив все имена в одно поле (см. fiddle здесь):

HTML:

<div ng-controller="MyCtrl">
    <input type="text" ng-model="search.filterTerm" />
    <table border="1">
        <tr ng-repeat="row in list | filter:search">
            <td>{{row.first}} {{row.last}} {{row.address}}</td>
        </tr>
    </table>
</div>

JavaScript:

var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
    $scope.list = [{
        "id": 0, "first": "Jenny", "last": "Sorenson", "address": "123 W. Wallnut St.",
        "filterTerm": "Jenny Sorenson"
    },{
        "id": 0, "first": "Susan", "last": "Hinkle", "address": "456 W. Doorbell Dr.",
        "filterTerm": "Susan Hinkle"
    },{
        "id": 0, "first": "Rachel", "last": "Karlyle", "address": "789 W. Sunset Blvd.",
        "filterTerm": "Rachel Karlyle"
    },{
        "id": 0, "first": "Gwen", "last": "Lippi", "address": "0 W. Silly Cir.",
        "filterTerm": "Gwen Lippi"
    }]
}
person Trevor    schedule 23.04.2014
comment
это как создать index для списка. отличная идея. Благодарю. - person Aakash; 19.08.2016

Учитывая, что у вашего пользователя есть эта форма:

{
  "id": 2,
  "firstName": "Angelina",
  "middleName": null,
  "lastName": "Jolie",
  "address": "Beverley Hills"
}

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

$scope.query = '';

$scope.search = function (user) {
  var query = $scope.query.toLowerCase(),
  fullname = user.firstName.toLowerCase() + ' ' + user.lastName.toLowerCase();

  if (fullname.indexOf(query) != -1) {
    return true;
  }
  return false;
};

Эта функция вернет true, если текущий пользователь удовлетворит ваш запрос, и false, если нет. Внутри функции я рекомендую поместить ваш запрос в строчные буквы, чтобы вам не приходилось иметь дело с прописными буквами, которые ваш пользователь будет вводить при поиске.

Вот HTML:

<input type="text" placeholder="Search" ng-model="query">
<table>
   <tr ng-repeat="user in users | filter:search">
      <td>{{user.firstName}} {{user.lastName}}</td>
   </tr>
</table>

Эта техника будет работать, только если вы попытаетесь найти Angelina Jolie, Angelina, Jolie или даже InA JOLIe (почему бы и нет). Если вы попытаетесь сначала выполнить поиск по фамилии, например Jolie Angelina, это не сработает. Вы можете легко исправить это, создав второе полное имя в своей функции (например, reverseFullname), объединив сначала lastName, а затем firstName и протестировав его так же, как и первую строку полного имени.

person Jean-Baptiste Louazel    schedule 05.04.2015
comment
Вот плункер для вышеуказанного решения https://plnkr.co/edit/eGSMxheRdEUwHzdwRsTu?p=preview ИЛИ попробуйте этот [Plunker][plnkr.co/edit/eGSMxheRdEUwHzdwRsTu?p =предварительный просмотр] - person aabiskar; 31.08.2017

Итак, вот что я сделал, чтобы решить эту проблему.

Я добавил новый элемент в объект json (используя функцию angular.forEach) и фильтруется по нему.

$scope.list = beauties.query(function(response) {
    angular.forEach(response, function(value, key) {
          var fullName = value.firstName + ' ' + value.lastName;
          $scope.list[key].fullName = fullName;
   });
});

код поля ввода:

<input type="text" placeholder="Filter" ng-model="filterBeauties.fullName">

нг-повторить

<td ng-repeat="row in list | filter:filterBeauties">
{{row.firstName}} {{row.lastName}}
</td>
person Kuldeep Daftary    schedule 08.01.2014

Вы можете передать третий аргумент функции фильтра:

$filter('filter')(list, {'firstName':search});

Я бы сделал что-то вроде ниже:

<input type="text" ng-model="search">
<table border="1">
    <tr ng-repeat="row in list | filterBoth:search">
        <td>{{row.firstName}} {{row.lastName}}</td>
    </tr>
</table>

А затем напишите пользовательский фильтр как:

myApp.filter('filterBoth', function($filter) {
  return function(list, search) {
    if (!search) return list;

    var arrSearch = search.split(' '),
        lookup = '',
        result = [];

    arrSearch.forEach(function(item) {
      lookup = $filter('filter')(list, {'firstName': item});console.log(lookup);
      if (lookup.length > 0) result = result.concat(lookup);
    });

    return result;
  };
});

Демонстрация: http://jsfiddle.net/wAp4S/1/

Единственная проблема заключается в том, что вы получите повторяющиеся строки, поскольку вы объединяете два похожих массива, которые можно легко исправить с помощью метода _.uniq underscore.js.

person codef0rmer    schedule 07.01.2014
comment
Привет, jsFiddle, которым вы поделились, на самом деле не работает так, как я хочу. Если вы напишите Jennifer Aniston в поле ввода, это ничего не вернет в результате. - person Kuldeep Daftary; 08.01.2014
comment
Ой. В этом случае вам придется разделить поиск по пробелам, отфильтровать каждое слово отдельно, сгруппировать результат, сделать его уникальным и, наконец, обновить область поиска. Текущая демонстрация достаточно хороша, чтобы вы могли изучить ее в соответствии с вашими ожиданиями. - person codef0rmer; 08.01.2014
comment
Это не работает. Проверьте свой jsfiddle. Если я наберу Ang, я увижу только Angelina, а не Aniston. - person Adam Arold; 22.04.2014
comment
Я не думаю, что «Энг» должен соответствовать «Энистон». Однако «Ан» также НЕ возвращает «Энистон». Похоже, фамилии не фильтруются в скрипке. - person Trevor; 23.04.2014
comment
Это действительно не работает так, как должно. Он также фильтрует адрес, хотя это нежелательное поведение. - person JordyV; 25.08.2015

Попробуйте использовать библиотеку angular-filter вместо написания сложных фильтров. Здесь может помочь фильтр searchField.

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

КОНТРОЛЛЕР

$scope.users = [
  { first_name: 'Sharon', last_name: 'Melendez' },
  { first_name: 'Edmundo', last_name: 'Hepler' },
  { first_name: 'Marsha', last_name: 'Letourneau' }
];

HTML

<input ng-model="search" placeholder="search by full name"/>
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
  {{ user.first_name }} {{ user.last_name }}
</th>
<!-- so now you can search by full name -->

Удачи.

person Aakash    schedule 19.08.2016