Reputation: 117
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:
There are also 3 new problems once a selection is made:
[Object object]
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
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