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

Commit 167cfad

Browse files
chenyuzhcywesleycho
authored andcommitted
feat(typeahead): add 'is-open' support
- Adds support for checking the toggled state of the dropdown Closes #4760 Closes #4779
1 parent a8624e0 commit 167cfad

File tree

3 files changed

+91
-4
lines changed

3 files changed

+91
-4
lines changed

src/typeahead/docs/readme.md

+4
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,7 @@ The typeahead directives provide several attributes:
7878
* `typeahead-focus-on-select`
7979
_(Defaults: true) :
8080
On selection, focus the input element the typeahead directive is associated with
81+
82+
* `typeahead-is-open` <i class="glyphicon glyphicon-eye-open"></i>
83+
_(Defaults: angular.noop)_ :
84+
Binding to a variable that indicates if dropdown is open

src/typeahead/test/typeahead.spec.js

+72
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,78 @@ describe('typeahead tests', function() {
588588
});
589589
});
590590

591+
describe('is-open indicator', function () {
592+
var element;
593+
594+
beforeEach(function () {
595+
element = prepareInputEl('<div><input ng-model="result" uib-typeahead="item for item in source | filter:$viewValue" typeahead-is-open="isOpen"></div>');
596+
});
597+
598+
it('should bind is-open indicator as true when matches are returned', function () {
599+
expect($scope.isOpen).toBeFalsy();
600+
changeInputValueTo(element, 'b');
601+
expect($scope.isOpen).toBeTruthy();
602+
});
603+
604+
it('should bind is-open indicator as false when no matches returned', function () {
605+
expect($scope.isOpen).toBeFalsy();
606+
changeInputValueTo(element, 'b');
607+
expect($scope.isOpen).toBeTruthy();
608+
changeInputValueTo(element, 'not match');
609+
expect($scope.isOpen).toBeFalsy();
610+
});
611+
612+
it('should bind is-open indicator as false when a match is clicked', function () {
613+
expect($scope.isOpen).toBeFalsy();
614+
changeInputValueTo(element, 'b');
615+
expect($scope.isOpen).toBeTruthy();
616+
var match = findMatches(element).find('a').eq(0);
617+
618+
match.click();
619+
$scope.$digest();
620+
expect($scope.isOpen).toBeFalsy();
621+
});
622+
it('should bind is-open indicator as false when click outside', function () {
623+
expect($scope.isOpen).toBeFalsy();
624+
changeInputValueTo(element, 'b');
625+
expect($scope.isOpen).toBeTruthy();
626+
$document.find('body').click();
627+
$scope.$digest();
628+
expect($scope.isOpen).toBeFalsy();
629+
});
630+
631+
it('should bind is-open indicator as false on enter', function () {
632+
expect($scope.isOpen).toBeFalsy();
633+
changeInputValueTo(element, 'b');
634+
expect($scope.isOpen).toBeTruthy();
635+
triggerKeyDown(element, 13);
636+
expect($scope.isOpen).toBeFalsy();
637+
});
638+
639+
it('should bind is-open indicator as false on tab', function () {
640+
expect($scope.isOpen).toBeFalsy();
641+
changeInputValueTo(element, 'b');
642+
expect($scope.isOpen).toBeTruthy();
643+
triggerKeyDown(element, 9);
644+
expect($scope.isOpen).toBeFalsy();
645+
});
646+
647+
it('should bind is-open indicator as false on escape key', function () {
648+
expect($scope.isOpen).toBeFalsy();
649+
changeInputValueTo(element, 'b');
650+
expect($scope.isOpen).toBeTruthy();
651+
triggerKeyDown(element, 27);
652+
expect($scope.isOpen).toBeFalsy();
653+
});
654+
655+
it('should bind is-open indicator as false input value smaller than a defined threshold', function () {
656+
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="item for item in source | filter:$viewValue" typeahead-is-open="isToggled" typeahead-min-length="2"></div>');
657+
expect($scope.isToggled).toBeFalsy();
658+
changeInputValueTo(element, 'b');
659+
expect($scope.isToggled).toBeFalsy();
660+
});
661+
});
662+
591663
describe('pop-up interaction', function() {
592664
var element;
593665

src/typeahead/typeahead.js

+15-4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
6868
//If input matches an item of the list exactly, select it automatically
6969
var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;
7070

71+
//binding to a variable that indicates if dropdown is open
72+
var isOpenSetter = $parse(attrs.typeaheadIsOpen).assign || angular.noop;
73+
7174
//INTERNAL VARIABLES
7275

7376
//model setter executed upon match selection
@@ -117,7 +120,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
117120
select: 'select(activeIdx)',
118121
'move-in-progress': 'moveInProgress',
119122
query: 'query',
120-
position: 'position'
123+
position: 'position',
124+
'assign-is-open': 'assignIsOpen(isOpen)'
121125
});
122126
//custom item template
123127
if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
@@ -268,6 +272,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
268272

269273
resetMatches();
270274

275+
scope.assignIsOpen = function (isOpen) {
276+
isOpenSetter(originalScope, isOpen);
277+
};
278+
271279
scope.select = function(activeIdx) {
272280
//called from within the $digest() cycle
273281
var locals = {};
@@ -463,7 +471,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
463471
active: '=',
464472
position: '&',
465473
moveInProgress: '=',
466-
select: '&'
474+
select: '&',
475+
assignIsOpen: '&',
467476
},
468477
replace: true,
469478
templateUrl: function(element, attrs) {
@@ -472,8 +481,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
472481
link: function(scope, element, attrs) {
473482
scope.templateUrl = attrs.templateUrl;
474483

475-
scope.isOpen = function() {
476-
return scope.matches.length > 0;
484+
scope.isOpen = function () {
485+
var isDropdownOpen = scope.matches.length > 0;
486+
scope.assignIsOpen({ isOpen: isDropdownOpen });
487+
return isDropdownOpen;
477488
};
478489

479490
scope.isActive = function(matchIdx) {

0 commit comments

Comments
 (0)