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

Commit 74beecd

Browse files
fix(typeahead): fix matches pop-up positioning issues
Closes #262, #282
1 parent 77d9fa7 commit 74beecd

File tree

3 files changed

+29
-20
lines changed

3 files changed

+29
-20
lines changed

src/typeahead/test/typeahead.spec.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ describe('typeahead tests', function () {
200200
};
201201

202202
var findDropDown = function(element) {
203-
return element.find('div.dropdown');
203+
return element.find('ul.typeahead');
204204
};
205205

206206
var findMatches = function(element) {
@@ -222,7 +222,7 @@ describe('typeahead tests', function () {
222222
this.message = function() {
223223
return "Expected '" + angular.mock.dump(this.actual) + "' to be closed.";
224224
};
225-
return !typeaheadEl.hasClass('open') && findMatches(this.actual).length === 0;
225+
return typeaheadEl.css('display')==='none' && findMatches(this.actual).length === 0;
226226

227227
}, toBeOpenWithActive: function(noOfMatches, activeIdx) {
228228

@@ -232,7 +232,7 @@ describe('typeahead tests', function () {
232232
this.message = function() {
233233
return "Expected '" + angular.mock.dump(this.actual) + "' to be opened.";
234234
};
235-
return typeaheadEl.hasClass('open') && liEls.length === noOfMatches && $(liEls[activeIdx]).hasClass('active');
235+
return typeaheadEl.css('display')==='block' && liEls.length === noOfMatches && $(liEls[activeIdx]).hasClass('active');
236236
}
237237
});
238238
});
@@ -391,12 +391,11 @@ describe('typeahead tests', function () {
391391
var inputEl = findInput(element);
392392

393393
changeInputValueTo(element, 'b');
394-
var dropdown = findDropDown(element);
395394

396395
$document.find('body').click();
397396
$scope.$digest();
398397

399-
expect(dropdown).not.toHaveClass('open');
398+
expect(element).toBeClosed();
400399
});
401400
});
402401

src/typeahead/typeahead.js

+20-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
angular.module('ui.bootstrap.typeahead', [])
1+
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
22

33
/**
44
* A helper service that can parse typeahead's syntax (string provided by users)
@@ -29,8 +29,7 @@ angular.module('ui.bootstrap.typeahead', [])
2929
};
3030
}])
3131

32-
//options - min length
33-
.directive('typeahead', ['$compile', '$parse', '$q', '$document', 'typeaheadParser', function ($compile, $parse, $q, $document, typeaheadParser) {
32+
.directive('typeahead', ['$compile', '$parse', '$q', '$document', '$position', 'typeaheadParser', function ($compile, $parse, $q, $document, $position, typeaheadParser) {
3433

3534
var HOT_KEYS = [9, 13, 27, 38, 40];
3635

@@ -51,6 +50,16 @@ angular.module('ui.bootstrap.typeahead', [])
5150

5251
var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
5352

53+
//pop-up element used to display matches
54+
var popUpEl = angular.element(
55+
"<typeahead-popup " +
56+
"matches='matches' " +
57+
"active='activeIdx' " +
58+
"select='select(activeIdx)' "+
59+
"query='query' "+
60+
"position='position'>"+
61+
"</typeahead-popup>");
62+
5463
//create a child scope for the typeahead directive so we are not polluting original scope
5564
//with typeahead-specific data (matches, query etc.)
5665
var scope = originalScope.$new();
@@ -87,6 +96,11 @@ angular.module('ui.bootstrap.typeahead', [])
8796
}
8897

8998
scope.query = inputValue;
99+
//position pop-up with matches - we need to re-calculate its position each time we are opening a window
100+
//with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
101+
//due to other elements being rendered
102+
scope.position = $position.position(element);
103+
scope.position.top = scope.position.top + element.prop('offsetHeight');
90104

91105
} else {
92106
resetMatches();
@@ -167,15 +181,12 @@ angular.module('ui.bootstrap.typeahead', [])
167181
}
168182
});
169183

170-
$document.find('body').bind('click', function(){
171-
184+
$document.bind('click', function(){
172185
resetMatches();
173186
scope.$digest();
174187
});
175188

176-
var tplElCompiled = $compile("<typeahead-popup matches='matches' active='activeIdx' select='select(activeIdx)' "+
177-
"query='query'></typeahead-popup>")(scope);
178-
element.after(tplElCompiled);
189+
element.after($compile(popUpEl)(scope));
179190
}
180191
};
181192

@@ -188,6 +199,7 @@ angular.module('ui.bootstrap.typeahead', [])
188199
matches:'=',
189200
query:'=',
190201
active:'=',
202+
position:'=',
191203
select:'&'
192204
},
193205
replace:true,

template/typeahead/typeahead.html

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
<div class="dropdown clearfix" ng-class="{open: isOpen()}">
2-
<ul class="typeahead dropdown-menu">
3-
<li ng-repeat="match in matches" ng-class="{active: isActive($index) }" ng-mouseenter="selectActive($index)">
4-
<a tabindex="-1" ng-click="selectMatch($index)" ng-bind-html-unsafe="match.label | typeaheadHighlight:query"></a>
5-
</li>
6-
</ul>
7-
</div>
1+
<ul class="typeahead dropdown-menu" ng-style="{display: isOpen()&&'block' || 'none', top: position.top+'px', left: position.left+'px'}">
2+
<li ng-repeat="match in matches" ng-class="{active: isActive($index) }" ng-mouseenter="selectActive($index)">
3+
<a tabindex="-1" ng-click="selectMatch($index)" ng-bind-html-unsafe="match.label | typeaheadHighlight:query"></a>
4+
</li>
5+
</ul>

0 commit comments

Comments
 (0)