2
votes

Currently I have external filters for my ui-grid but have enableFiltering: true so I can still utilize the filter property on my columns (maybe this is wrong, I don't know, but the ui-grid filtering API works well so I don't want to screw with it).

The problem with this is that the enableFiltering property also controls the visibility of the Clear All Filters menu option for the grid.

I've tried using uiGridGridMenuService.removeFromGridMenu(grid, id) to unregister the menu option, but this won't work when the grid is first rendered because the grid.gridMenuScope.menuItems property is not even defined until the user clicks on the grid menu button for the first time. Additionally, this menu item is assigned an id of menuitem-0 instead of some static/unique property so even if it the removal did work - it's not a safe way to remove this. Finally, based on the code below and running the debugger, the getMenuItems call is executed each time the grid menu button is clicked so the clear filter option is added every single time.

It doesn't look like there's any way to 1) prevent this menu option from appearing, short of not using the grid's filtering API, or 2) overriding the menu action.

Here's the directive code for the grid menu button (note the $broadcast event, maybe I can use that? But that's also fragile/hacky):

.directive('uiGridMenuButton', ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 'i18nService',
function (gridUtil, uiGridConstants, uiGridGridMenuService, i18nService) {

  return {
    priority: 0,
    scope: true,
    require: ['^uiGrid'],
    templateUrl: 'ui-grid/ui-grid-menu-button',
    replace: true,

    link: function ($scope, $elm, $attrs, controllers) {
      var uiGridCtrl = controllers[0];

      // For the aria label
      $scope.i18n = {
        aria: i18nService.getSafeText('gridMenu.aria')
      };

      uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);

      $scope.shown = false;

      $scope.toggleMenu = function () {
        if ( $scope.shown ){
          $scope.$broadcast('hide-menu');
          $scope.shown = false;
        } else {
          $scope.menuItems = uiGridGridMenuService.getMenuItems( $scope );
          $scope.$broadcast('show-menu');
          $scope.shown = true;
        }
      };

      $scope.$on('menu-hidden', function() {
        $scope.shown = false;
        gridUtil.focus.bySelector($elm, '.ui-grid-icon-container');
      });
    }
  };    
}]);

And here's the getMenuItems service method:

getMenuItems: function( $scope ) {
  var menuItems = [
    // this is where we add any menu items we want to always include
  ];

  if ( $scope.grid.options.gridMenuCustomItems ){
    if ( !angular.isArray( $scope.grid.options.gridMenuCustomItems ) ){
      gridUtil.logError( 'gridOptions.gridMenuCustomItems must be an array, and is not');
    } else {
      menuItems = menuItems.concat( $scope.grid.options.gridMenuCustomItems );
    }
  }

  var clearFilters = [{
    title: i18nService.getSafeText('gridMenu.clearAllFilters'),
    action: function ($event) {
      $scope.grid.clearAllFilters(undefined, true, undefined);
    },
    shown: function() {
      return $scope.grid.options.enableFiltering;
    },
    order: 100
  }];
  menuItems = menuItems.concat( clearFilters );

  menuItems = menuItems.concat( $scope.registeredMenuItems );

  if ( $scope.grid.options.gridMenuShowHideColumns !== false ){
    menuItems = menuItems.concat( service.showHideColumns( $scope ) );
  }

  menuItems.sort(function(a, b){
    return a.order - b.order;
  });

  return menuItems;
}
3
Was your PR merged? If not, could you add a link to it here in the comments?lebolo
No. I never did a PR because I was waiting on them to respond. Sounds like they never will so I'm just going to make one and cross my fingers. I will try to remember to update this afterwards.icfantv

3 Answers

2
votes

If you don't mind dropping into jQuery, add this to your gridOptions.onRegisterApi function:

// Need the timeout yield to let the grid fully materialize
$timeout(function () {
  $(".ui-grid-menu-button").click(function () {
    $("button.ui-grid-menu-item:contains('Clear all filters')").hide();
  });
});
2
votes

I noticed that Clear All Filters option always has id="menuitem-0", you can do this in css:

#menuitem-0{
    display: none;
}
1
votes

I created my own show/hide columns menu directive. The trick was getting the grid api with a promise. In my controller, I do:

var deferred = $q.defer();
$scope.gridApi = deferred.promise;

$scope.grid = {
    onRegisterApi: function (gridApi) {
        // Timeout is a hack to solve a race condition where api
        // doesn't actually exist when this callback is fired.
        // See: https://github.com/angular-ui/ui-grid/issues/1717
        $timeout(function () {
            deferred.resolve(gridApi);
        }, 0);
    }
}

Then then directive uses the same service that the ui-grid Grid Menu uses:

angular.module('myApp')
    .directive('columnMenu', [
        'uiGridGridMenuService',
        columnMenu
    ]);

function columnMenu (uiGridGridMenuService) {
    return {
        restrict: 'E',
        scope: {
            api: '='
        },
        templateUrl: '/column-menu.html', 
        link: function (scope) {
            scope.toggle = uiGridGridMenuService.toggleColumnVisibility;

            scope.api.then(function (api) {
                scope.columns = api.grid.columns.filter((col) => !col.isRowHeader);
            });
        }
    };
}

In my view I pass the api to my directive and bam! I have my own show/hide columns menu that only contains what I want:

<column-menu api="gridApi"></column-menu>

Here's a complete plunkr.