web-dev-qa-db-fra.com

Angular ui-grid calcule dynamiquement la hauteur de la grille

J'utilise: 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>

Lorsque je code la valeur, comme indiqué ci-dessus, la grille s’étale et tout fonctionne comme prévu.

Cependant, si je fais ce qui suit ...

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

La hauteur est imprimée dans le div et div s'élargit, mais le contenu lui-même ne s'élargit qu'à environ 340 pixels. L'espace laissé est vide, donc au lieu de 25 lignes, je ne vois que 8 points. Je dois faire défiler l'écran vers le bas, alors qu'il reste 400 pixels libres dans la grille. Les fenêtres ui-grid-viewport et ui-grid-canvas n'utilisent pas cet espace ...

Pourquoi l'interface utilisateur ui-grid-viewport ne peut-elle pas utiliser cet espace?

44
Lachezar Raychev

J'utilise ui-grid - v3.0.0-rc.20 Car un le problème de défilement est corrigé lorsque vous atteignez la hauteur maximale du conteneur. Utilisez le module ui.grid.autoResize Pour redimensionner automatiquement la grille de manière dynamique en fonction de vos données. Pour calculer la hauteur de votre grille, utilisez la fonction ci-dessous. Le ui-if Est facultatif pour attendre que vos données soient définies avant le rendu.

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>
76
tony

Une approche plus simple consiste à utiliser css avec la définition dynamique de la valeur minRowsToShow et virtualizationThreshold.

Dans la feuille de style:

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

Dans le code, appelez la fonction ci-dessous chaque fois que vous modifiez votre data dans gridOptions. maxRowToShow est la valeur que vous avez prédéfinie. Dans mon cas d'utilisation, je la règle à 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 ;
}
18
LeOn - Han Li

UPDATE :

Le code HTML a été demandé, je l'ai donc collé ci-dessous.

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

ORIGINAL :

Nous avons pu résoudre correctement ce problème en utilisant CSS sensible (@media) qui définit la hauteur et la largeur en fonction de l’écran. Quelque chose comme (et vous pouvez clairement en ajouter davantage en fonction de vos besoins):

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

La meilleure partie de cette solution est que nous n’avons pas besoin de la gestion des événements de redimensionnement pour surveiller les changements de taille de la grille. Ça fonctionne.

3
icfantv

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

1
Slava

J'aime l'approche de Tony. Cela fonctionne, mais j'ai décidé de mettre en œuvre de manière différente. Voici mes commentaires:

1) J'ai fait quelques tests et en utilisant le style ng, Angular évalue le contenu en style ng, je veux dire la fonction getTableHeight () plus d'une fois. J'ai placé un point d'arrêt dans la fonction getTableHeight () pour analyser cette.

À propos, ui-if a été supprimé. Maintenant, vous avez ng-if intégré.

2) Je préfère écrire un service comme celui-ci:

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;

});

Et ensuite, dans le contrôleur, écrivez ce qui suit:

  angular.module('app',['ui.grid']).controller('AppController', ['uiGridConstants', function(uiGridConstants) {

  ...

  // Execute this when you have $scope.gridData loaded...
  $scope.gridHeight = uiGridService.getGridHeight($scope.gridData);

Et au fichier HTML:

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

Lorsque angular applique le style, il suffit de regarder dans la variable $ scope.gridHeight et non d’évaluer une fonction complète.

3) Si vous voulez calculer dynamiquement la hauteur d'une grille extensible, c'est plus compliqué. Dans ce cas, vous pouvez définir la propriété expandableRowHeight. Cela corrige la hauteur réservée pour chaque sous-réseau.

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

Je suis en retard au match mais j'ai trouvé une solution intéressante. J'ai créé une directive d'attribut personnalisée. Tout ce que vous avez à faire est de transmettre le gridApi et celui-ci calculera automatiquement la hauteur. Il s'abonne également à l'événement de changement de pagination; ainsi, si l'utilisateur change la taille de la page, il sera redimensionné.

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>
1
Jamie Steele

suivant l'approche de @ tony, a changé la fonction getTableHeight () en

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

la grille aurait également une hauteur dynamique par rapport à la hauteur de la fenêtre.

0
cmTanko

l'approche de Tony fonctionne pour moi, mais quand on fait un fichier console.log, la fonction getTableHeight est appelée trop de fois (sort, clic du menu ...)

Je le modifie pour que la hauteur ne soit recalculée que lorsque j’ajoute/supprime des lignes. Note: tableData est le tableau de lignes

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