问题
I am using : https://github.com/angular-ui/ui-grid.info/tree/gh-pages/release/3.0.0-RC.18
<div ui-grid="gridOptions" style="height:765px"></div>
When I hard code the value, as shown above, the grid spreads out and everything works as expected.
However, if I do the following...
$scope.gridStyle = 'height:'+numRows*rowHeight+'px' //(765px);
<div ui-grid="gridOptions" style="{{gridStyle}}"></div>
The height is printed in the div and div widens but the content itself widens to only around 340px. The space that is left is blank, so instead of 25 rows I see only 8. I have to scroll down, while there is a whole 400px free in the grid. The ui-grid-viewport and ui-grid-canvas are both not using this space...
Why can't the ui-grid-viewport use that space?
回答1:
I use ui-grid - v3.0.0-rc.20
because a scrolling issue is fixed when you go full height of container. Use the ui.grid.autoResize
module will dynamically auto resize the grid to fit your data. To calculate the height of your grid use the function below. The ui-if
is optional to wait until your data is set before rendering.
angular.module('app',['ui.grid','ui.grid.autoResize']).controller('AppController', ['uiGridConstants', function(uiGridConstants) {
...
$scope.gridData = {
rowHeight: 30, // set row height, this is default size
...
};
...
$scope.getTableHeight = function() {
var rowHeight = 30; // your row height
var headerHeight = 30; // your header height
return {
height: ($scope.gridData.data.length * rowHeight + headerHeight) + "px"
};
};
...
<div ui-if="gridData.data.length>0" id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize ng-style="getTableHeight()"></div>
回答2:
A simpler approach is set use css
combined with setting the minRowsToShow
and virtualizationThreshold
value dynamically.
In stylesheet:
.ui-grid, .ui-grid-viewport {
height: auto !important;
}
In code, call the below function every time you change your data
in gridOptions
. maxRowToShow
is the value you pre-defined, for my use case, I set it to 25.
ES5:
setMinRowsToShow(){
//if data length is smaller, we shrink. otherwise we can do pagination.
$scope.gridOptions.minRowsToShow = Math.min($scope.gridOptions.data.length, $scope.maxRowToShow);
$scope.gridOptions.virtualizationThreshold = $scope.gridOptions.minRowsToShow ;
}
回答3:
UPDATE:
The HTML was requested so I've pasted it below.
<div ui-grid="gridOptions" class="my-grid"></div>
ORIGINAL:
We were able to adequately solve this problem by using responsive CSS (@media
) that sets the height and width based on screen real estate. Something like (and clearly you can add more based on your needs):
@media (min-width: 1024px) {
.my-grid {
width: 772px;
}
}
@media (min-width: 1280px) {
.my-grid {
width: 972px;
}
}
@media (min-height: 768px) {
.my-grid {
height: 480px;
}
}
@media (min-height: 900px) {
.my-grid {
height: 615px;
}
}
The best part about this solution is that we need no resize event handling to monitor for grid size changes. It just works.
回答4:
.ui-grid, .ui-grid-viewport,.ui-grid-contents-wrapper, .ui-grid-canvas { height: auto !important; }
回答5:
I like Tony approach. It works, but I decided to implement in different way. Here my comments:
1) I did some tests and when using ng-style, Angular evaluates ng-style content, I mean getTableHeight() function more than once. I put a breakpoint into getTableHeight() function to analyze this.
By the way, ui-if was removed. Now you have ng-if build-in.
2) I prefer to write a service like this:
angular.module('angularStart.services').factory('uiGridService', function ($http, $rootScope) {
var factory = {};
factory.getGridHeight = function(gridOptions) {
var length = gridOptions.data.length;
var rowHeight = 30; // your row height
var headerHeight = 40; // your header height
var filterHeight = 40; // your filter height
return length * rowHeight + headerHeight + filterHeight + "px";
}
factory.removeUnit = function(value, unit) {
return value.replace(unit, '');
}
return factory;
});
And then in the controller write the following:
angular.module('app',['ui.grid']).controller('AppController', ['uiGridConstants', function(uiGridConstants) {
...
// Execute this when you have $scope.gridData loaded...
$scope.gridHeight = uiGridService.getGridHeight($scope.gridData);
And at the HTML file:
<div id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize style="height: {{gridHeight}}"></div>
When angular applies the style, it only has to look in the $scope.gridHeight variable and not to evaluate a complete function.
3) If you want to calculate dynamically the height of an expandable grid, it is more complicated. In this case, you can set expandableRowHeight property. This fixes the reserved height for each subgrid.
$scope.gridData = {
enableSorting: true,
multiSelect: false,
enableRowSelection: true,
showFooter: false,
enableFiltering: true,
enableSelectAll: false,
enableRowHeaderSelection: false,
enableGridMenu: true,
noUnselect: true,
expandableRowTemplate: 'subGrid.html',
expandableRowHeight: 380, // 10 rows * 30px + 40px (header) + 40px (filters)
onRegisterApi: function(gridApi) {
gridApi.expandable.on.rowExpandedStateChanged($scope, function(row){
var height = parseInt(uiGridService.removeUnit($scope.jdeNewUserConflictsGridHeight,'px'));
var changedRowHeight = parseInt(uiGridService.getGridHeight(row.entity.subGridNewUserConflictsGrid, true));
if (row.isExpanded)
{
height += changedRowHeight;
}
else
{
height -= changedRowHeight;
}
$scope.jdeNewUserConflictsGridHeight = height + 'px';
});
},
columnDefs : [
{ field: 'GridField1', name: 'GridField1', enableFiltering: true }
]
}
回答6:
I am late to the game but I found a nice solution. I created a custom attribute directive all you need to do is pass in the gridApi and it will automatically calculate the height. It also subscribes to the pagination change event so if the user changes page size it will resize.
class UIGridAutoResize implements ng.IDirective {
link: (scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => void;
scope: { gridApi: "=" };
restrict = "A";
private previousValue: string;
private isValid: boolean = true;
private watch: any;
constructor($timeout: ng.ITimeoutService) {
UIGridAutoResize.prototype.link = (scope: ng.IScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes) => {
const gridOptions = scope.$eval(attrs.uiGrid) as any;
const gridApi = scope.$eval(attrs.gridResize) as any;
gridApi.core.on.rowsRendered(scope, () => {
$timeout(() => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, false);
}, 100);
});
gridApi.core.on.filterChanged(scope, () => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, false);
});
if (attrs.uiGridPagination === "") {
gridApi.pagination.on.paginationChanged(null, () => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, true);
});
}
angular.element(window).resize(() => {
$timeout(() => {
this.autoSizeGrid(element, attrs, gridOptions, gridApi, false);
}, 100);
});
};
}
static Factory(): ng.IDirectiveFactory {
const directive = ($timeout: ng.ITimeoutService) => {
return new UIGridAutoResize($timeout);
};
directive["$inject"] = ["$timeout"];
return directive;
}
private autoSizeGrid(element: ng.IAugmentedJQuery, attrs: ng.IAttributes, gridOptions: any, gridApi: any, isPaginationChanged: boolean) {
gridApi.core.handleWindowResize();
// Clear empty grid message
angular.element(element.parent()).find("#emptyGridMessage").remove();
element.find(".ui-grid-viewport").css("display", "");
if (attrs.hidePageSize === "") {
element.find(".ui-grid-pager-row-count-picker").css("display", "none");
}
let rowCount = gridApi.core.getVisibleRows().length;
const headerElements = element.find(".ui-grid-header");
let headerHeight = 2;
if (headerElements.length > 1) { // If we have more than one header element the grid is using grouping
const headerElement = angular.element(headerElements[1]);
headerHeight += headerElement.height();
} else {
headerHeight += headerElements.height();
}
if (attrs.uiGridPagination === "") {
if (rowCount < 1) {
gridOptions.enablePagination = false;
gridOptions.enablePaginationControls = false;
element.css("height", (rowCount * 30) + headerHeight - 2);
element.find(".ui-grid-viewport").css("display", "none");
angular.element("<div id='emptyGridMessage' style='font-size: 1em; width: 100%; background-color: white; border: 1px solid #d4d4d4; padding: 7px 12px; color: #707070;'><span style='opacity: 0.95;'>There are no records.</span></div>").insertAfter(element);
} else if (gridApi.core.getVisibleRows().length < gridOptions.paginationPageSize && !isPaginationChanged) {
gridOptions.enablePagination = false;
gridOptions.enablePaginationControls = false;
element.css("height", (rowCount * 30) + headerHeight);
} else {
gridOptions.enablePagination = true;
gridOptions.enablePaginationControls = true;
element.css("height", (rowCount * 30) + headerHeight);
}
} else {
if (rowCount < 1) {
element.css("height", (rowCount * 30) + headerHeight - 2);
element.find(".ui-grid-viewport").css("display", "none");
angular.element("<div id='emptyGridMessage' style='font-size: 1em; width: 100%; background-color: white; border: 1px solid #d4d4d4; padding: 7px 12px; color: #707070;'><span style='opacity: 0.95;'>There are no records.</span></div>").insertAfter(element);
} else {
element.css("height", (rowCount * 30) + headerHeight);
}
}
// Add extra margin to prevent scroll bar and pager from overlapping content underneath
const pagerHeight = element.find(".ui-grid-pager-panel").height();
if (rowCount > 0) {
if (pagerHeight > 0)
element.css("margin-bottom", pagerHeight);
else
element.css("margin-bottom", 10);
} else {
if (pagerHeight > 0)
angular.element(element.parent()).find("#emptyGridMessage").css("margin-bottom", pagerHeight);
else
angular.element(element.parent()).find("#emptyGridMessage").css("margin-bottom", 10);
}
if (rowCount > gridOptions.paginationPageSize) // Sometimes paging shows all rows this fixes that
gridApi.core.refresh();
}
}
<div ui-grid="vm.gridOptions" grid-resize="vm.gridApi" ui-grid-resize-columns ui-grid-pagination></div>
回答7:
tony's approach does work for me but when do a console.log, the function getTableHeight get called too many time(sort, menu click...)
I modify it so the height is recalculated only when i add/remove rows. Note: tableData is the array of rows
$scope.getTableHeight = function() {
var rowHeight = 30; // your row height
var headerHeight = 30; // your header height
return {
height: ($scope.gridData.data.length * rowHeight + headerHeight) + "px"
};
};
$scope.$watchCollection('tableData', function (newValue, oldValue) {
angular.element(element[0].querySelector('.grid')).css($scope.getTableHeight());
});
Html
<div id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize"></div>
回答8:
following @tony's approach, changed the getTableHeight() function to
<div id="grid1" ui-grid="$ctrl.gridOptions" class="grid" ui-grid-auto-resize style="{{$ctrl.getTableHeight()}}"></div>
getTableHeight() {
var offsetValue = 365;
return "height: " + parseInt(window.innerHeight - offsetValue ) + "px!important";
}
the grid would have a dynamic height with regards to window height as well.
来源:https://stackoverflow.com/questions/27837335/angular-ui-grid-dynamically-calculate-height-of-the-grid