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

Commit c66a262

Browse files
author
Stefan Zollinger
committed
fix(uiSelectCtrl): properly calculate container width
- Account for paddings on input container in case box-sizing: border-box is set. - Added some tests for this case Closes #1980.
1 parent 2b0b17b commit c66a262

File tree

3 files changed

+80
-5
lines changed

3 files changed

+80
-5
lines changed

src/common.js

+20
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,24 @@ var uis = angular.module('ui.select', [])
172172
left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
173173
};
174174
};
175+
}])
176+
177+
/**
178+
* Gets an elements inner width (width minus padding)
179+
*/
180+
.factory('uisElementInnerWidth',
181+
['$window',
182+
function ($window) {
183+
return $window.jQuery ? getInnerWidthJQuery : getInnerWidth;
184+
185+
function getInnerWidthJQuery(element) {
186+
return element.width();
187+
}
188+
189+
function getInnerWidth(element) {
190+
var style = $window.getComputedStyle(element[0]);
191+
var paddingLeft = parseFloat(style.getPropertyValue('padding-left'));
192+
var paddingRight = parseFloat(style.getPropertyValue('padding-right'));
193+
return element[0].clientWidth - paddingLeft - paddingRight;
194+
}
175195
}]);

src/uiSelectController.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
* put as much logic in the controller (instead of the link functions) as possible so it can be easily tested.
66
*/
77
uis.controller('uiSelectCtrl',
8-
['$scope', '$element', '$timeout', '$filter', '$$uisDebounce', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window',
9-
function($scope, $element, $timeout, $filter, $$uisDebounce, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window) {
8+
['$scope', '$element', '$timeout', '$filter', '$$uisDebounce', 'uisRepeatParser', 'uiSelectMinErr', 'uiSelectConfig', '$parse', '$injector', '$window', 'uisElementInnerWidth',
9+
function($scope, $element, $timeout, $filter, $$uisDebounce, RepeatParser, uiSelectMinErr, uiSelectConfig, $parse, $injector, $window, uisElementInnerWidth) {
1010

1111
var ctrl = this;
1212

@@ -534,10 +534,9 @@ uis.controller('uiSelectCtrl',
534534
ctrl.sizeSearchInput = function() {
535535

536536
var input = ctrl.searchInput[0],
537-
container = ctrl.$element[0],
538537
calculateContainerWidth = function() {
539538
// Return the container width only if the search input is visible
540-
return container.clientWidth * !!input.offsetParent;
539+
return uisElementInnerWidth(ctrl.$element) * !!input.offsetParent;
541540
},
542541
updateIfVisible = function(containerWidth) {
543542
if (containerWidth === 0) {
@@ -549,7 +548,7 @@ uis.controller('uiSelectCtrl',
549548
return true;
550549
};
551550

552-
ctrl.searchInput.css('width', '10px');
551+
ctrl.searchInput.css('width', '50px');
553552
$timeout(function() { //Give tags time to render correctly
554553
if (sizeWatch === null && !updateIfVisible(calculateContainerWidth())) {
555554
sizeWatch = $scope.$watch(function() {

test/select.spec.js

+56
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,62 @@ describe('ui-select tests', function () {
20602060

20612061
});
20622062

2063+
it('input size should properly account for container paddings if box-sizing is set to border-box', function () {
2064+
var el = createUiSelectMultiple({
2065+
tagging: '',
2066+
taggingLabel: 'false'
2067+
});
2068+
2069+
angular.element(document.body).append(el);
2070+
// Set fixed match item width for easier testing
2071+
var style = $(
2072+
'<style> \
2073+
* { box-sizing: border-box; } \
2074+
.ui-select-container { position: relative; } \
2075+
.ui-select-container > div { font-size: 0; } \
2076+
.ui-select-container > div > span, \
2077+
.ui-select-container > div > input { font-size: 14px; } \
2078+
.ui-select-search { border: 0; } \
2079+
.ui-select-match-item { display: inline-block; overflow: hidden; width: 260px; white-space: nowrap; } \
2080+
.ui-select-search { outline: 0; border: 0; margin: 0; padding: 0; } \
2081+
</style>'
2082+
);
2083+
2084+
$('head').append(style);
2085+
2086+
var searchInput = el.find('.ui-select-search');
2087+
2088+
el.css({
2089+
paddingLeft: '6px',
2090+
paddingRight: '6px'
2091+
});
2092+
2093+
$timeout.flush();
2094+
2095+
var fullWidth = searchInput.outerWidth();
2096+
var matchItemWidth = 260;
2097+
2098+
expect(searchInput.outerWidth()).toBe(el.width() - 6); // Full width minus padding due to nested div
2099+
2100+
clickItem(el, 'Wladimir');
2101+
$timeout.flush();
2102+
// 1 items selected, input should be less than full width minus the invisible text node and one item with
2103+
expect(searchInput.outerWidth()).toBe(fullWidth - matchItemWidth ); // remaining width of the row
2104+
2105+
clickItem(el, 'Samantha');
2106+
$timeout.flush();
2107+
// Input should be smaller than before
2108+
expect(searchInput.outerWidth()).toBe(fullWidth - (2 * matchItemWidth));
2109+
2110+
clickItem(el, 'Adrian');
2111+
$timeout.flush();
2112+
// Minimum input width is 50px, we should be on a new line now
2113+
expect(searchInput.outerWidth()).toBe(fullWidth);
2114+
2115+
el.remove();
2116+
style.remove();
2117+
});
2118+
20632119
it('should update size of search input use container width', function () {
20642120
scope.selection.selectedMultiple = [scope.people[4], scope.people[5]]; //Wladimir & Samantha
20652121
var el = createUiSelectMultiple({

0 commit comments

Comments
 (0)