【问题标题】:Angular ui-grid dynamically calculate height of the gridAngular ui-grid 动态计算网格的高度
【发布时间】:2018-04-03 05:19:59
【问题描述】:

我正在使用: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>

当我对值进行硬编码时,如上所示,网格展开并且一切都按预期工作。

但是,如果我执行以下操作...

$scope.gridStyle = 'height:'+numRows*rowHeight+'px' //(765px);
<div ui-grid="gridOptions" style="{{gridStyle}}"></div>

高度打印在 div 中并且 div 变宽,但内容本身仅加宽到 340 像素左右。剩下的空间是空白的,所以我只看到 8 行而不是 25 行。我必须向下滚动,而网格中有 400 像素的空闲空间。 ui-grid-viewport 和 ui-grid-canvas 都没有使用这个空间...

为什么 ui-grid-viewport 不能使用该空间?

【问题讨论】:

  • 据我了解,网格不提供动态高度。但是,您可以将 ui-grid-auto-resize 附加到您的网格,它应该尝试使其适合数据。这就是我解决问题的方法(+ 为您的网格提供一种通过函数计算高度的方法,我使用了 ng-class="myStyle()" 其中 myStyle 只是我的 rowheight 和 $scope.gridOptions 之间的乘积。 data.length。希望对您有所帮助!

标签: angularjs angular-ui angular-ui-grid


【解决方案1】:

我使用ui-grid - v3.0.0-rc.20,因为当您到达容器的全高时使用scrolling issue is fixed。使用ui.grid.autoResize 模块将动态自动调整网格大小以适应您的数据。要计算网格的高度,请使用以下函数。 ui-if 是可选的,等待数据设置好后再渲染。

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"
       };
    };
      
    ...
&lt;div ui-if="gridData.data.length&gt;0" id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize ng-style="getTableHeight()"&gt;&lt;/div&gt;

【讨论】:

  • 请注意,使用此方法可能会出现性能问题,因为这会设置一个每 250 毫秒执行一次的计时器,以查看网格大小是否已更改。如果您不想走这条路,请参阅我关于响应式 CSS 的回答。
  • 假设我有一个按钮 onclick,其中添加了一个新的 ui-grid 行,有没有办法让我避免 250 毫秒的计时器执行?
  • 可接受的、有效的解决方案。应该在 ui-grid 手册/教程中。
  • 如果行的高度不是恒定的,有什么解决办法吗?提问者假设高度不变,所以我在这里提出了一个新问题:stackoverflow.com/questions/40311664/…
  • 在@tony 的回答中,函数$scope.getTableHeight 将返回一个对象,我们需要一个字符串,所以return 'height:' + ($scope.gridData.data.length * rowHeight + headerHeight) + 'px'; 效果很好。 ng-style 不适合我,我可以在 html 中使用 style="{{getTableHeight()}}"
【解决方案2】:

一个更简单的方法是设置使用css 结合动态设置minRowsToShowvirtualizationThreshold 值。

在样式表中:

.ui-grid, .ui-grid-viewport {
    height: auto !important;
}

在代码中,每次在gridOptions 中更改data 时调用以下函数。 maxRowToShow 是您预定义的值,对于我的用例,我将其设置为 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 ;
}

【讨论】:

  • 考虑到此修复的简单性,它的效果很好 - 但是有一个错误:如果您需要可扩展的网格,它会破坏嵌套网格上的滚动。
  • 我一直在努力更新页面大小更改的高度。我使用了你的 CSS 并将代码放在你的 setMinRowsToShow()gridApi.pagination.on.paginationChanged 中,对我来说效果很好。
  • 我在更改数据长度时遇到问题stackoverflow.com/questions/45072428/…
  • 这是一个很好的解决方案,因为它不涉及绝对高度。
【解决方案3】:

.ui-grid, .ui-grid-viewport,.ui-grid-contents-wrapper, .ui-grid-canvas { 高度:自动!重要; }

【讨论】:

    【解决方案4】:

    更新

    请求了 HTML,所以我将其粘贴在下面。

    <div ui-grid="gridOptions" class="my-grid"></div>
    

    原创

    我们能够通过使用根据屏幕空间设置高度和宽度的响应式 CSS (@media) 充分解决此问题。类似的东西(显然您可以根据自己的需要添加更多内容):

    @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;
      }
    }
    

    这个解决方案最好的部分是我们不需要调整大小事件处理来监控网格大小的变化。它只是工作。

    【讨论】:

    • 应用到 my-grid 的“样式”不是覆盖了您的课程设置吗?
    • 我不会将任何样式直接应用于我们的网格。我只添加一个类属性。我将更新上面的示例。
    • 我明白了,但事实是 ui.grid 自己设置了一个样式,特别是它设置了它的 height 属性......也许我们有不同的版本或不同的条件......:/跨度>
    • 是的,我不知道。我只知道我们的工作,我不需要使用!important
    【解决方案5】:

    我喜欢 Tony 的方法。它有效,但我决定以不同的方式实施。这是我的cmets:

    1) 我做了一些测试,当使用 ng-style 时,Angular 会评估 ng-style 内容,我的意思是 getTableHeight() 函数不止一次。我在 getTableHeight() 函数中设置了一个断点来分析它。

    顺便说一句,ui-if 已被删除。现在你有 ng-if 内置了。

    2) 我更喜欢这样写一个服务:

    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;
    

    });

    然后在控制器中写入以下内容:

      angular.module('app',['ui.grid']).controller('AppController', ['uiGridConstants', function(uiGridConstants) {
    
      ...
    
      // Execute this when you have $scope.gridData loaded...
      $scope.gridHeight = uiGridService.getGridHeight($scope.gridData);
    

    在 HTML 文件中:

      <div id="grid1" ui-grid="gridData" class="grid" ui-grid-auto-resize style="height: {{gridHeight}}"></div>
    

    当 Angular 应用样式时,它只需要查看 $scope.gridHeight 变量而不是评估完整的函数。

    3) 如果要动态计算可扩展网格的高度,则比较复杂。在这种情况下,您可以设置 expandableRowHeight 属性。这固定了每个子网格的保留高度。

        $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 }
            ]
        }
    

    【讨论】:

    • gridOptions.data.length 结果是字符串的长度而不是数组的长度,在我的例子中是“referenceData.Subscriptions”= 21 个字符。如果将数据属性定义为字符串值,例如` $scope.gridOptions = { enableColumnResizing: true, data: 'referenceData.Subscriptions',`
    【解决方案6】:

    tony 的方法确实对我有用,但是当执行 console.log 时,函数 getTableHeight 被调用太多次(排序,菜单点击...)

    我对其进行了修改,因此只有在我添加/删除行时才会重新计算高度。注意:tableData 是行数组

    $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>
    

    【讨论】:

      【解决方案7】:

      我迟到了,但我找到了一个不错的解决方案。我创建了一个自定义属性指令,您只需传入 gridApi,它就会自动计算高度。它还订阅分页更改事件,因此如果用户更改页面大小,它将调整大小。

      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>
      

      【讨论】:

        【解决方案8】:

        按照@tony 的方法,将getTableHeight() 函数更改为

        <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";
        }
        

        网格在窗口高度方面也将具有动态高度。

        【讨论】:

          猜你喜欢
          • 2017-07-23
          • 1970-01-01
          • 1970-01-01
          • 2017-12-11
          • 1970-01-01
          • 1970-01-01
          • 2017-06-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多