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

Commit

Permalink
fix(typeahead): separate text field rendering and drop down rendering
Browse files Browse the repository at this point in the history
Closes #240
Closes #274
  • Loading branch information
pkozlowski-opensource committed Jun 30, 2013
1 parent c4e169c commit ea1e858
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 11 deletions.
16 changes: 15 additions & 1 deletion src/typeahead/test/typeahead.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ describe('typeahead tests', function () {
});
});

describe('integration with existing formatters', function () {
describe('input formatting', function () {

it('should co-operate with existing formatters', function () {

Expand All @@ -290,6 +290,20 @@ describe('typeahead tests', function () {

expect(inputEl.val()).toEqual('formatted' + $scope.result.name);
});

it('should support a custom input formatting function', function () {

$scope.result = $scope.states[0];
$scope.formatInput = function($model) {
return $model.code;
};

var element = prepareInputEl("<div><input ng-model='result' typeahead-input-formatter='formatInput($model)' typeahead='state as state.name for state in states | filter:$viewValue'></div>"),
inputEl = findInput(element);

expect(inputEl.val()).toEqual('AL');
expect($scope.result).toEqual($scope.states[0]);
});
});

});
39 changes: 29 additions & 10 deletions src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,34 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
require:'ngModel',
link:function (originalScope, element, attrs, modelCtrl) {

var $setModelValue = $parse(attrs.ngModel).assign;
//SUPPORTED ATTRIBUTES (OPTIONS)

//minimal no of characters that needs to be entered before typeahead kicks-in
var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;

//minimal wait time after last character typed before typehead kicks-in
var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;

//expressions used by typeahead
var parserResult = typeaheadParser.parse(attrs.typeahead);

//should it restrict model values to the ones selected from the popup only?
var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;

//binding to a variable that indicates if matches are being retrieved asynchronously
var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;

//a callback executed when a match is selected
var onSelectCallback = $parse(attrs.typeaheadOnSelect);

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

//INTERNAL VARIABLES

//model setter executed upon match selection
var $setModelValue = $parse(attrs.ngModel).assign;

//expressions used by typeahead
var parserResult = typeaheadParser.parse(attrs.typeahead);


//pop-up element used to display matches
var popUpEl = angular.element('<typeahead-popup></typeahead-popup>');
popUpEl.attr({
Expand Down Expand Up @@ -147,16 +157,25 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
});

modelCtrl.$formatters.push(function (modelValue) {

var candidateViewValue, emptyViewValue;
var locals = {};
locals[parserResult.itemName] = modelValue;

//it might happen that we don't have enough info to properly render input value
//we need to check for this
candidateViewValue = parserResult.viewMapper(originalScope, locals);
emptyViewValue = parserResult.viewMapper(originalScope, {});
if (inputFormatter) {

return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
locals['$model'] = modelValue;
return inputFormatter(originalScope, locals);

} else {
locals[parserResult.itemName] = modelValue;

//it might happen that we don't have enough info to properly render input value
//we need to check for this situation and simply return model value if we can't apply custom formatting
candidateViewValue = parserResult.viewMapper(originalScope, locals);
emptyViewValue = parserResult.viewMapper(originalScope, {});

return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
}
});

scope.select = function (activeIdx) {
Expand Down

0 comments on commit ea1e858

Please sign in to comment.