Skip to content

Commit 6c64e8e

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 angular-ui#1980.
1 parent 2b0b17b commit 6c64e8e

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

src/common.js

Lines changed: 20 additions & 0 deletions
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

Lines changed: 3 additions & 4 deletions
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) {

test/select.spec.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,52 @@ describe('ui-select tests', function () {
20602060

20612061
});
20622062

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

0 commit comments

Comments
 (0)