diff --git a/src/typeahead/test/typeahead.spec.js b/src/typeahead/test/typeahead.spec.js index e2c3eebf64..746a5a2854 100644 --- a/src/typeahead/test/typeahead.spec.js +++ b/src/typeahead/test/typeahead.spec.js @@ -200,7 +200,7 @@ describe('typeahead tests', function () { }; var findDropDown = function(element) { - return element.find('div.dropdown'); + return element.find('ul.typeahead'); }; var findMatches = function(element) { @@ -222,7 +222,7 @@ describe('typeahead tests', function () { this.message = function() { return "Expected '" + angular.mock.dump(this.actual) + "' to be closed."; }; - return !typeaheadEl.hasClass('open') && findMatches(this.actual).length === 0; + return typeaheadEl.css('display')==='none' && findMatches(this.actual).length === 0; }, toBeOpenWithActive: function(noOfMatches, activeIdx) { @@ -232,7 +232,7 @@ describe('typeahead tests', function () { this.message = function() { return "Expected '" + angular.mock.dump(this.actual) + "' to be opened."; }; - return typeaheadEl.hasClass('open') && liEls.length === noOfMatches && $(liEls[activeIdx]).hasClass('active'); + return typeaheadEl.css('display')==='block' && liEls.length === noOfMatches && $(liEls[activeIdx]).hasClass('active'); } }); }); @@ -391,12 +391,11 @@ describe('typeahead tests', function () { var inputEl = findInput(element); changeInputValueTo(element, 'b'); - var dropdown = findDropDown(element); $document.find('body').click(); $scope.$digest(); - expect(dropdown).not.toHaveClass('open'); + expect(element).toBeClosed(); }); }); diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 901f4ccbaa..6bb4ad3eaf 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -1,4 +1,4 @@ -angular.module('ui.bootstrap.typeahead', []) +angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position']) /** * A helper service that can parse typeahead's syntax (string provided by users) @@ -29,8 +29,7 @@ angular.module('ui.bootstrap.typeahead', []) }; }]) - //options - min length - .directive('typeahead', ['$compile', '$parse', '$q', '$document', 'typeaheadParser', function ($compile, $parse, $q, $document, typeaheadParser) { + .directive('typeahead', ['$compile', '$parse', '$q', '$document', '$position', 'typeaheadParser', function ($compile, $parse, $q, $document, $position, typeaheadParser) { var HOT_KEYS = [9, 13, 27, 38, 40]; @@ -51,6 +50,16 @@ angular.module('ui.bootstrap.typeahead', []) var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop; + //pop-up element used to display matches + var popUpEl = angular.element( + ""+ + ""); + //create a child scope for the typeahead directive so we are not polluting original scope //with typeahead-specific data (matches, query etc.) var scope = originalScope.$new(); @@ -87,6 +96,11 @@ angular.module('ui.bootstrap.typeahead', []) } scope.query = inputValue; + //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 = $position.position(element); + scope.position.top = scope.position.top + element.prop('offsetHeight'); } else { resetMatches(); @@ -167,15 +181,12 @@ angular.module('ui.bootstrap.typeahead', []) } }); - $document.find('body').bind('click', function(){ - + $document.bind('click', function(){ resetMatches(); scope.$digest(); }); - var tplElCompiled = $compile("")(scope); - element.after(tplElCompiled); + element.after($compile(popUpEl)(scope)); } }; @@ -188,6 +199,7 @@ angular.module('ui.bootstrap.typeahead', []) matches:'=', query:'=', active:'=', + position:'=', select:'&' }, replace:true, diff --git a/template/typeahead/typeahead.html b/template/typeahead/typeahead.html index 8d4a6908b5..d535f0e438 100644 --- a/template/typeahead/typeahead.html +++ b/template/typeahead/typeahead.html @@ -1,7 +1,5 @@ - \ No newline at end of file + \ No newline at end of file