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

Commit 7f355f6

Browse files
author
Robert Messerle
committed
fix(autocomplete): moves autocomplete dropdown to nearest content container
Closes #2013 Closes #1961 Closes #1670
1 parent 78e81a7 commit 7f355f6

6 files changed

Lines changed: 92 additions & 60 deletions

File tree

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
md-autocomplete {
1+
md-autocomplete.md-THEME_NAME-theme {
22
background: '{{background-50}}';
33
button {
44
md-icon {
@@ -10,18 +10,18 @@ md-autocomplete {
1010
background: '{{background-600-0.3}}';
1111
}
1212
}
13-
ul {
14-
background: '{{background-50}}';
15-
li {
16-
border-top: 1px solid '{{background-400}}';
17-
color: '{{background-900}}';
18-
.highlight {
19-
color: '{{background-600}}';
20-
}
21-
&:hover,
22-
&.selected {
23-
background: '{{background-200}}';
24-
}
13+
}
14+
.md-autocomplete-suggestions.md-THEME_NAME-theme {
15+
background: '{{background-50}}';
16+
li {
17+
border-top: 1px solid '{{background-300}}';
18+
color: '{{background-900}}';
19+
.highlight {
20+
color: '{{background-600}}';
21+
}
22+
&:hover,
23+
&.selected {
24+
background: '{{background-200}}';
2525
}
2626
}
2727
}

src/components/autocomplete/autocomplete.scss

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@
2727
height: 40px;
2828
}
2929
}
30-
md-content {
31-
overflow: visible;
32-
}
3330
md-autocomplete {
3431
box-shadow: 0 2px 5px rgba(black, 0.25);
3532
border-radius: 2px;
@@ -98,7 +95,6 @@ md-autocomplete {
9895
line-height: 40px;
9996
height: 40px;
10097
outline: none;
101-
z-index: 2;
10298
background: transparent;
10399
&::-ms-clear {
104100
display: none;
@@ -109,7 +105,6 @@ md-autocomplete {
109105
top: 10px;
110106
right: 10px;
111107
line-height: 20px;
112-
z-index: 2;
113108
text-align: center;
114109
width: 20px;
115110
height: 20px;
@@ -130,7 +125,6 @@ md-autocomplete {
130125
transform: scale(0);
131126
opacity: 0;
132127
transition: $swift-ease-out;
133-
z-index: -1;
134128
}
135129
&:focus {
136130
outline: none;
@@ -163,40 +157,6 @@ md-autocomplete {
163157
}
164158
}
165159
}
166-
ul {
167-
position: absolute;
168-
top: 100%;
169-
left: 0;
170-
right: 0;
171-
box-shadow: 0 2px 5px rgba(black, 0.25);
172-
margin: 0;
173-
list-style: none;
174-
padding: 0;
175-
overflow: auto;
176-
max-height: 41px * 5.5;
177-
z-index: $z-index-backdrop - 1;
178-
li {
179-
border-top: 1px solid #ddd;
180-
padding: 0 15px;
181-
line-height: 40px;
182-
font-size: 14px;
183-
overflow: hidden;
184-
height: 40px;
185-
transition: background 0.15s linear;
186-
cursor: pointer;
187-
margin: 0;
188-
&.ng-enter,
189-
&.ng-hide-remove {
190-
transition: none;
191-
animation: md-autocomplete-list-in 0.2s;
192-
}
193-
&.ng-leave,
194-
&.ng-hide-add {
195-
transition: none;
196-
animation: md-autocomplete-list-out 0.2s;
197-
}
198-
}
199-
}
200160
@media screen and (-ms-high-contrast: active) {
201161
$border-color: #fff;
202162

@@ -208,3 +168,37 @@ md-autocomplete {
208168
}
209169
}
210170
}
171+
.md-autocomplete-suggestions {
172+
position: absolute;
173+
top: 100%;
174+
left: 0;
175+
right: 0;
176+
box-shadow: 0 2px 5px rgba(black, 0.25);
177+
margin: 0;
178+
list-style: none;
179+
padding: 0;
180+
overflow: auto;
181+
max-height: 41px * 5.5;
182+
z-index: $z-index-backdrop - 1;
183+
li {
184+
border-top: 1px solid #ddd;
185+
padding: 0 15px;
186+
line-height: 40px;
187+
font-size: 14px;
188+
overflow: hidden;
189+
height: 40px;
190+
transition: background 0.15s linear;
191+
cursor: pointer;
192+
margin: 0;
193+
&.ng-enter,
194+
&.ng-hide-remove {
195+
transition: none;
196+
animation: md-autocomplete-list-in 0.2s;
197+
}
198+
&.ng-leave,
199+
&.ng-hide-add {
200+
transition: none;
201+
animation: md-autocomplete-list-out 0.2s;
202+
}
203+
}
204+
}

src/components/autocomplete/autocomplete.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('<md-autocomplete>', function() {
2828
}
2929

3030
describe('basic functionality', function () {
31-
it('should fail', inject(function($timeout, $mdConstant) {
31+
it('should fail', inject(function($timeout, $mdConstant, $rootElement) {
3232
var scope = createScope();
3333
var template = '\
3434
<md-autocomplete\

src/components/autocomplete/js/autocompleteController.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
.module('material.components.autocomplete')
55
.controller('MdAutocompleteCtrl', MdAutocompleteCtrl);
66

7-
function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout) {
7+
function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $rootElement, $mdTheming) {
88

99
//-- private variables
1010

@@ -54,9 +54,34 @@
5454
$timeout(function () {
5555
gatherElements();
5656
focusElement();
57+
moveDropdown();
5758
});
5859
}
5960

61+
function getNearestContentElement () {
62+
var current = $element.parent()[0];
63+
while (current && current !== $rootElement[0] && current !== document.body) {
64+
if (current.tagName && current.tagName.toLowerCase() === 'md-content') break;
65+
current = current.parentNode;
66+
}
67+
return current;
68+
}
69+
70+
function positionDropdown () {
71+
elements.$.ul.css({
72+
left: $element.prop('offsetLeft') + 'px',
73+
top: ($element.prop('offsetTop') + $element.prop('offsetHeight')) + 'px',
74+
width: $element.prop('offsetWidth') + 'px'
75+
});
76+
}
77+
78+
function moveDropdown () {
79+
if (!elements.$.root.length) return;
80+
$mdTheming(elements.$.ul);
81+
elements.$.ul.detach();
82+
elements.$.root.append(elements.$.ul);
83+
}
84+
6085
function focusElement () {
6186
if ($scope.autofocus) elements.input.focus();
6287
}
@@ -74,8 +99,18 @@
7499
elements = {
75100
main: $element[0],
76101
ul: $element[0].getElementsByTagName('ul')[0],
77-
input: $element[0].getElementsByTagName('input')[0]
102+
input: $element[0].getElementsByTagName('input')[0],
103+
root: getNearestContentElement()
78104
};
105+
elements.$ = getAngularElements(elements);
106+
}
107+
108+
function getAngularElements (elements) {
109+
var obj = {};
110+
for (var key in elements) {
111+
obj[key] = angular.element(elements[key]);
112+
}
113+
return obj;
79114
}
80115

81116
//-- event/change handlers
@@ -130,6 +165,7 @@
130165
self.loading = false;
131166
self.matches = [];
132167
self.hidden = shouldHide();
168+
positionDropdown();
133169
updateMessages();
134170
} else {
135171
handleQuery();

src/components/autocomplete/js/autocompleteDirective.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* </hljs>
4040
*/
4141

42-
function MdAutocomplete () {
42+
function MdAutocomplete ($mdTheming) {
4343
return {
4444
controller: 'MdAutocompleteCtrl',
4545
controllerAs: '$mdAutocompleteCtrl',
@@ -112,6 +112,7 @@
112112
ng-if="$mdAutocompleteCtrl.loading"\
113113
md-mode="indeterminate"></md-progress-linear>\
114114
<ul role="presentation"\
115+
class="md-autocomplete-suggestions"\
115116
id="ul-{{$mdAutocompleteCtrl.id}}"\
116117
ng-mouseenter="$mdAutocompleteCtrl.listEnter()"\
117118
ng-mouseleave="$mdAutocompleteCtrl.listLeave()"\
@@ -141,6 +142,7 @@
141142
scope[key] = attr.hasOwnProperty(attr.$normalize(binding.attrName));
142143
}
143144
});
145+
$mdTheming(element);
144146
}
145147
}
146148
})();

src/components/autocomplete/js/listItemDirective.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66

77
function MdAutocompleteListItem ($compile, $mdUtil) {
88
return {
9-
require: '^?mdAutocomplete',
109
terminal: true,
1110
link: link,
1211
scope: false
1312
};
14-
function link (scope, element, attr, ctrl) {
15-
var newScope = ctrl.parent.$new(false, ctrl.parent),
13+
function link (scope, element, attr) {
14+
var ctrl = scope.$parent.$mdAutocompleteCtrl,
15+
newScope = ctrl.parent.$new(false, ctrl.parent),
1616
itemName = ctrl.scope.$eval(attr.mdAutocompleteListItem);
1717
newScope[itemName] = scope.item;
1818
element.html(ctrl.scope.$eval(attr.mdAutocompleteListItemTemplate));

0 commit comments

Comments
 (0)