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

feat(autocomplete): allow developers to specify amount of dropdown items #9307

Merged
merged 1 commit into from Sep 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/components/autocomplete/autocomplete.scss
@@ -1,4 +1,5 @@
$autocomplete-option-height: 48px !default;
// The default item height is also specified in the JavaScript.
$md-autocomplete-item-height: 48px !default;

@keyframes md-autocomplete-list-out {
0% {
Expand Down Expand Up @@ -201,25 +202,24 @@ md-autocomplete {
.md-virtual-repeat-container.md-autocomplete-suggestions-container {
position: absolute;
box-shadow: 0 2px 5px rgba(black, 0.25);
height: 41px * 5.5;
max-height: 41px * 5.5;
z-index: $z-index-tooltip;
}

.md-virtual-repeat-container.md-not-found {
height: 48px;
height: $md-autocomplete-item-height;
}

.md-autocomplete-suggestions {
margin: 0;
list-style: none;
padding: 0;

li {
font-size: 14px;
overflow: hidden;
padding: 0 15px;
line-height: $autocomplete-option-height;
height: $autocomplete-option-height;
line-height: $md-autocomplete-item-height;
height: $md-autocomplete-item-height;
transition: background 0.15s linear;
margin: 0;
white-space: nowrap;
Expand Down
118 changes: 118 additions & 0 deletions src/components/autocomplete/autocomplete.spec.js
Expand Up @@ -1736,6 +1736,26 @@ describe('<md-autocomplete>', function() {

describe('dropdown position', function() {

var DEFAULT_MAX_ITEMS = 5;
var DEFAULT_ITEM_HEIGHT = 48;

var dropdownItems = DEFAULT_MAX_ITEMS;

/**
* Function to create fake matches with the given dropdown items.
* Useful when running tests against the dropdown max items calculations.
* @returns {Array} Fake matches.
*/
function fakeItemMatch() {
var matches = [];

for (var i = 0; i < dropdownItems; i++) {
matches.push('Item ' + i);
}

return matches;
}

it('should adjust the width when the window resizes', inject(function($timeout, $window) {
var scope = createScope();

Expand Down Expand Up @@ -1936,6 +1956,104 @@ describe('<md-autocomplete>', function() {
document.body.removeChild(parent[0]);
}));

it('should calculate the height from the default max items', inject(function($timeout) {
var scope = createScope();

scope.match = fakeItemMatch;

var template =
'<div>' +
'<md-autocomplete ' +
'md-search-text="searchText" ' +
'md-items="item in match(searchText)" ' +
'md-item-text="item" ' +
'md-min-length="0" ' +
'placeholder="placeholder">' +
'<span md-highlight-text="searchText">{{item}}</span>' +
'</md-autocomplete>' +
'</div>';

var parent = compile(template, scope);
var element = parent.find('md-autocomplete');
var ctrl = element.controller('mdAutocomplete');

// Add container to the DOM to be able to test the rect calculations.
document.body.appendChild(parent[0]);

$timeout.flush();

// Focus the autocomplete and trigger a query to be able to open the dropdown.
ctrl.focus();
scope.$apply('searchText = "Query 1"');
waitForVirtualRepeat(element);

var scrollContainer = document.body.querySelector('.md-virtual-repeat-container');

expect(scrollContainer).toBeTruthy();
expect(scrollContainer.style.maxHeight).toBe(DEFAULT_MAX_ITEMS * DEFAULT_ITEM_HEIGHT + 'px');

dropdownItems = 6;

// Trigger a new query to request an update of the items and dropdown.
scope.$apply('searchText = "Query 2"');

// The dropdown should not increase its height because of the new extra item.
expect(scrollContainer.style.maxHeight).toBe(DEFAULT_MAX_ITEMS * DEFAULT_ITEM_HEIGHT + 'px');

document.body.removeChild(parent[0]);
}));

it('should calculate its height from the specified max items', inject(function($timeout) {
var scope = createScope();
var maxDropdownItems = 2;

// Set the current dropdown items to the new maximum.
dropdownItems = maxDropdownItems;
scope.match = fakeItemMatch;

var template =
'<div>' +
'<md-autocomplete ' +
'md-search-text="searchText" ' +
'md-items="item in match(searchText)" ' +
'md-item-text="item" ' +
'md-min-length="0" ' +
'md-dropdown-items="' + maxDropdownItems +'"' +
'placeholder="placeholder">' +
'<span md-highlight-text="searchText">{{item}}</span>' +
'</md-autocomplete>' +
'</div>';

var parent = compile(template, scope);
var element = parent.find('md-autocomplete');
var ctrl = element.controller('mdAutocomplete');

// Add container to the DOM to be able to test the rect calculations.
document.body.appendChild(parent[0]);

$timeout.flush();

// Focus the autocomplete and trigger a query to be able to open the dropdown.
ctrl.focus();
scope.$apply('searchText = "Query 1"');
waitForVirtualRepeat(element);

var scrollContainer = document.body.querySelector('.md-virtual-repeat-container');

expect(scrollContainer).toBeTruthy();
expect(scrollContainer.style.maxHeight).toBe(maxDropdownItems * DEFAULT_ITEM_HEIGHT + 'px');

dropdownItems = 6;

// Trigger a new query to request an update of the items and dropdown.
scope.$apply('searchText = "Query 2"');

// The dropdown should not increase its height because of the new extra item.
expect(scrollContainer.style.maxHeight).toBe(maxDropdownItems * DEFAULT_ITEM_HEIGHT + 'px');

document.body.removeChild(parent[0]);
}));

});

describe('md-highlight-text', function() {
Expand Down
17 changes: 11 additions & 6 deletions src/components/autocomplete/js/autocompleteController.js
Expand Up @@ -2,8 +2,8 @@ angular
.module('material.components.autocomplete')
.controller('MdAutocompleteCtrl', MdAutocompleteCtrl);

var ITEM_HEIGHT = 41,
MAX_HEIGHT = 5.5 * ITEM_HEIGHT,
var ITEM_HEIGHT = 48,
MAX_ITEMS = 5,
MENU_PADDING = 8,
INPUT_PADDING = 2; // Padding provided by `md-input-container`

Expand Down Expand Up @@ -92,7 +92,12 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
* @returns {*}
*/
function positionDropdown () {
if (!elements) return $mdUtil.nextTick(positionDropdown, false, $scope);
if (!elements) {
return $mdUtil.nextTick(positionDropdown, false, $scope);
}

var dropdownHeight = ($scope.dropdownItems || MAX_ITEMS) * ITEM_HEIGHT;

var hrect = elements.wrap.getBoundingClientRect(),
vrect = elements.snap.getBoundingClientRect(),
root = elements.root.getBoundingClientRect(),
Expand All @@ -112,14 +117,14 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
minWidth: width + 'px',
maxWidth: Math.max(hrect.right - root.left, root.right - hrect.left) - MENU_PADDING + 'px'
};
if (top > bot && root.height - hrect.bottom - MENU_PADDING < MAX_HEIGHT) {
if (top > bot && root.height - hrect.bottom - MENU_PADDING < dropdownHeight) {
styles.top = 'auto';
styles.bottom = bot + 'px';
styles.maxHeight = Math.min(MAX_HEIGHT, hrect.top - root.top - MENU_PADDING) + 'px';
styles.maxHeight = Math.min(dropdownHeight, hrect.top - root.top - MENU_PADDING) + 'px';
} else {
styles.top = (top - offset) + 'px';
styles.bottom = 'auto';
styles.maxHeight = Math.min(MAX_HEIGHT, root.bottom + $mdUtil.scrollTop() - hrect.bottom - MENU_PADDING) + 'px';
styles.maxHeight = Math.min(dropdownHeight, root.bottom + $mdUtil.scrollTop() - hrect.bottom - MENU_PADDING) + 'px';
}

elements.$.scrollContainer.css(styles);
Expand Down
7 changes: 6 additions & 1 deletion src/components/autocomplete/js/autocompleteDirective.js
Expand Up @@ -82,6 +82,10 @@ angular
* will select on case-insensitive match
* @param {string=} md-escape-options Override escape key logic. Default is `blur clear`.<br/>
* Options: `blur | clear`, `none`
* @param {string=} md-dropdown-items Specifies the maximum amount of items to be shown in
* the dropdown.<br/><br/>
* When the dropdown doesn't fit into the viewport, the dropdown will shrink
* as less as possible.
*
* @usage
* ### Basic Example
Expand Down Expand Up @@ -165,7 +169,8 @@ function MdAutocomplete ($$mdSvgRegistry) {
autoselect: '=?mdAutoselect',
menuClass: '@?mdMenuClass',
inputId: '@?mdInputId',
escapeOptions: '@?mdEscapeOptions'
escapeOptions: '@?mdEscapeOptions',
dropdownItems: '=?mdDropdownItems'
},
link: function(scope, element, attrs, controller) {
// Retrieve the state of using a md-not-found template by using our attribute, which will
Expand Down