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

typeahead improvement - çlear ('x') button which appears after some option selected from suggestions #4483

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
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
43 changes: 43 additions & 0 deletions src/typeahead/test/typeahead.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ describe('typeahead tests', function() {
return findDropDown(element).find('li');
};

var findClearBtn = function(element) {
return element.find('.glyphicon-remove');
};

var triggerKeyDown = function(element, keyCode, options) {
options = options || {};
var inputEl = findInput(element);
Expand Down Expand Up @@ -232,6 +236,45 @@ describe('typeahead tests', function() {
expect($scope.result).toEqual('prefixfoo');
});

it('should display X button after some option selected', function() {
$scope.updaterFn = function(selectedItem) {
return 'prefix' + selectedItem;
};
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="updaterFn(item) as item for item in source | filter:$viewValue"></div>');
changeInputValueTo(element, 'f');
triggerKeyDown(element, 13);
expect($scope.result).toEqual('prefixfoo');
var clearBtn = findClearBtn(element);
expect(clearBtn).not.toHaveClass('ng-hide');
});

it('should hide X button when selected item removed and input got empty', function() {
$scope.updaterFn = function(selectedItem) {
return 'prefix' + selectedItem;
};
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="updaterFn(item) as item for item in source | filter:$viewValue"></div>');
changeInputValueTo(element, 'f');
triggerKeyDown(element, 13);
expect($scope.result).toEqual('prefixfoo');
var clearBtn = findClearBtn(element);
changeInputValueTo(element, '');
expect(clearBtn).toHaveClass('ng-hide');
});

it('when pressing X button should clear the ngModel', function() {
$scope.updaterFn = function(selectedItem) {
return 'prefix' + selectedItem;
};
var element = prepareInputEl('<div><input ng-model="result" uib-typeahead="updaterFn(item) as item for item in source | filter:$viewValue"></div>');
changeInputValueTo(element, 'f');
triggerKeyDown(element, 13);
expect($scope.result).toEqual('prefixfoo');
var clearBtn = findClearBtn(element);
clearBtn.click();
$scope.$digest();
expect($scope.result).toEqual('');
});

it('should support custom label rendering function', function() {
$scope.formatterFn = function(sourceItem) {
return 'prefix' + sourceItem;
Expand Down
17 changes: 16 additions & 1 deletion src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap

//pop-up element used to display matches
var popUpEl = angular.element('<div uib-typeahead-popup></div>');
var clearBtnEl = angular.element('<span class="glyphicon glyphicon-remove" ng-style="{ cursor:\'pointer\',position:\'absolute\',top:positionClearBtn.top+\'px\', left:positionClearBtn.left+\'px\'}" ng-show="showClearBtn" ng-click="clearModel()"></span>');
popUpEl.attr({
id: popupId,
matches: 'matches',
Expand Down Expand Up @@ -319,6 +320,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
function recalculatePosition() {
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
scope.position.top += element.prop('offsetHeight');
scope.positionClearBtn = $position.position(element);
scope.positionClearBtn.top += element.prop('offsetHeight') / 4;
scope.positionClearBtn.left += element.prop('offsetWidth') - 20;
}

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

resetMatches();

//method for clear blutton
scope.clearModel = function() {
$setModelValue(originalScope, '');
scope.showClearBtn = false;
};
scope.assignIsOpen = function (isOpen) {
isOpenSetter(originalScope, isOpen);
};
Expand All @@ -351,6 +359,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
var model, item;

selected = true;

scope.showClearBtn = true; // Indicator that some choice selected (clear button should appear)
locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
model = parserResult.modelMapper(originalScope, locals);
$setModelValue(originalScope, model);
Expand Down Expand Up @@ -498,6 +508,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
});

var $popup = $compile(popUpEl)(scope);
var $clearBtn = $compile(clearBtnEl)(scope);

if (appendToBody) {
$document.find('body').append($popup);
Expand All @@ -506,6 +517,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
} else {
element.after($popup);
}
element.after($clearBtn);

this.init = function(_modelCtrl, _ngModelOptions) {
modelCtrl = _modelCtrl;
Expand All @@ -529,6 +541,9 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap
isLoadingSetter(originalScope, false);
cancelPreviousTimeout();
resetMatches();
if (!inputValue) {
scope.showClearBtn = false; // Hide clear button if input empty
}
}

if (isEditable) {
Expand Down