Автопредложение результатов поиска с использованием нескольких определенных свойств объекта с использованием ng-модели и фильтра

Вот JS для простого автозаполнения Angular:

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

app.controller('TestCtrl', function($scope) {
    $scope.things = [
        { name: "foo", description: "not just any foo" },
        { name: "bar", description: "a bar, in so many words" },
        { name: "gronk", description: "gronk was a wildcat before he was a patriot" },
        { name: "fleebles", description: "i dunno. fleebles just rolls off the tongue for me" },
        { name: "sepulveda", description: "i think 'sepulveda' is a real word with a real meaning" },
        { name: "crinkle", description: "crinkle, since 2008" }
    ];

    $scope.selected;

    $scope.choose = function(thing) {
        $scope.selected = thing;
        $scope.searchForm.$setPristine();
    }
});

... и html:

<body ng-app="typeAhead" ng-controller="TestCtrl">

    <form name="searchForm" novalidate>
        <input type="text" ng-model="selected">
        <span>{{selected.description}}</span>
    </form>

    <div ng-if="selected">
        <div class="result" ng-repeat="thing in filtered = (things | filter:selected)" ng-click="choose(thing)">{{thing.name}}</div>
    </div>

</body>

Сначала кажется, что это работает, с двумя проблемами при наборе текста:

  1. введите несколько букв, затем очистите все, и в результате появится полный список. Ожидаемое поведение не дало бы результатов, если бы не было текста поиска
  2. поиск опрашивает и вещь.имя, и вещь.описание, что хорошо, но мне нужно, чтобы совпадения имен были приоритетными, а не совпадения описания

Есть также 3 новые задачи после выбора:

  1. Предложения не исчезают
  2. Текстовое поле показывает [Object object]
  3. Модель взорвана, поэтому последующие поиски не работают

Если я изменю ввод ng-model на selected.name, выбор исправит отображение текста, но тогда он будет искать только по имени.

Вот пример: http://plnkr.co/edit/BcyfGnTGW6NFpf9jm7Mq?p=preview

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

Пожалуйста, не предлагайте мне использовать директиву Typeahead UI-Bootstrap; это здорово, но мой пример здесь значительно упрощен по сравнению с потребностями моего реального проекта, а UI-Bootstrap не учитывает некоторые из моих пользовательских потребностей.


person grilchgristle    schedule 30.06.2015    source источник
comment
Проверьте директиву Typeahead из Angular Bootstrap angular-ui.github.io/bootstrap   -  person Dmitri Algazin    schedule 30.06.2015
comment
Дмитрий, я хотел добавить, пожалуйста, не предлагайте тип ui-bootstrap в конце вопроса, но я просто забыл (сейчас исправлю). Мой пример здесь на самом деле сильно упрощен по сравнению с моим настоящим проектом; Typeahead ui-bootstrap не поддерживает некоторые другие пользовательские функции, которые мне нужны.   -  person grilchgristle    schedule 30.06.2015
comment
у вас наконец есть решение? это простая задача Angular, я бы сделал для этого директиву   -  person Dmitri Algazin    schedule 01.07.2015
comment
Не совсем. Я выбрал другой подход, используя, как вы уже догадались, UI-Bootstrap. Он действительно ограничен, но я живу с его ограничениями и использую пользовательские шаблоны результатов. Спасибо.   -  person grilchgristle    schedule 02.07.2015


Ответы (1)


Вы используете поле ввода поиска с переменной $scope.selected в качестве ng-модели (которая на данный момент является строковым литералом), а затем, после вызова функции choose(thing), $scope.selected становится объектом. Вот почему ваш ввод показывает [object Object].

Итак, первое, что нужно сделать, это отделить поле ввода поиска от вашего объекта, в котором вы держите выбранный элемент. Ваша форма поиска получает собственную модель: searchText.

<form name="searchForm" novalidate>
  <input type="text" ng-model="searchText">
  <span>{{selected.description}}</span>
</form>

Следующее — это ваш фильтр. Я обновил ваш ng-repeat до следующего:

<div ng-if="searchText">
  <div class="result" ng-repeat="thing in things | filter: {name: searchText}" ng-click="choose(thing)">
    {{thing.name}}
  </div>
</div>

Для явного поиска только полей имени вы уже могли заметить выбор свойства в filter: {name: searchText}, который, в свою очередь, просто фильтрует свойство имени, соответствующее значению вашего ввода.

Вот plnkr.

ОБНОВЛЕНИЕ в связи с сообщением от grilchgristle 1 июля в 22:09

Итак, я ввел новую переменную isUserSearching, которая верна, когда пользователи изменяют searchText. Когда пользователь выбирает запись, для isUserSearching устанавливается значение false, что затем скрывает результаты поиска. Как только пользователь что-то изменяет в поле поиска, переменная isUserSearching снова становится истинной, и появляются результаты поиска. См. plnkr.co/edit/UE7wFjAztUNFqzXpPEvu?p=preview.

По поводу фильтра: нужно написать свой фильтр, который сортирует ваш массив сначала по названию, а потом по описаниям. См. docs.angularjs.org/api/ng/filter/filter.

person ilmgb    schedule 30.06.2015
comment
Спасибо! Это здорово, но ваш ответ — только часть решения. Я не могу ограничить поиск thing.name, мне просто нужно, чтобы совпадения name имели приоритет над совпадениями description. Кроме того, выбор решения не скрывает результаты поиска. - person grilchgristle; 02.07.2015
comment
@grilchgristle Я удалил свой комментарий и обновил свой ответ. Это, наконец, помогло вам решить вашу проблему? - person ilmgb; 13.07.2015