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

Commit 7403527

Browse files
committed
feat(typeahead): added clear button
1 parent ddcacb7 commit 7403527

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

src/typeahead/test/typeahead.spec.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ describe('typeahead tests', function() {
6464
return findDropDown(element).find('li');
6565
};
6666

67+
var findClearBtn = function(element) {
68+
return element.find('.glyphicon-remove');
69+
};
70+
6771
var triggerKeyDown = function(element, keyCode, options) {
6872
options = options || {};
6973
var inputEl = findInput(element);
@@ -232,6 +236,45 @@ describe('typeahead tests', function() {
232236
expect($scope.result).toEqual('prefixfoo');
233237
});
234238

239+
it('should display X button after some option selected', function() {
240+
$scope.updaterFn = function(selectedItem) {
241+
return 'prefix' + selectedItem;
242+
};
243+
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="updaterFn(item) as item for item in source | filter:$viewValue"></div>');
244+
changeInputValueTo(element, 'f');
245+
triggerKeyDown(element, 13);
246+
expect($scope.result).toEqual('prefixfoo');
247+
var clearBtn = findClearBtn(element);
248+
expect(clearBtn).not.toHaveClass('ng-hide');
249+
});
250+
251+
it('should hide X button when selected item removed and input got empty', function() {
252+
$scope.updaterFn = function(selectedItem) {
253+
return 'prefix' + selectedItem;
254+
};
255+
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="updaterFn(item) as item for item in source | filter:$viewValue"></div>');
256+
changeInputValueTo(element, 'f');
257+
triggerKeyDown(element, 13);
258+
expect($scope.result).toEqual('prefixfoo');
259+
var clearBtn = findClearBtn(element);
260+
changeInputValueTo(element, '');
261+
expect(clearBtn).toHaveClass('ng-hide');
262+
});
263+
264+
it('when pressing X button should clear the ngModel', function() {
265+
$scope.updaterFn = function(selectedItem) {
266+
return 'prefix' + selectedItem;
267+
};
268+
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="updaterFn(item) as item for item in source | filter:$viewValue"></div>');
269+
changeInputValueTo(element, 'f');
270+
triggerKeyDown(element, 13);
271+
expect($scope.result).toEqual('prefixfoo');
272+
var clearBtn = findClearBtn(element);
273+
clearBtn.click();
274+
$scope.$digest();
275+
expect($scope.result).toEqual('');
276+
});
277+
235278
it('should support custom label rendering function', function() {
236279
$scope.formatterFn = function(sourceItem) {
237280
return 'prefix' + sourceItem;

src/typeahead/typeahead.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,17 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
162162

163163
//pop-up element used to display matches
164164
var popUpEl = angular.element('<div uib-typeahead-popup></div>');
165+
166+
var clearBtnEl = angular.element('<span></span>');
167+
clearBtnEl.attr({
168+
'class': 'glyphicon glyphicon-remove',
169+
'style': 'position: absolute; cursor: pointer;',
170+
'ng-style': '{top: positionClearBtn.top+\'px\', left: positionClearBtn.left +\'px\'}',
171+
'ng-click': 'clearModel()',
172+
'ng-show': 'showClearBtn'
173+
});
174+
175+
165176
popUpEl.attr({
166177
id: popupId,
167178
matches: 'matches',
@@ -319,6 +330,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
319330
function recalculatePosition() {
320331
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
321332
scope.position.top += element.prop('offsetHeight');
333+
scope.positionClearBtn = $position.position(element);
334+
scope.positionClearBtn.top += element.prop('offsetHeight') / 4;
335+
scope.positionClearBtn.left += element.prop('offsetWidth') - 20;
322336
}
323337

324338
//we need to propagate user's query so we can higlight matches
@@ -340,7 +354,11 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
340354
};
341355

342356
resetMatches();
343-
357+
//method for clear blutton
358+
scope.clearModel = function() {
359+
$setModelValue(originalScope, '');
360+
scope.showClearBtn = false;
361+
};
344362
scope.assignIsOpen = function (isOpen) {
345363
isOpenSetter(originalScope, isOpen);
346364
};
@@ -351,6 +369,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
351369
var model, item;
352370

353371
selected = true;
372+
373+
scope.showClearBtn = true; // Indicator that some choice selected (clear button should appear)
354374
locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
355375
model = parserResult.modelMapper(originalScope, locals);
356376
$setModelValue(originalScope, model);
@@ -498,6 +518,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
498518
});
499519

500520
var $popup = $compile(popUpEl)(scope);
521+
var $clearBtn = $compile(clearBtnEl)(scope);
501522

502523
if (appendToBody) {
503524
$document.find('body').append($popup);
@@ -506,6 +527,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
506527
} else {
507528
element.after($popup);
508529
}
530+
element.after($clearBtn);
509531

510532
this.init = function(_modelCtrl, _ngModelOptions) {
511533
modelCtrl = _modelCtrl;
@@ -529,6 +551,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
529551
isLoadingSetter(originalScope, false);
530552
cancelPreviousTimeout();
531553
resetMatches();
554+
if (!inputValue) {
555+
scope.showClearBtn = false; // Hide clear button if input empty
556+
}
532557
}
533558

534559
if (isEditable) {

0 commit comments

Comments
 (0)