Skip to content

Commit 6a68e23

Browse files
authored
fix(core): hide Grid Menu Filter/Sort cmd when disabling functionality (#607)
* fix(core): hide Grid Menu Filter/Sort cmd when disabling functionality
1 parent 27a472f commit 6a68e23

File tree

6 files changed

+239
-15
lines changed

6 files changed

+239
-15
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ module.exports = {
6868
```
6969

7070
### Fully Tested with [Jest](https://jestjs.io/) (Unit Tests) - [Cypress](https://www.cypress.io/) (E2E Tests)
71-
Angular-Slickgrid reached **100%** Unit Test Coverage, we are talking about ~10,000 lines of code (+2,600 unit tests) that are now fully tested with [Jest](https://jestjs.io/). There are also over 300 Cypress E2E tests to cover most UI functionalities.
71+
Angular-Slickgrid reached **100%** Unit Test Coverage, we are talking about +10,000 lines of code (+2,700 unit tests) that are now fully tested with [Jest](https://jestjs.io/). There are also over +350 Cypress E2E tests to cover most UI functionalities on nearly all Examples of Angular-Slickgrid.
7272

7373
## Installation
7474
Refer to the **[Wiki - HOWTO Step by Step](https://github.com/ghiscoding/angular-slickgrid/wiki/HOWTO---Step-by-Step)** and/or clone the [Angular-Slickgrid Demos](https://github.com/ghiscoding/angular-slickgrid-demos) repository. Please don't open any issue unless you have followed these steps (from the Wiki), and if any of the steps are incorrect or confusing, then please let me know.

src/app/modules/angular-slickgrid/services/__tests__/filter.service.spec.ts

+40-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import {
99
BackendService,
1010
Column,
1111
CurrentFilter,
12+
GridMenuItem,
1213
GridOption,
1314
FieldType,
15+
MenuCommandItem,
1416
SlickEventHandler,
1517
} from '../../models';
1618
import { Filters } from '../../filters';
@@ -35,6 +37,22 @@ const gridOptionMock = {
3537
preProcess: jest.fn(),
3638
process: jest.fn(),
3739
postProcess: jest.fn(),
40+
},
41+
gridMenu: {
42+
customItems: [{
43+
command: 'clear-filter',
44+
disabled: false,
45+
iconCssClass: 'fa fa-filter mdi mdi-filter-remove-outline',
46+
positionOrder: 50,
47+
title: 'Clear all Filters'
48+
}, {
49+
command: 'toggle-filter',
50+
disabled: false,
51+
hidden: true,
52+
iconCssClass: 'fa fa-random mdi mdi-flip-vertical',
53+
positionOrder: 52,
54+
title: 'Toggle Filter Row'
55+
}]
3856
}
3957
} as GridOption;
4058

@@ -1125,15 +1143,25 @@ describe('FilterService', () => {
11251143
});
11261144

11271145
it('should disable the Filter Functionality from the Grid Options & toggle the Header Filter row', () => {
1128-
const mockColumns = [{ id: 'field1', field: 'field1', width: 100 }, { id: 'field2', field: 'field2', width: 100 }];
1146+
const mockColumns = [
1147+
{ id: 'field1', field: 'field1', width: 100, header: { menu: { items: [{ command: 'clear-filter' }] } } },
1148+
{ id: 'field2', field: 'field2', width: 100, header: { menu: { items: [{ command: 'clear-filter' }] } } }
1149+
];
11291150
const setOptionSpy = jest.spyOn(gridStub, 'setOptions');
11301151
const setHeaderSpy = jest.spyOn(gridStub, 'setHeaderRowVisibility');
11311152
const setColsSpy = jest.spyOn(gridStub, 'setColumns');
1153+
jest.spyOn(gridStub, 'getColumns').mockReturnValue(mockColumns);
11321154
jest.spyOn(SharedService.prototype, 'columnDefinitions', 'get').mockReturnValue(mockColumns)
11331155

11341156
service.init(gridStub);
11351157
service.disableFilterFunctionality();
11361158

1159+
mockColumns.forEach(col => col.header.menu.items.forEach(item => {
1160+
expect((item as MenuCommandItem).hidden).toBeTruthy();
1161+
}));
1162+
gridOptionMock.gridMenu.customItems.forEach(item => {
1163+
expect((item as GridMenuItem).hidden).toBeTruthy();
1164+
});
11371165
expect(setOptionSpy).toHaveBeenCalledWith({ enableFiltering: false }, false, true);
11381166
expect(setHeaderSpy).toHaveBeenCalledWith(false);
11391167
expect(setColsSpy).toHaveBeenCalledWith(mockColumns);
@@ -1143,15 +1171,25 @@ describe('FilterService', () => {
11431171
gridOptionMock.enableFiltering = false;
11441172
gridOptionMock.showHeaderRow = false;
11451173

1146-
const mockColumns = [{ id: 'field1', field: 'field1', width: 100 }, { id: 'field2', field: 'field2', width: 100 }];
1174+
const mockColumns = [
1175+
{ id: 'field1', field: 'field1', width: 100, header: { menu: { items: [{ command: 'clear-filter' }] } } },
1176+
{ id: 'field2', field: 'field2', width: 100, header: { menu: { items: [{ command: 'clear-filter' }] } } }
1177+
];
11471178
const setOptionSpy = jest.spyOn(gridStub, 'setOptions');
11481179
const setHeaderSpy = jest.spyOn(gridStub, 'setHeaderRowVisibility');
11491180
const setColsSpy = jest.spyOn(gridStub, 'setColumns');
1181+
jest.spyOn(gridStub, 'getColumns').mockReturnValue(mockColumns);
11501182
jest.spyOn(SharedService.prototype, 'columnDefinitions', 'get').mockReturnValue(mockColumns)
11511183

11521184
service.init(gridStub);
11531185
service.disableFilterFunctionality(false);
11541186

1187+
mockColumns.forEach(col => col.header.menu.items.forEach(item => {
1188+
expect((item as MenuCommandItem).hidden).toBeFalsy();
1189+
}));
1190+
gridOptionMock.gridMenu.customItems.forEach(item => {
1191+
expect((item as GridMenuItem).hidden).toBeFalsy();
1192+
});
11551193
expect(setOptionSpy).toHaveBeenCalledWith({ enableFiltering: true }, false, true);
11561194
expect(setHeaderSpy).toHaveBeenCalledWith(true);
11571195
expect(setColsSpy).toHaveBeenCalledWith(mockColumns);

src/app/modules/angular-slickgrid/services/__tests__/sort.service.spec.ts

+26-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
CurrentSorter,
88
EmitterType,
99
FieldType,
10+
GridMenuItem,
1011
GridOption,
1112
MenuCommandItem,
1213
SlickEventHandler,
@@ -29,6 +30,16 @@ const gridOptionMock = {
2930
preProcess: jest.fn(),
3031
process: jest.fn(),
3132
postProcess: jest.fn(),
33+
},
34+
gridMenu: {
35+
customItems: [{
36+
command: 'clear-sorting',
37+
disabled: false,
38+
hidden: true,
39+
iconCssClass: 'fa fa-unsorted mdi mdi-swap-vertical',
40+
positionOrder: 51,
41+
title: 'Clear all Sorting'
42+
}]
3243
}
3344
} as GridOption;
3445

@@ -563,11 +574,14 @@ describe('SortService', () => {
563574
expect(clearSpy).toHaveBeenCalled();
564575
expect(unsubscribeSpy).toHaveBeenCalled();
565576
mockColumns.forEach(col => {
566-
expect(col.sortable).toBeFalse();
577+
expect(col.sortable).toBeFalsy();
567578
});
568579
mockColumns.forEach(col => col.header.menu.items.forEach(item => {
569-
expect((item as MenuCommandItem).hidden).toBeTrue();
580+
expect((item as MenuCommandItem).hidden).toBeTruthy();
570581
}));
582+
gridOptionMock.gridMenu.customItems.forEach(item => {
583+
expect((item as GridMenuItem).hidden).toBeTruthy();
584+
});
571585
});
572586

573587
it('should disable Sort functionality when passing True as 1st argument and False as 2nd argument SHOULD NOT trigger an event', () => {
@@ -581,11 +595,14 @@ describe('SortService', () => {
581595
expect(clearSpy).not.toHaveBeenCalled();
582596
expect(unsubscribeSpy).toHaveBeenCalled();
583597
mockColumns.forEach(col => {
584-
expect(col.sortable).toBeFalse();
598+
expect(col.sortable).toBeFalsy();
585599
});
586600
mockColumns.forEach(col => col.header.menu.items.forEach(item => {
587-
expect((item as MenuCommandItem).hidden).toBeTrue();
601+
expect((item as MenuCommandItem).hidden).toBeTruthy();
588602
}));
603+
gridOptionMock.gridMenu.customItems.forEach(item => {
604+
expect((item as GridMenuItem).hidden).toBeTruthy();
605+
});
589606
});
590607

591608
it('should enable Sort functionality when passing False as 1st argument', (done) => {
@@ -597,11 +614,14 @@ describe('SortService', () => {
597614
gridStub.onSort.notify({ multiColumnSort: true, sortCols: [], grid: gridStub }, new Slick.EventData(), gridStub);
598615

599616
mockColumns.forEach(col => {
600-
expect(col.sortable).toBeTrue();
617+
expect(col.sortable).toBeTruthy();
601618
});
602619
mockColumns.forEach(col => col.header.menu.items.forEach(item => {
603-
expect((item as MenuCommandItem).hidden).toBeFalse();
620+
expect((item as MenuCommandItem).hidden).toBeFalsy();
604621
}));
622+
gridOptionMock.gridMenu.customItems.forEach(item => {
623+
expect((item as GridMenuItem).hidden).toBeFalsy();
624+
});
605625

606626
setTimeout(() => {
607627
expect(handleSpy).toHaveBeenCalled();

src/app/modules/angular-slickgrid/services/filter.service.ts

+42
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,11 @@ export class FilterService {
651651
if (clearFiltersWhenDisabled && isFilterDisabled) {
652652
this.clearFilters();
653653
}
654+
this.disableAllFilteringCommands(isFilterDisabled);
654655
this._grid.setOptions({ enableFiltering: newShowFilterFlag }, false, true);
655656
this._grid.setHeaderRowVisibility(newShowFilterFlag);
657+
this._gridOptions.enableFiltering = !isFilterDisabled;
658+
this.sharedService.gridOptions = this._gridOptions;
656659

657660
// when displaying header row, we'll call "setColumns" which in terms will recreate the header row filters
658661
this._grid.setColumns(this.sharedService.columnDefinitions);
@@ -859,6 +862,45 @@ export class FilterService {
859862
}
860863
}
861864

865+
/**
866+
* Loop through all column definitions and do the following thing
867+
* 1. loop through each Header Menu commands and change the "hidden" commands to show/hide depending if it's enabled/disabled
868+
* Also note that we aren't deleting any properties, we just toggle their flags so that we can reloop through at later point in time.
869+
* (if we previously deleted these properties we wouldn't be able to change them back since these properties wouldn't exist anymore, hence why we just hide the commands)
870+
* @param {boolean} isDisabling - are we disabling the filter functionality? Defaults to true
871+
*/
872+
private disableAllFilteringCommands(isDisabling = true): Column[] {
873+
const columnDefinitions = this._grid.getColumns();
874+
875+
// loop through column definition to hide/show header menu commands
876+
columnDefinitions.forEach((col) => {
877+
if (col && col.header && col.header.menu) {
878+
col.header.menu.items.forEach(menuItem => {
879+
if (menuItem && typeof menuItem !== 'string') {
880+
const menuCommand = menuItem.command;
881+
if (menuCommand === 'clear-filter') {
882+
menuItem.hidden = isDisabling;
883+
}
884+
}
885+
});
886+
}
887+
});
888+
889+
// loop through column definition to hide/show grid menu commands
890+
if (this._gridOptions && this._gridOptions.gridMenu && this._gridOptions.gridMenu.customItems) {
891+
this._gridOptions.gridMenu.customItems.forEach((menuItem) => {
892+
if (menuItem && typeof menuItem !== 'string') {
893+
const menuCommand = menuItem.command;
894+
if (menuCommand === 'clear-filter' || menuCommand === 'toggle-filter') {
895+
menuItem.hidden = isDisabling;
896+
}
897+
}
898+
});
899+
}
900+
901+
return columnDefinitions;
902+
}
903+
862904
private updateColumnFilters(searchTerms: SearchTerm[] | undefined, columnDef: any, operator?: OperatorType | OperatorString) {
863905
if (searchTerms && columnDef) {
864906
this._columnFilters[columnDef.id] = {

src/app/modules/angular-slickgrid/services/sort.service.ts

+18-4
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,14 @@ export class SortService {
206206
this.clearSorting();
207207
}
208208
this._eventHandler.unsubscribeAll();
209-
updatedColumnDefinitions = this.disableSortingOnAllColumns(true);
209+
updatedColumnDefinitions = this.disableAllSortingCommands(true);
210210
} else {
211-
updatedColumnDefinitions = this.disableSortingOnAllColumns(false);
211+
updatedColumnDefinitions = this.disableAllSortingCommands(false);
212212
const onSortHandler = this._grid.onSort;
213213
this._eventHandler.subscribe(onSortHandler, (e: Event, args: any) => this.handleLocalOnSort(e, args));
214214
}
215215
this._grid.setOptions({ enableSorting: this._gridOptions.enableSorting }, false, true);
216+
this.sharedService.gridOptions = this._gridOptions;
216217

217218
// reset columns so that it recreate the column headers and remove/add the sort icon hints
218219
// basically without this, the sort icon hints were still showing up even after disabling the Sorting
@@ -527,14 +528,15 @@ export class SortService {
527528
/**
528529
* Loop through all column definitions and do the following 2 things
529530
* 1. disable/enable the "sortable" property of each column
530-
* 2. loop through each Header Menu commands and change the command "hidden" property to enable/disable
531+
* 2. loop through each Header Menu commands and change the "hidden" commands to show/hide depending if it's enabled/disabled
531532
* Also note that we aren't deleting any properties, we just toggle their flags so that we can reloop through at later point in time.
532533
* (if we previously deleted these properties we wouldn't be able to change them back since these properties wouldn't exist anymore, hence why we just hide the commands)
533534
* @param {boolean} isDisabling - are we disabling the sort functionality? Defaults to true
534535
*/
535-
private disableSortingOnAllColumns(isDisabling = true): Column[] {
536+
private disableAllSortingCommands(isDisabling = true): Column[] {
536537
const columnDefinitions = this._grid.getColumns();
537538

539+
// loop through column definition to hide/show header menu commands
538540
columnDefinitions.forEach((col) => {
539541
if (typeof col.sortable !== undefined) {
540542
col.sortable = !isDisabling;
@@ -551,6 +553,18 @@ export class SortService {
551553
}
552554
});
553555

556+
// loop through column definition to hide/show grid menu commands
557+
if (this._gridOptions && this._gridOptions.gridMenu && this._gridOptions.gridMenu.customItems) {
558+
this._gridOptions.gridMenu.customItems.forEach((menuItem) => {
559+
if (menuItem && typeof menuItem !== 'string') {
560+
const menuCommand = menuItem.command;
561+
if (menuCommand === 'clear-sorting') {
562+
menuItem.hidden = isDisabling;
563+
}
564+
}
565+
});
566+
}
567+
554568
return columnDefinitions;
555569
}
556570
}

0 commit comments

Comments
 (0)