grilchgristle
grilchgristle

Reputation: 117

Autosuggest Search results using multiple, specific object properties using ng-model and filter

Here's the JS for a simple, Angular autosuggest:

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

...and the 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>

This seems like it's working at first, with 2 problems while typing:

  1. type some letters, then clear everything, and the full list shows up as results. Expected behavior would have no results if there's no search text
  2. the search is polling both thing.name and thing.description, which is good, but I need it to prioritize name matches over description matches

There are also 3 new problems once a selection is made:

  1. The suggestions don't disappear
  2. The textfield shows [Object object]
  3. The model is blown up, so subsequent searches don't work

If I change the input's ng-model to selected.name, making a choice fixes the text display, but then it's searching on name only.

Here's the plunk: http://plnkr.co/edit/BcyfGnTGW6NFpf9jm7Mq?p=preview

It's obvious to me that there's a lot of power available by piping into a filter, but as far as I can tell they incinerated the documentation and offed the poor schlep who wrote it, so I have no idea what options and approaches are available, either strategic or syntactic.

Please don't suggest that I use UI-Bootstrap's Typeahead directive; it's awesome, but my example here is greatly simplified from the needs of my actual project, and UI-Bootstrap doesn't accommodate some of my custom needs.

Upvotes: 1

Views: 149

Answers (1)

ilmgb
ilmgb

Reputation: 770

You are using your search input field with the $scope.selected variable as the ng-model (which is at this point a string literal) and then, after calling thechoose(thing) function - the $scope.selected becomes an object. This is why your input then shows [object Object].

So the first thing is to decouple the search input field and your object where you hold your selected item. Your search form gets its own model: searchText.

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

The next thing is your filter. I have updated your ng-repeat to the following:

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

To explicitly search only for the name fields you already may have noticed the property selection on the filter: {name: searchText} - which in turn just filters for the name property matching your input's value.

Here's the plnkr.

UPDATE due to the from grilchgristle Jul 1 at 22:09

So then, I have introduced a new variable isUserSearching which is true when the users is changing the searchText. When the user selects an entry, then isUserSearching is set to false - which then, hides the search results. As soon as the user changes something in the search field - the isUserSearching Variable gets set to true again and the search results appears. See plnkr.co/edit/UE7wFjAztUNFqzXpPEvu?p=preview.

Regarding the filter: you need to write your own filter which sorts your array first by the name, and then by descriptions. See docs.angularjs.org/api/ng/filter/filter

Upvotes: 0

Related Questions