-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Typeahead popup position #3874
Typeahead popup position #3874
Changes from 9 commits
71c34ae
7271ca0
810733a
2155610
690d78b
b7ab020
a35d89a
156b223
2a3cd0f
6cfd598
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,10 +29,11 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap | |
}; | ||
}]) | ||
|
||
.directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$rootScope', '$position', 'typeaheadParser', | ||
function ($compile, $parse, $q, $timeout, $document, $rootScope, $position, typeaheadParser) { | ||
.directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$position', 'typeaheadParser', | ||
function ($compile, $parse, $q, $timeout, $document, $window, $rootScope, $position, typeaheadParser) { | ||
|
||
var HOT_KEYS = [9, 13, 27, 38, 40]; | ||
var eventDebounceTime = 200; | ||
|
||
return { | ||
require:'ngModel', | ||
|
@@ -96,6 +97,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap | |
matches: 'matches', | ||
active: 'activeIdx', | ||
select: 'select(activeIdx)', | ||
'move-in-progress': 'moveInProgress', | ||
query: 'query', | ||
position: 'position' | ||
}); | ||
|
@@ -153,8 +155,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap | |
//position pop-up with matches - we need to re-calculate its position each time we are opening a window | ||
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page | ||
//due to other elements being rendered | ||
scope.position = appendToBody ? $position.offset(element) : $position.position(element); | ||
scope.position.top = scope.position.top + element.prop('offsetHeight'); | ||
recalculatePosition(); | ||
|
||
element.attr('aria-expanded', true); | ||
} else { | ||
|
@@ -170,6 +171,52 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap | |
}); | ||
}; | ||
|
||
// bind events only if appendToBody params exist - performance feature | ||
if ( appendToBody ) { | ||
angular.element( $window ).bind( 'resize', fireRecalculating ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove spaces just after |
||
$document.find( 'body' ).bind( 'scroll', fireRecalculating ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both these event listeners need to be throttled - the resize and scroll events both fire often. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, a debounce on each of the event listeners would be better, since we only care about the trailing trigger of the event. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove spaces just after |
||
} | ||
|
||
// Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later | ||
var timeoutEventPromise; | ||
|
||
// Default progress type | ||
scope.moveInProgress = false; | ||
|
||
function fireRecalculating() { | ||
|
||
if( !scope.moveInProgress ){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change to |
||
scope.moveInProgress = true; | ||
scope.$digest(); | ||
} | ||
|
||
// Cancel previous timeout | ||
if ( timeoutEventPromise ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove spaces just after |
||
$timeout.cancel(timeoutEventPromise); | ||
} | ||
|
||
// Debounced executing recalculate after events fired | ||
timeoutEventPromise = $timeout(function () { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this line |
||
// if popup is visible | ||
if ( scope.matches.length ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
recalculatePosition(); | ||
} | ||
|
||
scope.moveInProgress = false; | ||
scope.$digest(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove this line |
||
}, eventDebounceTime); | ||
|
||
} | ||
|
||
// recalculate actual position and set new values to scope | ||
// after digest loop is popup in right position | ||
function recalculatePosition() { | ||
scope.position = appendToBody ? $position.offset(element) : $position.position(element); | ||
scope.position.top = scope.position.top + element.prop('offsetHeight'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is there a separate top calculation? Also this should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is function copied from original code and top, must be calculate with offsetHeight of input, because dropdown must be showed after bottom edge of input. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make more sense to move the functionality into the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think something like |
||
} | ||
|
||
resetMatches(); | ||
|
||
//we need to propagate user's query so we can higlight matches | ||
|
@@ -358,6 +405,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap | |
query:'=', | ||
active:'=', | ||
position:'&', | ||
moveInProgress:'=', | ||
select:'&' | ||
}, | ||
replace:true, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove spaces in between
(
and)