Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 1ed298b

Browse files
donmccurdyjelbourn
authored andcommitted
feat(autocomplete): add md-dropdown-position option (#9774)
Because obstructions in the viewport (liked fixed-position elements) cannot be automatically detected, allow users to override top/bottom positioning when needed. Usage: ```html <md-autocomplete md-items="item in ctrl.querySearch(ctrl.searchText)" md-dropdown-position="bottom" ... ``` Fixes #9769.
1 parent 002207c commit 1ed298b

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

src/components/autocomplete/autocomplete.spec.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,54 @@ describe('<md-autocomplete>', function() {
22462246
document.body.removeChild(parent[0]);
22472247
}));
22482248

2249+
it('should allow dropdown position to be specified', inject(function($timeout, $window) {
2250+
var scope = createScope();
2251+
2252+
scope.match = fakeItemMatch;
2253+
scope.position = 'top';
2254+
2255+
var template = '<div>' +
2256+
'<md-autocomplete ' +
2257+
'md-search-text="searchText" ' +
2258+
'md-items="item in match(searchText)" ' +
2259+
'md-item-text="item" ' +
2260+
'md-min-length="0" ' +
2261+
'md-dropdown-position="{{position}}" ' +
2262+
'placeholder="placeholder">' +
2263+
'<span md-highlight-text="searchText">{{item}}</span>' +
2264+
'</md-autocomplete>' +
2265+
'</div>';
2266+
2267+
var parent = compile(template, scope);
2268+
var element = parent.find('md-autocomplete');
2269+
var ctrl = element.controller('mdAutocomplete');
2270+
2271+
// Add container to the DOM to be able to test the rect calculations.
2272+
document.body.appendChild(parent[0]);
2273+
2274+
$timeout.flush();
2275+
2276+
// Focus the autocomplete and trigger a query to be able to open the dropdown.
2277+
ctrl.focus();
2278+
scope.$apply('searchText = "Query 1"');
2279+
waitForVirtualRepeat(element);
2280+
2281+
var scrollContainer = document.body.querySelector('.md-virtual-repeat-container');
2282+
2283+
expect(scrollContainer).toBeTruthy();
2284+
expect(scrollContainer.style.top).toBe('auto');
2285+
expect(scrollContainer.style.bottom).toMatch(/[0-9]+px/);
2286+
2287+
// Change position and resize to force a DOM update.
2288+
scope.$apply('position = "bottom"');
2289+
angular.element($window).triggerHandler('resize');
2290+
2291+
expect(scrollContainer.style.top).toMatch(/[0-9]+px/);
2292+
expect(scrollContainer.style.bottom).toBe('auto');
2293+
2294+
parent.remove();
2295+
}));
2296+
22492297
});
22502298

22512299
describe('md-highlight-text', function() {

src/components/autocomplete/js/autocompleteController.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,13 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
113113
left = hrect.left - root.left,
114114
width = hrect.width,
115115
offset = getVerticalOffset(),
116+
position = $scope.dropdownPosition,
116117
styles;
118+
119+
// Automatically determine dropdown placement based on available space in viewport.
120+
if (!position) {
121+
position = (top > bot && root.height - hrect.bottom - MENU_PADDING < dropdownHeight) ? 'top' : 'bottom';
122+
}
117123
// Adjust the width to account for the padding provided by `md-input-container`
118124
if ($attrs.mdFloatingLabel) {
119125
left += INPUT_PADDING;
@@ -124,7 +130,8 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
124130
minWidth: width + 'px',
125131
maxWidth: Math.max(hrect.right - root.left, root.right - hrect.left) - MENU_PADDING + 'px'
126132
};
127-
if (top > bot && root.height - hrect.bottom - MENU_PADDING < dropdownHeight) {
133+
134+
if (position === 'top') {
128135
styles.top = 'auto';
129136
styles.bottom = bot + 'px';
130137
styles.maxHeight = Math.min(dropdownHeight, hrect.top - root.top - MENU_PADDING) + 'px';

src/components/autocomplete/js/autocompleteDirective.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ angular
114114
* the dropdown.<br/><br/>
115115
* When the dropdown doesn't fit into the viewport, the dropdown will shrink
116116
* as less as possible.
117+
* @param {string=} md-dropdown-position Overrides the default dropdown position. Options: `top`, `bottom`.
117118
* @param {string=} ng-trim If set to false, the search text will be not trimmed automatically.
118119
* Defaults to true.
119120
* @param {string=} ng-pattern Adds the pattern validator to the ngModel of the search text.
@@ -230,7 +231,8 @@ function MdAutocomplete ($$mdSvgRegistry) {
230231
menuClass: '@?mdMenuClass',
231232
inputId: '@?mdInputId',
232233
escapeOptions: '@?mdEscapeOptions',
233-
dropdownItems: '=?mdDropdownItems'
234+
dropdownItems: '=?mdDropdownItems',
235+
dropdownPosition: '@?mdDropdownPosition'
234236
},
235237
compile: function(tElement, tAttrs) {
236238
var attributes = ['md-select-on-focus', 'md-no-asterisk', 'ng-trim', 'ng-pattern'];

0 commit comments

Comments
 (0)