Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit 9df2912

Browse files
feat(typeahead): Adds 'select on exact'.
1 parent 4af83ad commit 9df2912

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

Diff for: src/typeahead/docs/readme.md

+9-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ The typeahead directives provide several attributes:
2727
* `typeahead-editable` <i class="glyphicon glyphicon-eye-open"></i>
2828
_(Defaults: true)_ :
2929
Should it restrict model values to the ones selected from the popup only ?
30+
31+
* `typeahead-focus-first`
32+
_(Defaults: true)_ :
33+
Should the first match automatically be focused as you type?
3034

3135
* `typeahead-input-formatter` <i class="glyphicon glyphicon-eye-open"></i>
3236
_(Defaults: undefined)_ :
@@ -39,11 +43,15 @@ The typeahead directives provide several attributes:
3943
* `typeahead-min-length` <i class="glyphicon glyphicon-eye-open"></i>
4044
_(Defaults: 1)_ :
4145
Minimal no of characters that needs to be entered before typeahead kicks-in
42-
46+
4347
* `typeahead-on-select($item, $model, $label)`
4448
_(Defaults: null)_ :
4549
A callback executed when a match is selected
4650

51+
* `typeahead-select-on-exact`
52+
_(Defaults: false)_ :
53+
Should it automatically select an item when there is one option that exactly matches the user input?
54+
4755
* `typeahead-template-url` <i class="glyphicon glyphicon-eye-open"></i>
4856
:
4957
Set custom item template
@@ -52,10 +60,6 @@ The typeahead directives provide several attributes:
5260
_(Defaults: 0)_ :
5361
Minimal wait time after last character typed before typeahead kicks-in
5462

55-
* `typeahead-focus-first`
56-
_(Defaults: true)_ :
57-
Should the first match automatically be focused as you type?
58-
5963
* `select-on`blur`
6064
_(Defaults: false)_ :
6165
On blur, select the currently highlighted match

Diff for: src/typeahead/test/typeahead.spec.js

+57
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,63 @@ describe('typeahead tests', function () {
456456
expect(inputEl.val()).toEqual('AL');
457457
});
458458
});
459+
460+
describe('select on exact match', function(){
461+
462+
it('should select on an exact match when set', function () {
463+
464+
$scope.onSelect = jasmine.createSpy('onSelect');
465+
var element = prepareInputEl('<div><input ng-model="result" typeahead-editable="false" typeahead-on-select="onSelect()" typeahead="item for item in source | filter:$viewValue" typeahead-select-on-exact="true"></div>');
466+
var inputEl = findInput(element);
467+
468+
changeInputValueTo(element, 'bar');
469+
470+
expect($scope.result).toEqual('bar');
471+
expect(inputEl.val()).toEqual('bar');
472+
expect(element).toBeClosed();
473+
expect($scope.onSelect).toHaveBeenCalled();
474+
});
475+
476+
it('should not select on an exact match by default', function () {
477+
478+
$scope.onSelect = jasmine.createSpy('onSelect');
479+
var element = prepareInputEl('<div><input ng-model="result" typeahead-editable="false" typeahead-on-select="onSelect()" typeahead="item for item in source | filter:$viewValue"></div>');
480+
var inputEl = findInput(element);
481+
482+
changeInputValueTo(element, 'bar');
483+
484+
expect($scope.result).toBeUndefined();
485+
expect(inputEl.val()).toEqual('bar');
486+
expect($scope.onSelect.calls.any()).toBe(false);
487+
});
488+
489+
it('should not be case sensitive when select on an exact match', function () {
490+
491+
$scope.onSelect = jasmine.createSpy('onSelect');
492+
var element = prepareInputEl('<div><input ng-model="result" typeahead-editable="false" typeahead-on-select="onSelect()" typeahead="item for item in source | filter:$viewValue" typeahead-select-on-exact="true"></div>');
493+
var inputEl = findInput(element);
494+
495+
changeInputValueTo(element, 'BaR');
496+
497+
expect($scope.result).toEqual('bar');
498+
expect(inputEl.val()).toEqual('bar');
499+
expect(element).toBeClosed();
500+
expect($scope.onSelect).toHaveBeenCalled();
501+
});
502+
503+
it('should not auto select when not a match with one potential result left', function () {
504+
505+
$scope.onSelect = jasmine.createSpy('onSelect');
506+
var element = prepareInputEl('<div><input ng-model="result" typeahead-editable="false" typeahead-on-select="onSelect()" typeahead="item for item in source | filter:$viewValue" typeahead-select-on-exact="true"></div>');
507+
var inputEl = findInput(element);
508+
509+
changeInputValueTo(element, 'fo');
510+
511+
expect($scope.result).toBeUndefined();
512+
expect(inputEl.val()).toEqual('fo');
513+
expect($scope.onSelect.calls.any()).toBe(false);
514+
});
515+
});
459516

460517
describe('pop-up interaction', function () {
461518
var element;

Diff for: src/typeahead/typeahead.js

+17
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
6767
var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
6868

6969
var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;
70+
71+
//If input matches an item of the list exactly, select it automatically
72+
var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
7073

7174
//INTERNAL VARIABLES
7275

@@ -128,6 +131,15 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
128131
element.attr('aria-activedescendant', getMatchId(index));
129132
}
130133
});
134+
135+
var inputIsExactMatch = function(inputValue, index) {
136+
137+
if (scope.matches.length > index && inputValue){
138+
return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
139+
}
140+
141+
return false;
142+
};
131143

132144
var getMatchesAsync = function(inputValue) {
133145

@@ -161,6 +173,11 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
161173
recalculatePosition();
162174

163175
element.attr('aria-expanded', true);
176+
177+
//Select the single remaining option if user input matches
178+
if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)){
179+
scope.select(0);
180+
}
164181
} else {
165182
resetMatches();
166183
}

0 commit comments

Comments
 (0)