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.
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
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" >
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With