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

Commit

Permalink
feat(typeahead): add noResults indicator binding
Browse files Browse the repository at this point in the history
- Add ability to configure no results message

Closes #2016
Closes #2792
Closes #4068
  • Loading branch information
Jeff Treuting authored and wesleycho committed Aug 1, 2015
1 parent 9f73d24 commit 647cdd9
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 7 deletions.
5 changes: 4 additions & 1 deletion src/typeahead/docs/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ <h4>Static arrays</h4>

<h4>Asynchronous results</h4>
<pre>Model: {{asyncSelected | json}}</pre>
<input type="text" ng-model="asyncSelected" placeholder="Locations loaded via $http" typeahead="address for address in getLocation($viewValue)" typeahead-loading="loadingLocations" class="form-control">
<input type="text" ng-model="asyncSelected" placeholder="Locations loaded via $http" typeahead="address for address in getLocation($viewValue)" typeahead-loading="loadingLocations" typeahead-no-results="noResults" class="form-control">
<i ng-show="loadingLocations" class="glyphicon glyphicon-refresh"></i>
<div ng-show="noResults">
<i class="glyphicon glyphicon-remove"></i> No Results Found
</div>

<h4>Custom templates for results</h4>
<pre>Model: {{customSelected | json}}</pre>
Expand Down
6 changes: 5 additions & 1 deletion src/typeahead/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ The typeahead directives provide several attributes:
* `typeahead-min-length` <i class="glyphicon glyphicon-eye-open"></i>
_(Defaults: 1)_ :
Minimal no of characters that needs to be entered before typeahead kicks-in


* `typeahead-no-results` <i class="glyphicon glyphicon-eye-open"></i>
_(Defaults: angular.noop)_ :
Binding to a variable that indicates if no matching results were found

* `typeahead-on-select($item, $model, $label)`
_(Defaults: null)_ :
A callback executed when a match is selected
Expand Down
34 changes: 34 additions & 0 deletions src/typeahead/test/typeahead.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,40 @@ describe('typeahead tests', function () {
expect($scope.result).toEqual('AL');
expect(inputEl.val()).toEqual('AL');
});

it('should bind no results indicator as true when no matches returned', inject(function ($timeout) {

$scope.isNoResults = false;
$scope.loadMatches = function (viewValue) {
return $timeout(function () {
return [];
}, 1000);
};

var element = prepareInputEl('<div><input ng-model="result" typeahead="item for item in loadMatches()" typeahead-no-results="isNoResults"></div>');
changeInputValueTo(element, 'foo');

expect($scope.isNoResults).toBeFalsy();
$timeout.flush();
expect($scope.isNoResults).toBeTruthy();
}));

it('should bind no results indicator as false when matches are returned', inject(function ($timeout) {

$scope.isNoResults = false;
$scope.loadMatches = function (viewValue) {
return $timeout(function () {
return [viewValue];
}, 1000);
};

var element = prepareInputEl('<div><input ng-model="result" typeahead="item for item in loadMatches()" typeahead-no-results="isNoResults"></div>');
changeInputValueTo(element, 'foo');

expect($scope.isNoResults).toBeFalsy();
$timeout.flush();
expect($scope.isNoResults).toBeFalsy();
}));
});

describe('select on exact match', function(){
Expand Down
17 changes: 12 additions & 5 deletions src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
//should it select highlighted popup value when losing focus?
var isSelectOnBlur = angular.isDefined(attrs.typeaheadSelectOnBlur) ? originalScope.$eval(attrs.typeaheadSelectOnBlur) : false;

//binding to a variable that indicates if there were no results after the query is completed
var isNoResultsSetter = $parse(attrs.typeaheadNoResults).assign || angular.noop;

var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;

var appendToBody = attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;

var focusFirst = originalScope.$eval(attrs.typeaheadFocusFirst) !== false;

//If input matches an item of the list exactly, select it automatically
var selectOnExact = attrs.typeaheadSelectOnExact ? originalScope.$eval(attrs.typeaheadSelectOnExact) : false;

Expand Down Expand Up @@ -136,20 +139,21 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
element.attr('aria-activedescendant', getMatchId(index));
}
});

var inputIsExactMatch = function(inputValue, index) {

if (scope.matches.length > index && inputValue) {
return inputValue.toUpperCase() === scope.matches[index].label.toUpperCase();
}

return false;
};

var getMatchesAsync = function(inputValue) {

var locals = {$viewValue: inputValue};
isLoadingSetter(originalScope, true);
isNoResultsSetter(originalScope, false);
$q.when(parserResult.source(originalScope, locals)).then(function(matches) {

//it might happen that several async queries were in progress if a user were typing fast
Expand All @@ -159,6 +163,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
if (matches && matches.length > 0) {

scope.activeIdx = focusFirst ? 0 : -1;
isNoResultsSetter(originalScope, false);
scope.matches.length = 0;

//transform labels
Expand All @@ -178,13 +183,14 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
recalculatePosition();

element.attr('aria-expanded', true);

//Select the single remaining option if user input matches
if (selectOnExact && scope.matches.length === 1 && inputIsExactMatch(inputValue, 0)) {
scope.select(0);
}
} else {
resetMatches();
isNoResultsSetter(originalScope, true);
}
}
if (onCurrentRequest) {
Expand All @@ -193,6 +199,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap
}, function(){
resetMatches();
isLoadingSetter(originalScope, false);
isNoResultsSetter(originalScope, true);
});
};

Expand Down

0 comments on commit 647cdd9

Please sign in to comment.