Reputation: 383
I created a custom <select>
dropdown element using a directive, and one aspect of its behavior is automatic sizing, where the element is fit to one of three sizes depending on how wide its widest option is.
However, because the options are populated in the compile
function based on data from the controller, I cannot determine the width of the option list until later, in a pre- or post-link function, but the only way I've been able to check the width was by waiting for the list to be populated through nesting my post-link function in a 0-ms timer.
This was the solution I found through various resources, but I feel there might be a more elegant way?
Here is my directive's code:
.directive('slidingSelect', function($timeout) {
return {
restrict: 'E',
compile: function(element, attrs) {
var selecting = attrs.selecting;
// ng-repeated options come from selecting attr
var dropDownList = $('<div class="sliding-select-list"></div>');
dropDownList.append('<div class="sliding-select-option" ng-repeat="item'+
' in home.'+selecting+'.options">{{item.name}}</div>');
element.append(dropDownList);
element.click(
// Function to slide up/down the list as necessary
function() {
/* omitted */
});
// With compile defined, can return post-link functions
return function(scope, element, attrs) {
$timeout(function() {
var list = element.find('.sliding-select-list');
var options = list.children();
// Find natural width of list, set data-width, then list to match
var listWidth = list.width();
element.attr('data-width', (listWidth>180?'large':(listWidth>100?'medium':'small')));
// Hide list
element.addClass('closed');
}, 0);
};
}
};
Upvotes: 4
Views: 562
Reputation: 3186
When javascript is running, the browser pauses rendering of the DOM until the javascript execution has completed. So when you add the element to the DOM, the browser knows that it has new items to draw and that it has to repaint the screen, but it can't do it until the javascript finishes executing.
What setting a timeout does is it lets the browser regain control before calling any functions registered for timeouts, thus allowing it to repaint the screen and calculate the width of your options list before it runs your timeout code.
I'm sure it's much more complicated than how I have described, but thinking about it this way has helped me to better understand how javascript and the DOM work together.
I can't think of a better way of doing what you are trying to do. That's how I have always done it.
Upvotes: 1