diff --git a/src/uiSelectDirective.js b/src/uiSelectDirective.js index 285cfb4ac..a1199269e 100644 --- a/src/uiSelectDirective.js +++ b/src/uiSelectDirective.js @@ -1,6 +1,6 @@ uis.directive('uiSelect', - ['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout', - function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout) { + ['$document', 'uiSelectConfig', 'uiSelectMinErr', 'uisOffset', '$compile', '$parse', '$timeout', '$window', + function($document, uiSelectConfig, uiSelectMinErr, uisOffset, $compile, $parse, $timeout, $window) { return { restrict: 'EA', @@ -206,11 +206,15 @@ uis.directive('uiSelect', $select.clickTriggeredSelect = false; } - // See Click everywhere but here event http://stackoverflow.com/questions/12931369 - $document.on('click', onDocumentClick); + // See Click everywhere but here. Similar approach to http://stackoverflow.com/questions/12931369 + // but using the capture phase instead of bubble phase of the event propagation. + // + // Using the capture phase avoids problems that araise when event.stopPropatagion() + // is called before the event reaches the `document`. + $window.document.addEventListener('click', onDocumentClick, true); scope.$on('$destroy', function() { - $document.off('click', onDocumentClick); + $window.document.removeEventListener('click', onDocumentClick, true); }); // Move transcluded elements to their correct position in main template diff --git a/test/select.spec.js b/test/select.spec.js index c9498bf1e..7f6f6a98f 100644 --- a/test/select.spec.js +++ b/test/select.spec.js @@ -746,6 +746,28 @@ describe('ui-select tests', function () { el2.remove(); }); + it('should close an opened select clicking outside with stopPropagation()', function () { + var el1 = createUiSelect(); + var el2 = $('
'); + el1.appendTo(document.body); + el2.appendTo(document.body); + + el2.on('click', function (e) { + e.stopPropagation() + }); + + expect(isDropdownOpened(el1)).toEqual(false); + clickMatch(el1); + expect(isDropdownOpened(el1)).toEqual(true); + + // Using a native dom click() to make sure the test fails when it should. + el2[0].click(); + + expect(isDropdownOpened(el1)).toEqual(false); + el1.remove(); + el2.remove(); + }); + it('should bind model correctly (with object as source)', function () { var el = compileTemplate( '