Search code examples
angularjsangularjs-directiveangular-strap

AngularStrap typeahead incorrectly searching entire label value


I am encountering a usability problem with AngularStrap Typeahead and wondering if anyone else has experienced this or possibly has a workaround. Any feedback is appreciated, seriously.

The problem can easily be demonstrated from this plunkr, which i JUST created from the AngularStrap documentation and ripped out all the unnecessary stuff, just focusing on the problem at hand.

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

In the icon search box, type: class="fa fa-

And notice that all four icons show up. Now add a "g" to the end and watch it become limted to the gear icon. Why is that? Because the label value in $scope.icons has all share the same prefix for the icons, of course. Now imagine that you have a more complex template, or something that shares much more in common between elements, like this:

Item1: <img src="http://myawesomehost/atmygreatlocation/somewhere/abc.jpg> ABC

Item2: <img src="http://myawesomehost/atmygreatlocation/somewhere/lmnop.jpg> LMNOP

Item3: <img src="http://myawesomehost/atmygreatlocation/somewhere/xyz.jpg> XYZ

Because there are so many common characters here and TypeAhead is matching the entire value, including the urls, virtually ANYTHING you type in will result in a match.

If there is no work around, I have a hard time believing that anyone would be able to use this as end users will always complain that the search results don't match what they are typing.

Any thoughts?

Cheers! Stabby


Solution

  • By default, the bs-typeahead directive will append this filter to your ng-options:

    | filter:$viewValue
    

    It means if any properties in an item contains $viewValue (text that you typed), that item will show up.

    If you want to filter on specific fields e.g. only value not label, you could put a filter in the ng-options directly like this:

    ng-options="icon as icon.label for icon in icons | filter: { value: $viewValue }"
    

    Or an alternative would be pass your custom filter like this:

    <input ... data-filter="myFilter" bs-typeahead />
    

    And put the filtering logic in your custom filter:

    .filter('myFilter', function (filterFilter) {
      return function (items, searchValue) {
        return filterFilter(items, { value: searchValue });
      };
    });
    

    Example Plunker: http://plnkr.co/edit/iX8S8VSTHNAzQftSIFvf?p=preview