Skip to content

Commit e7dfb8c

Browse files
committed
fix(uiGrid): Wait for grid to get dimensions
If the grid has no width initially, wait for up to 2 seconds for the grid to be shown and have dimensions. Once that happens it will re-initialize its height and width and redraw the canvas. This should fix the problems with the grid taking up too much space in a modal. BREAKING CHANGE: gridUtil will no longer calculate dimensions of hidden elements
1 parent 76029e7 commit e7dfb8c

File tree

7 files changed

+205
-108
lines changed

7 files changed

+205
-108
lines changed

Diff for: misc/demo/modal.html

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<!DOCTYPE html>
2+
<html ng-app="app">
3+
4+
<head>
5+
<link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
6+
<script data-require="[email protected]" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
7+
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
8+
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-touch.js"></script>
9+
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-animate.js"></script>
10+
<script data-require="ui-bootstrap@*" data-semver="0.12.1" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.1.min.js"></script>
11+
<script src="http://ui-grid.info/docs/grunt-scripts/csv.js"></script>
12+
<script src="http://ui-grid.info/docs/grunt-scripts/pdfmake.js"></script>
13+
<script src="http://ui-grid.info/docs/grunt-scripts/vfs_fonts.js"></script>
14+
<script src="/dist/release/ui-grid.js"></script>
15+
<link rel="stylesheet" href="/dist/release/ui-grid.css" type="text/css" />
16+
<style type="text/css">
17+
.grid {
18+
width: 100%;
19+
max-width: 600px;
20+
height: 400px;
21+
}
22+
23+
body {
24+
padding: 20px;
25+
}
26+
</style>
27+
</head>
28+
29+
<body>
30+
<div ng-controller="MainCtrl">
31+
<button ng-click="openModal()" class="btn btn-success">Open Modal</button>
32+
</div>
33+
34+
<script>
35+
var app = angular.module('app', ['ui.grid', 'ui.bootstrap']);
36+
37+
app.controller('MainCtrl', function ($scope, $modal) {
38+
$scope.openModal = function () {
39+
$modal.open({
40+
templateUrl: 'modal.html'
41+
});
42+
}
43+
});
44+
45+
app.controller('ModalDemoCtrl', function ($scope, $http) {
46+
$scope.gridOptions = {};
47+
48+
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500_complex.json')
49+
.success(function(data) {
50+
$scope.gridOptions.data = data;
51+
});
52+
});
53+
</script>
54+
55+
<script type="text/ng-template" id="modal.html">
56+
<div ng-controller="ModalDemoCtrl">
57+
<div class="modal-header">
58+
<h3 class="modal-title">I'm a modal!</h3>
59+
</div>
60+
<div class="modal-body">
61+
<div id="grid1" ui-grid="gridOptions" class="grid"></div>
62+
</div>
63+
<div class="modal-footer">
64+
<button class="btn btn-warning" ng-click="$close()">Cancel</button>
65+
</div>
66+
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
67+
</div>
68+
</script>
69+
</body>
70+
</html>

Diff for: src/js/core/directives/ui-grid.js

+125-101
Original file line numberDiff line numberDiff line change
@@ -160,124 +160,148 @@
160160
</file>
161161
</example>
162162
*/
163-
angular.module('ui.grid').directive('uiGrid',
164-
[
165-
'$compile',
166-
'$templateCache',
167-
'gridUtil',
168-
'$window',
169-
'uiGridConstants',
170-
function(
171-
$compile,
172-
$templateCache,
173-
gridUtil,
174-
$window,
175-
uiGridConstants
176-
) {
163+
angular.module('ui.grid').directive('uiGrid', uiGridDirective);
164+
165+
uiGridDirective.$inject = ['$compile', '$templateCache', '$timeout', '$window', 'gridUtil', 'uiGridConstants'];
166+
function uiGridDirective($compile, $templateCache, $timeout, $window, gridUtil, uiGridConstants) {
167+
return {
168+
templateUrl: 'ui-grid/ui-grid',
169+
scope: {
170+
uiGrid: '='
171+
},
172+
replace: true,
173+
transclude: true,
174+
controller: 'uiGridController',
175+
compile: function () {
177176
return {
178-
templateUrl: 'ui-grid/ui-grid',
179-
scope: {
180-
uiGrid: '='
181-
},
182-
replace: true,
183-
transclude: true,
184-
controller: 'uiGridController',
185-
compile: function () {
186-
return {
187-
post: function ($scope, $elm, $attrs, uiGridCtrl) {
188-
// gridUtil.logDebug('ui-grid postlink');
189-
190-
var grid = uiGridCtrl.grid;
191-
192-
// Initialize scrollbars (TODO: move to controller??)
193-
uiGridCtrl.scrollbars = [];
194-
195-
//todo: assume it is ok to communicate that rendering is complete??
196-
grid.renderingComplete();
197-
198-
grid.element = $elm;
199-
200-
grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
201-
202-
// Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
203-
grid.canvasWidth = uiGridCtrl.grid.gridWidth;
204-
205-
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
206-
207-
// If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
208-
if (grid.gridHeight < grid.options.rowHeight && grid.options.enableMinHeightCheck) {
209-
// Figure out the new height
210-
var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
211-
var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
212-
var footerHeight = grid.calcFooterHeight();
213-
214-
var scrollbarHeight = 0;
215-
if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
216-
scrollbarHeight = gridUtil.getScrollbarWidth();
217-
}
177+
post: function ($scope, $elm, $attrs, uiGridCtrl) {
178+
var grid = uiGridCtrl.grid;
179+
// Initialize scrollbars (TODO: move to controller??)
180+
uiGridCtrl.scrollbars = [];
181+
grid.element = $elm;
218182

219-
var maxNumberOfFilters = 0;
220-
// Calculates the maximum number of filters in the columns
221-
angular.forEach(grid.options.columnDefs, function(col) {
222-
if (col.hasOwnProperty('filter')) {
223-
if (maxNumberOfFilters < 1) {
224-
maxNumberOfFilters = 1;
225-
}
226-
}
227-
else if (col.hasOwnProperty('filters')) {
228-
if (maxNumberOfFilters < col.filters.length) {
229-
maxNumberOfFilters = col.filters.length;
230-
}
231-
}
232-
});
233-
var filterHeight = maxNumberOfFilters * headerHeight;
234183

235-
var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
184+
// See if the grid has a rendered width, if not, wait a bit and try again
185+
var sizeCheckInterval = 100; // ms
186+
var maxSizeChecks = 20; // 2 seconds total
187+
var sizeChecks = 0;
236188

237-
$elm.css('height', newHeight + 'px');
189+
// Setup (event listeners) the grid
190+
setup();
238191

239-
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
240-
}
192+
// And initialize it
193+
init();
241194

242-
// Run initial canvas refresh
243-
grid.refreshCanvas();
195+
// Mark rendering complete so API events can happen
196+
grid.renderingComplete();
244197

245-
//if we add a left container after render, we need to watch and react
246-
$scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
247-
if (newValue === oldValue) {
248-
return;
249-
}
250-
grid.refreshCanvas(true);
251-
});
198+
// If the grid doesn't have size currently, wait for a bit to see if it gets size
199+
checkSize();
252200

253-
//if we add a right container after render, we need to watch and react
254-
$scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
255-
if (newValue === oldValue) {
256-
return;
257-
}
258-
grid.refreshCanvas(true);
259-
});
201+
/*-- Methods --*/
260202

203+
function checkSize() {
204+
// If the grid has no width and we haven't checked more than <maxSizeChecks> times, check again in <sizeCheckInterval> milliseconds
205+
if ($elm[0].offsetWidth <= 0 && sizeChecks < maxSizeChecks) {
206+
setTimeout(checkSize, sizeCheckInterval);
207+
sizeChecks++;
208+
}
209+
else {
210+
$timeout(init);
211+
}
212+
}
261213

262-
// Resize the grid on window resize events
263-
function gridResize($event) {
264-
grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
265-
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
214+
// Setup event listeners and watchers
215+
function setup() {
216+
// Bind to window resize events
217+
angular.element($window).on('resize', gridResize);
266218

267-
grid.refreshCanvas(true);
219+
// Unbind from window resize events when the grid is destroyed
220+
$elm.on('$destroy', function () {
221+
angular.element($window).off('resize', gridResize);
222+
});
223+
224+
// If we add a left container after render, we need to watch and react
225+
$scope.$watch(function () { return grid.hasLeftContainer();}, function (newValue, oldValue) {
226+
if (newValue === oldValue) {
227+
return;
268228
}
229+
grid.refreshCanvas(true);
230+
});
269231

270-
angular.element($window).on('resize', gridResize);
232+
// If we add a right container after render, we need to watch and react
233+
$scope.$watch(function () { return grid.hasRightContainer();}, function (newValue, oldValue) {
234+
if (newValue === oldValue) {
235+
return;
236+
}
237+
grid.refreshCanvas(true);
238+
});
239+
}
271240

272-
// Unbind from window resize events when the grid is destroyed
273-
$elm.on('$destroy', function () {
274-
angular.element($window).off('resize', gridResize);
275-
});
241+
// Initialize the directive
242+
function init() {
243+
grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
244+
245+
// Default canvasWidth to the grid width, in case we don't get any column definitions to calculate it from
246+
grid.canvasWidth = uiGridCtrl.grid.gridWidth;
247+
248+
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
249+
250+
// If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
251+
if (grid.gridHeight < grid.options.rowHeight && grid.options.enableMinHeightCheck) {
252+
autoAdjustHeight();
253+
}
254+
255+
// Run initial canvas refresh
256+
grid.refreshCanvas(true);
257+
}
258+
259+
// Set the grid's height ourselves in the case that its height would be unusably small
260+
function autoAdjustHeight() {
261+
// Figure out the new height
262+
var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
263+
var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
264+
var footerHeight = grid.calcFooterHeight();
265+
266+
var scrollbarHeight = 0;
267+
if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
268+
scrollbarHeight = gridUtil.getScrollbarWidth();
276269
}
277-
};
270+
271+
var maxNumberOfFilters = 0;
272+
// Calculates the maximum number of filters in the columns
273+
angular.forEach(grid.options.columnDefs, function(col) {
274+
if (col.hasOwnProperty('filter')) {
275+
if (maxNumberOfFilters < 1) {
276+
maxNumberOfFilters = 1;
277+
}
278+
}
279+
else if (col.hasOwnProperty('filters')) {
280+
if (maxNumberOfFilters < col.filters.length) {
281+
maxNumberOfFilters = col.filters.length;
282+
}
283+
}
284+
});
285+
var filterHeight = maxNumberOfFilters * headerHeight;
286+
287+
var newHeight = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight;
288+
289+
$elm.css('height', newHeight + 'px');
290+
291+
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
292+
}
293+
294+
// Resize the grid on window resize events
295+
function gridResize($event) {
296+
grid.gridWidth = $scope.gridWidth = gridUtil.elementWidth($elm);
297+
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
298+
299+
grid.refreshCanvas(true);
300+
}
278301
}
279302
};
280303
}
281-
]);
304+
};
305+
}
282306

283307
})();

Diff for: src/js/core/directives/ui-pinned-container.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
}
3434

3535
return width;
36-
}
36+
}
3737
}
3838

3939
function updateContainerDimensions() {

Diff for: src/js/core/services/ui-grid-util.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
106106
function getWidthOrHeight( elem, name, extra ) {
107107
// Start with offset property, which is equivalent to the border-box value
108108
var valueIsBorderBox = true,
109-
val,
109+
val, // = name === 'width' ? elem.offsetWidth : elem.offsetHeight,
110110
styles = getStyles(elem),
111111
isBorderBox = styles['boxSizing'] === 'border-box';
112112

@@ -173,6 +173,8 @@ module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateC
173173
function ($log, $window, $document, $http, $templateCache, $timeout, $injector, $q, $interpolate, uiGridConstants) {
174174
var s = {
175175

176+
augmentWidthOrHeight: augmentWidthOrHeight,
177+
176178
getStyles: getStyles,
177179

178180
/**
@@ -786,8 +788,8 @@ module.service('gridUtil', ['$log', '$window', '$document', '$http', '$templateC
786788
if (e) {
787789
var styles = getStyles(e);
788790
return e.offsetWidth === 0 && rdisplayswap.test(styles.display) ?
789-
s.fakeElement(e, cssShow, function(newElm) {
790-
return getWidthOrHeight( newElm, name, extra );
791+
s.swap(e, cssShow, function() {
792+
return getWidthOrHeight(e, name, extra );
791793
}) :
792794
getWidthOrHeight( e, name, extra );
793795
}

Diff for: src/less/header.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
.ui-grid-header {
99
border-bottom: 1px solid @borderColor;
10-
box-sizing: content-box;
10+
box-sizing: border-box;
1111
}
1212

1313
.ui-grid-top-panel {

Diff for: src/less/menu.less

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
overflow: hidden;
2929
padding: 0 10px 20px 10px;
3030
cursor: pointer;
31-
box-sizing: content-box;
31+
box-sizing: border-box;
3232
}
3333

3434
.ui-grid-menu .ui-grid-menu-inner {

Diff for: test/unit/core/services/ui-grid-util.spec.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ describe('ui.grid.utilService', function() {
199199
expect(w).toEqual(300);
200200
});
201201

202-
it('should work with hidden element', function() {
202+
// Width is no longer calculated for hidden elements
203+
xit('should work with hidden element', function() {
203204
angular.element(elm).remove();
204205

205206
elm = document.createElement('div');

0 commit comments

Comments
 (0)