Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJs UI typeahead match on leading characters

Tags:

The typeahead functionality in AngularJs UI seems simple and powerful however I have been trying to figure out how to get the matching to be done on the leading characters. For example if I type 'A' in the input box I would like to see all the states that start with 'A" and not all the states that contain an 'A' in the name. I have been looking for a couple of days on this and it seems that Angular has the concept of a custom filter that has a 'comparator'. The docs on this have a simple example that does not show the exact syntax for implementing a comparator.

The html looks like this:

<div>Selected: <span>{{selected}}</span></div>     <div><input type="text" ng-model="selected" typeahead="name for name in states | filter:selected"></div> 

The basic javascript looks like this

angular.module('firstChar', ['ui.bootstrap']);      function TypeaheadCtrl($scope) {         $scope.selected = undefined;         $scope.states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Dakota', 'North Carolina', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'];     } 

I have a plunker here http://plnkr.co/edit/LT6pAnS8asnpFEd5e6Ri

So the challenge in a nutshell is to get the AngularUI typeahead to match only on the leading characters.

Any help or ideas on this would be hugely appreciated.

like image 461
pat capozzi Avatar asked Aug 25 '13 14:08

pat capozzi


2 Answers

At the end of the day your question is not really specific to the typeahead directive but it has more to do with how AngularJS filters work.

Before presenting a working solution please note that the typeahead directive makes heavy use of AngularJS infrastructure ($http, promises) and expression language. So it is important to realize that the states | filter:selected is nothing more that an AngularJS expression.

Having a look at the above expression we need to find a way of filtering an array to return a list of matching items. The only special thing about the typeahead directive is that there is a $viewValue variable representing a value entered by a user in the input box. So we basically just need to filter the states array to return items starting with the $viewValue.

There are many ways of doing this but since you've mentioned the comparator for filters (please note that those were only introduced in 1.1.x version of AngularJS) you would have to define a comparator function that should decide if a given item should be returned in the list of results or not. Such a function could look like follows:

$scope.startsWith = function(state, viewValue) {   return state.substr(0, viewValue.length).toLowerCase() == viewValue.toLowerCase(); }  

Having it defined the usage is very simple:

typeahead="name for name in states | filter:$viewValue:startsWith" 

Here is the working plunk: http://plnkr.co/edit/WWWEwU4oPxvbN84fmAl0?p=preview

like image 150
pkozlowski.opensource Avatar answered Oct 27 '22 04:10

pkozlowski.opensource


Custom filter for get the matching to be done on the leading characters in typehead auto completion box.

(function() {        // Create global filters using angular.filter() only. Never use local filters inside      // controllers/services. This enhances testing and reusability.      function xpTypeaheadFilter() {            return function(items, props) {                var out = [];                            if (angular.isArray(items)) {                  items.forEach(function(item) {                                                          var text = props.toLowerCase();                  var itemLoverCase =item.toLowerCase();                  var substr = itemLoverCase.substr(0, text.length);                                       if (substr === text ) {                                             out.push(item);                                         }                                    });              } else {                // Let the output be the input untouched                out = items;              }              console.log("out lem", out.length);                return out;            };      }        // Pass functions into module methods rather than assigning a callback.      // This helps aid with readability and helps reduced the amount of code "wrapped"      // inside Angular.      angular.module('common')      .filter('xpTypeaheadFilter', xpTypeaheadFilter);  })();
<input type="text" ng-model="vesselName" placeholder="Vessel Name" typeahead="vesselName for vesselName in vesselNames | xpTypeaheadFilter:$viewValue | limitTo:8"  class="form-control form-textbox" >
like image 24
Rejayi CS Avatar answered Oct 27 '22 05:10

Rejayi CS