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

feat(typeahead): add 'is-toggled' option #4779

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/typeahead/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,7 @@ The typeahead directives provide several attributes:
* `typeahead-focus-on-select`
_(Defaults: true) :
On selection, focus the input element the typeahead directive is associated with

* `typeahead-is-open` <i class="glyphicon glyphicon-eye-open"></i>
_(Defaults: angular.noop)_ :
Binding to a variable that indicates if dropdown is open
72 changes: 72 additions & 0 deletions src/typeahead/test/typeahead.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,78 @@ describe('typeahead tests', function() {
});
});

describe('is-open indicator', function () {
var element;

beforeEach(function () {
element = prepareInputEl('<div><input ng-model="result" uib-typeahead="item for item in source | filter:$viewValue" typeahead-is-open="isOpen"></div>');
});

it('should bind is-open indicator as true when matches are returned', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
});

it('should bind is-open indicator as false when no matches returned', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
changeInputValueTo(element, 'not match');
expect($scope.isOpen).toBeFalsy();
});

it('should bind is-open indicator as false when a match is clicked', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
var match = findMatches(element).find('a').eq(0);

match.click();
$scope.$digest();
expect($scope.isOpen).toBeFalsy();
});
it('should bind is-open indicator as false when click outside', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
$document.find('body').click();
$scope.$digest();
expect($scope.isOpen).toBeFalsy();
});

it('should bind is-open indicator as false on enter', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
triggerKeyDown(element, 13);
expect($scope.isOpen).toBeFalsy();
});

it('should bind is-open indicator as false on tab', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
triggerKeyDown(element, 9);
expect($scope.isOpen).toBeFalsy();
});

it('should bind is-open indicator as false on escape key', function () {
expect($scope.isOpen).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isOpen).toBeTruthy();
triggerKeyDown(element, 27);
expect($scope.isOpen).toBeFalsy();
});

it('should bind is-open indicator as false input value smaller than a defined threshold', function () {
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>');
expect($scope.isToggled).toBeFalsy();
changeInputValueTo(element, 'b');
expect($scope.isToggled).toBeFalsy();
});
});

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

Expand Down
19 changes: 15 additions & 4 deletions src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
//If input matches an item of the list exactly, select it automatically
var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;

//binding to a variable that indicates if dropdown is open
var isOpenSetter = $parse(attrs.typeaheadIsOpen).assign || angular.noop;

//INTERNAL VARIABLES

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

resetMatches();

scope.assignIsOpen = function (isOpen) {
isOpenSetter(originalScope, isOpen);
};

scope.select = function(activeIdx) {
//called from within the $digest() cycle
var locals = {};
Expand Down Expand Up @@ -463,7 +471,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
active: '=',
position: '&',
moveInProgress: '=',
select: '&'
select: '&',
assignIsOpen: '&',
},
replace: true,
templateUrl: function(element, attrs) {
Expand All @@ -472,8 +481,10 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
link: function(scope, element, attrs) {
scope.templateUrl = attrs.templateUrl;

scope.isOpen = function() {
return scope.matches.length > 0;
scope.isOpen = function () {
var isDropdownOpen = scope.matches.length > 0;
scope.assignIsOpen({ isOpen: isDropdownOpen });
return isDropdownOpen;
};

scope.isActive = function(matchIdx) {
Expand Down