diff --git a/demos/vanilla/src/examples/example03.ts b/demos/vanilla/src/examples/example03.ts
index c40f8043cb..5a774f282b 100644
--- a/demos/vanilla/src/examples/example03.ts
+++ b/demos/vanilla/src/examples/example03.ts
@@ -94,6 +94,7 @@ export default class Example03 {
name: 'Title',
field: 'title',
columnGroup: 'Common Factor',
+ hidden: true, // column initially hidden
sortable: true,
editor: {
model: Editors.longText,
diff --git a/demos/vue/src/components/Example18.vue b/demos/vue/src/components/Example18.vue
index a3fe491226..56d07fdf29 100644
--- a/demos/vue/src/components/Example18.vue
+++ b/demos/vue/src/components/Example18.vue
@@ -54,6 +54,7 @@ function defineGrid() {
width: 70,
minWidth: 50,
cssClass: 'cell-title',
+ hidden: true, // column initially hidden
filterable: true,
sortable: true,
grouping: {
diff --git a/demos/vue/test/cypress/e2e/example18.cy.ts b/demos/vue/test/cypress/e2e/example18.cy.ts
index b9807b0bc8..397df8aa69 100644
--- a/demos/vue/test/cypress/e2e/example18.cy.ts
+++ b/demos/vue/test/cypress/e2e/example18.cy.ts
@@ -1,6 +1,16 @@
describe('Example 18 - Draggable Grouping & Aggregators', () => {
const preHeaders = ['Common Factor', 'Period', 'Analysis', ''];
+ const originalTitles = ['Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven'];
const fullTitles = ['Title', 'Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven'];
+ const gridMenuTitles = [
+ 'Common Factor - Title',
+ 'Common Factor - Duration',
+ 'Period - Start',
+ 'Period - Finish',
+ 'Analysis - Cost',
+ 'Analysis - % Complete',
+ 'Analysis - Effort-Driven',
+ ];
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/example18`);
@@ -18,7 +28,7 @@ describe('Example 18 - Draggable Grouping & Aggregators', () => {
cy.get('#grid18')
.find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .each(($child, index) => expect($child.text()).to.eq(originalTitles[index]));
});
it('should initially be grouped by "Duration" when loading the grid', () => {
@@ -26,6 +36,52 @@ describe('Example 18 - Draggable Grouping & Aggregators', () => {
cy.get('[data-row=1] > .slick-cell:nth(2)').should('contain', '0');
});
+ it('should open Grid Menu and be able to unhide "Title" column', () => {
+ cy.get('button.slick-grid-menu-button').click({ force: true });
+ cy.get('.slick-grid-menu:visible')
+ .find('.slick-column-picker-list')
+ .children('li:visible:nth(0)')
+ .children('label')
+ .should('contain', 'Common Factor - Title');
+ // .click({ force: true });
+
+ cy.get('.slick-column-picker-list input[data-columnid="title"]')
+ .parent('.icon-checkbox-container')
+ .find('.sgi')
+ .should('have.class', 'sgi-icon-picker-uncheck');
+
+ cy.get('.slick-column-picker-list li')
+ .children()
+
+ .each(($child, index) => {
+ if (index <= 5) {
+ expect($child.text()).to.eq(gridMenuTitles[index]);
+ }
+ });
+
+ cy.get('.slick-grid-menu:visible')
+ .find('.slick-column-picker-list')
+ .children('li:visible:nth(0)')
+ .children('label')
+ .should('contain', 'Common Factor - Title')
+ .click();
+
+ cy.get('.slick-column-picker-list input[data-columnid="title"]')
+ .parent('.icon-checkbox-container')
+ .find('.sgi')
+ .should('have.class', 'sgi-icon-picker-check');
+
+ cy.get('#grid18')
+ .find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
+ .children()
+ .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ });
+
+ it('should still be grouped by "Duration"', () => {
+ cy.get('[data-row=0] > .cell-title .slick-group-title').contains(/Duration: [0-9]/);
+ cy.get('[data-row=1] > .slick-cell:nth(2)').should('contain', '0');
+ });
+
it('should clear all groups with "Clear all Grouping" and no longer expect any grouping', () => {
cy.get('[data-test="clear-grouping-btn"]').click();
cy.get('#grid18').find('.slick-group-toggle-all').should('be.hidden');
diff --git a/docs/TOC.md b/docs/TOC.md
index 7006be6762..5724264197 100644
--- a/docs/TOC.md
+++ b/docs/TOC.md
@@ -35,6 +35,7 @@
* [Single Search Filter](column-functionalities/filters/single-search-filter.md)
* [Formatters](column-functionalities/formatters.md)
* [Sorting](column-functionalities/sorting.md)
+* [Visibility](column-functionalities/visibility.md)
## Events
diff --git a/docs/column-functionalities/visibility.md b/docs/column-functionalities/visibility.md
new file mode 100644
index 0000000000..1402c78681
--- /dev/null
+++ b/docs/column-functionalities/visibility.md
@@ -0,0 +1,56 @@
+### Demo
+[Demo](https://ghiscoding.github.io/slickgrid-universal/#/example03) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vanilla/src/examples/example03.ts)
+
+### Description
+
+For column visibility, you can define the `hidden` property in your column definitions to initially hide some columns. You could also toggle the `hidden` property at any point in time (see below for more code usage).
+
+### initially hidden columns
+
+Let's start by demoing how to initially hide some column(s) by using the `hidden` property.
+
+##### define columns
+
+```ts
+this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age', hidden: true }, // column initially hidden
+];
+```
+
+### change visibility afterward
+
+At any point in time, you could toggle the `hidden` property by using `grid.updateColumnById()` and make sure to also call `grid.updateColumns()` so that the UI is also updated.
+
+##### define columns
+
+```ts
+export class MyExample {
+ columns: Column[];
+
+ defineGrid() {
+ this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age' },
+ ];
+ }
+
+ // toggle column visibility & then update columns to show changes in the grid
+ toggleColumnVisibility(columnName: string) {
+ this.sgb.slickGrid.updateColumnById(columnName, { hidden: true });
+ this.sgb.slickGrid.updateColumns();
+ }
+
+ // get all columns (including `hidden` columns)
+ getAllColumns() {
+ this.sgb.slickGrid.getColumns();
+ }
+
+ // get only the visible columns
+ getOnlyVisibleColumns() {
+ this.sgb.slickGrid.getVisibleColumns();
+ }
+}
+```
diff --git a/frameworks/angular-slickgrid/docs/TOC.md b/frameworks/angular-slickgrid/docs/TOC.md
index d223637497..8b8e7523bc 100644
--- a/frameworks/angular-slickgrid/docs/TOC.md
+++ b/frameworks/angular-slickgrid/docs/TOC.md
@@ -35,6 +35,7 @@
* [Single Search Filter](column-functionalities/filters/single-search-filter.md)
* [Formatters](column-functionalities/formatters.md)
* [Sorting](column-functionalities/sorting.md)
+* [Visibility](column-functionalities/visibility.md)
## Events
diff --git a/frameworks/angular-slickgrid/docs/column-functionalities/visibility.md b/frameworks/angular-slickgrid/docs/column-functionalities/visibility.md
new file mode 100644
index 0000000000..f63027d71e
--- /dev/null
+++ b/frameworks/angular-slickgrid/docs/column-functionalities/visibility.md
@@ -0,0 +1,72 @@
+### Demo
+[Demo](https://ghiscoding.github.io/slickgrid-universal/#/example03) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vanilla/src/examples/example03.ts)
+
+### Description
+
+For column visibility, you can define the `hidden` property in your column definitions to initially hide some columns. You could also toggle the `hidden` property at any point in time (see below for more code usage).
+
+### initially hidden columns
+
+Let's start by demoing how to initially hide some column(s) by using the `hidden` property.
+
+##### define columns
+
+```ts
+this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age', hidden: true }, // column initially hidden
+];
+```
+
+### change visibility afterward
+
+At any point in time, you could toggle the `hidden` property by using `grid.updateColumnById()` and make sure to also call `grid.updateColumns()` so that the UI is also updated.
+
+##### define columns
+
+###### View
+```ts
+export class MyExample {
+ angularGrid: AngularGridInstance;
+ columns: Column[];
+
+ defineGrid() {
+ this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age' },
+ ];
+ }
+
+ angularGridReady(angularGrid: AngularGridInstance) {
+ this.angularGrid = angularGrid;
+ }
+
+ // toggle column visibility & then update columns to show changes in the grid
+ toggleColumnVisibility(columnName: string) {
+ this.angularGrid.slickGrid.updateColumnById(columnName, { hidden: true });
+ this.angularGrid.slickGrid.updateColumns();
+ }
+
+ // get all columns (including `hidden` columns)
+ getAllColumns() {
+ this.angularGrid.slickGrid.getColumns();
+ }
+
+ // get only the visible columns
+ getOnlyVisibleColumns() {
+ this.angularGrid.slickGrid.getVisibleColumns();
+ }
+}
+```
+
+###### ViewModel
+```html
+
+
+```
\ No newline at end of file
diff --git a/frameworks/angular-slickgrid/src/demos/examples/example18.component.ts b/frameworks/angular-slickgrid/src/demos/examples/example18.component.ts
index 87e22c2dec..dae9b619a8 100644
--- a/frameworks/angular-slickgrid/src/demos/examples/example18.component.ts
+++ b/frameworks/angular-slickgrid/src/demos/examples/example18.component.ts
@@ -75,6 +75,7 @@ export class Example18Component implements OnInit, OnDestroy {
name: 'Title',
field: 'title',
columnGroup: 'Common Factor',
+ hidden: true,
width: 70,
minWidth: 50,
cssClass: 'cell-title',
diff --git a/frameworks/angular-slickgrid/test/cypress/e2e/example18.cy.ts b/frameworks/angular-slickgrid/test/cypress/e2e/example18.cy.ts
index 855b1a5f6b..a2f067c377 100644
--- a/frameworks/angular-slickgrid/test/cypress/e2e/example18.cy.ts
+++ b/frameworks/angular-slickgrid/test/cypress/e2e/example18.cy.ts
@@ -1,6 +1,16 @@
describe('Example 18 - Draggable Grouping & Aggregators', () => {
const preHeaders = ['Common Factor', 'Period', 'Analysis', ''];
+ const originalTitles = ['Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven'];
const fullTitles = ['Title', 'Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven'];
+ const gridMenuTitles = [
+ 'Common Factor - Title',
+ 'Common Factor - Duration',
+ 'Period - Start',
+ 'Period - Finish',
+ 'Analysis - Cost',
+ 'Analysis - % Complete',
+ 'Analysis - Effort-Driven',
+ ];
it('should display Example title', () => {
cy.visit(`${Cypress.config('baseUrl')}/example18`);
@@ -18,7 +28,7 @@ describe('Example 18 - Draggable Grouping & Aggregators', () => {
cy.get('#grid18')
.find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .each(($child, index) => expect($child.text()).to.eq(originalTitles[index]));
});
it('should initially be grouped by "Duration" when loading the grid', () => {
@@ -26,6 +36,52 @@ describe('Example 18 - Draggable Grouping & Aggregators', () => {
cy.get('[data-row=1] > .slick-cell:nth(2)').should('contain', '0');
});
+ it('should open Grid Menu and be able to unhide "Title" column', () => {
+ cy.get('button.slick-grid-menu-button').click({ force: true });
+ cy.get('.slick-grid-menu:visible')
+ .find('.slick-column-picker-list')
+ .children('li:visible:nth(0)')
+ .children('label')
+ .should('contain', 'Common Factor - Title');
+ // .click({ force: true });
+
+ cy.get('.slick-column-picker-list input[data-columnid="title"]')
+ .parent('.icon-checkbox-container')
+ .find('.sgi')
+ .should('have.class', 'sgi-icon-picker-uncheck');
+
+ cy.get('.slick-column-picker-list li')
+ .children()
+
+ .each(($child, index) => {
+ if (index <= 5) {
+ expect($child.text()).to.eq(gridMenuTitles[index]);
+ }
+ });
+
+ cy.get('.slick-grid-menu:visible')
+ .find('.slick-column-picker-list')
+ .children('li:visible:nth(0)')
+ .children('label')
+ .should('contain', 'Common Factor - Title')
+ .click();
+
+ cy.get('.slick-column-picker-list input[data-columnid="title"]')
+ .parent('.icon-checkbox-container')
+ .find('.sgi')
+ .should('have.class', 'sgi-icon-picker-check');
+
+ cy.get('#grid18')
+ .find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
+ .children()
+ .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ });
+
+ it('should still be grouped by "Duration"', () => {
+ cy.get('[data-row=0] > .cell-title .slick-group-title').contains(/Duration: [0-9]/);
+ cy.get('[data-row=1] > .slick-cell:nth(2)').should('contain', '0');
+ });
+
it('should clear all groups with "Clear all Grouping" and no longer expect any grouping', () => {
cy.get('[data-test="clear-grouping-btn"]').click();
cy.get('#grid18').find('.slick-group-toggle-all').should('be.hidden');
diff --git a/frameworks/aurelia-slickgrid/docs/TOC.md b/frameworks/aurelia-slickgrid/docs/TOC.md
index 6726319c1d..8c91a4757b 100644
--- a/frameworks/aurelia-slickgrid/docs/TOC.md
+++ b/frameworks/aurelia-slickgrid/docs/TOC.md
@@ -34,6 +34,7 @@
* [Single Search Filter](column-functionalities/filters/single-search-filter.md)
* [Formatters](column-functionalities/formatters.md)
* [Sorting](column-functionalities/sorting.md)
+* [Visibility](column-functionalities/visibility.md)
## Events
diff --git a/frameworks/aurelia-slickgrid/docs/column-functionalities/visibility.md b/frameworks/aurelia-slickgrid/docs/column-functionalities/visibility.md
new file mode 100644
index 0000000000..7cd4c58dcd
--- /dev/null
+++ b/frameworks/aurelia-slickgrid/docs/column-functionalities/visibility.md
@@ -0,0 +1,72 @@
+### Demo
+[Demo](https://ghiscoding.github.io/slickgrid-universal/#/example03) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vanilla/src/examples/example03.ts)
+
+### Description
+
+For column visibility, you can define the `hidden` property in your column definitions to initially hide some columns. You could also toggle the `hidden` property at any point in time (see below for more code usage).
+
+### initially hidden columns
+
+Let's start by demoing how to initially hide some column(s) by using the `hidden` property.
+
+##### define columns
+
+```ts
+this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age', hidden: true }, // column initially hidden
+];
+```
+
+### change visibility afterward
+
+At any point in time, you could toggle the `hidden` property by using `grid.updateColumnById()` and make sure to also call `grid.updateColumns()` so that the UI is also updated.
+
+##### define columns
+
+###### View
+```ts
+export class MyExample {
+ aureliaGrid: AureliaGridInstance;
+ columns: Column[];
+
+ defineGrid() {
+ this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age' },
+ ];
+ }
+
+ aureliaGridReady(aureliaGrid: aureliaGridInstance) {
+ this.aureliaGrid = aureliaGrid;
+ }
+
+ // toggle column visibility & then update columns to show changes in the grid
+ toggleColumnVisibility(columnName: string) {
+ this.aureliaGrid.slickGrid.updateColumnById(columnName, { hidden: true });
+ this.aureliaGrid.slickGrid.updateColumns();
+ }
+
+ // get all columns (including `hidden` columns)
+ getAllColumns() {
+ this.aureliaGrid.slickGrid.getColumns();
+ }
+
+ // get only the visible columns
+ getOnlyVisibleColumns() {
+ this.aureliaGrid.slickGrid.getVisibleColumns();
+ }
+}
+```
+
+###### ViewModel
+```html
+
+
+```
diff --git a/frameworks/slickgrid-react/docs/TOC.md b/frameworks/slickgrid-react/docs/TOC.md
index 181477029c..8a7f62a075 100644
--- a/frameworks/slickgrid-react/docs/TOC.md
+++ b/frameworks/slickgrid-react/docs/TOC.md
@@ -34,6 +34,7 @@
* [Single Search Filter](column-functionalities/filters/single-search-filter.md)
* [Formatters](column-functionalities/formatters.md)
* [Sorting](column-functionalities/sorting.md)
+* [Visibility](column-functionalities/visibility.md)
## Events
diff --git a/frameworks/slickgrid-react/docs/column-functionalities/visibility.md b/frameworks/slickgrid-react/docs/column-functionalities/visibility.md
new file mode 100644
index 0000000000..7cbcd67ee5
--- /dev/null
+++ b/frameworks/slickgrid-react/docs/column-functionalities/visibility.md
@@ -0,0 +1,76 @@
+### Demo
+[Demo](https://ghiscoding.github.io/slickgrid-universal/#/example03) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vanilla/src/examples/example03.ts)
+
+### Description
+
+For column visibility, you can define the `hidden` property in your column definitions to initially hide some columns. You could also toggle the `hidden` property at any point in time (see below for more code usage).
+
+### initially hidden columns
+
+Let's start by demoing how to initially hide some column(s) by using the `hidden` property.
+
+##### define columns
+
+```ts
+this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age', hidden: true }, // column initially hidden
+];
+```
+
+### change visibility afterward
+
+At any point in time, you could toggle the `hidden` property by using `grid.updateColumnById()` and make sure to also call `grid.updateColumns()` so that the UI is also updated.
+
+##### define columns
+
+```tsx
+const Example: React.FC = () => {
+ const [dataset, setDataset] = useState
([]);
+ const [columns, setColumns] = useState([]);
+ const [options, setOptions] = useState(undefined);
+ const reactGridRef = useRef(null);
+
+ useEffect(() => defineGrid());
+
+ function defineGrid() {
+ this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age' },
+ ];
+ }
+
+ function reactGridReady(reactGrid: SlickgridReactInstance) {
+ reactGridRef.current = reactGrid;
+ }
+
+ // toggle column visibility & then update columns to show changes in the grid
+ function toggleColumnVisibility(columnName: string) {
+ this.aureliaGrid.slickGrid.updateColumnById(columnName, { hidden: true });
+ this.aureliaGrid.slickGrid.updateColumns();
+ }
+
+ // get all columns (including `hidden` columns)
+ function getAllColumns() {
+ this.aureliaGrid.slickGrid.getColumns();
+ }
+
+ // get only the visible columns
+ function getOnlyVisibleColumns() {
+ this.aureliaGrid.slickGrid.getVisibleColumns();
+ }
+ return !options ? '' : (
+
+ { reactGridReady(e.detail); }}
+ />
+
+ );
+}
+```
diff --git a/frameworks/slickgrid-react/docs/slick-grid-dataview-objects/slickgrid-dataview-objects.md b/frameworks/slickgrid-react/docs/slick-grid-dataview-objects/slickgrid-dataview-objects.md
index 876d0fc2bc..9ed99cc93d 100644
--- a/frameworks/slickgrid-react/docs/slick-grid-dataview-objects/slickgrid-dataview-objects.md
+++ b/frameworks/slickgrid-react/docs/slick-grid-dataview-objects/slickgrid-dataview-objects.md
@@ -29,16 +29,16 @@ const Example: React.FC = () => {
/** Change dynamically `autoEdit` grid options */
function setAutoEdit(isAutoEdit) {
setIsAutoEdit(isAutoEdit);
- reactGridRef.current?.setOptions({ autoEdit: isAutoEdit }); // change the grid option dynamically
+ reactGridRef.current?.slickGrid.setOptions({ autoEdit: isAutoEdit }); // change the grid option dynamically
return true;
}
function collapseAllGroups() {
- reactGridRef.current?.collapseAllGroups();
+ reactGridRef.current?.slickGrid.collapseAllGroups();
}
function expandAllGroups() {
- reactGridRef.current?.expandAllGroups();
+ reactGridRef.current?.slickGrid.expandAllGroups();
}
return !options ? '' : (
diff --git a/frameworks/slickgrid-vue/docs/TOC.md b/frameworks/slickgrid-vue/docs/TOC.md
index 9b6cc4d910..12f4c0acd0 100644
--- a/frameworks/slickgrid-vue/docs/TOC.md
+++ b/frameworks/slickgrid-vue/docs/TOC.md
@@ -34,6 +34,7 @@
* [Single Search Filter](column-functionalities/filters/single-search-filter.md)
* [Formatters](column-functionalities/formatters.md)
* [Sorting](column-functionalities/sorting.md)
+* [Visibility](column-functionalities/visibility.md)
## Events
diff --git a/frameworks/slickgrid-vue/docs/column-functionalities/visibility.md b/frameworks/slickgrid-vue/docs/column-functionalities/visibility.md
new file mode 100644
index 0000000000..5da6f15ff4
--- /dev/null
+++ b/frameworks/slickgrid-vue/docs/column-functionalities/visibility.md
@@ -0,0 +1,82 @@
+### Demo
+[Demo](https://ghiscoding.github.io/slickgrid-universal/#/example03) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vanilla/src/examples/example03.ts)
+
+### Description
+
+For column visibility, you can define the `hidden` property in your column definitions to initially hide some columns. You could also toggle the `hidden` property at any point in time (see below for more code usage).
+
+### initially hidden columns
+
+Let's start by demoing how to initially hide some column(s) by using the `hidden` property.
+
+##### define columns
+
+```ts
+this.columns = [
+ { id: 'firstName', field: 'firstName', name: 'First Name' },
+ { id: 'lastName', field: 'lastName', name: 'Last Name' },
+ { id: 'age', field: 'age', name: 'Age', hidden: true }, // column initially hidden
+];
+```
+
+### change visibility afterward
+
+At any point in time, you could toggle the `hidden` property by using `grid.updateColumnById()` and make sure to also call `grid.updateColumns()` so that the UI is also updated.
+
+##### define columns
+
+```vue
+
+
+
+
+
+
+
+```
diff --git a/packages/common/src/core/__tests__/slickDataView.spec.ts b/packages/common/src/core/__tests__/slickDataView.spec.ts
index 770b5a6b90..779a72187d 100644
--- a/packages/common/src/core/__tests__/slickDataView.spec.ts
+++ b/packages/common/src/core/__tests__/slickDataView.spec.ts
@@ -1114,6 +1114,7 @@ describe('SlickDatView core file', () => {
},
},
cssClasses: 'slick-group slick-group-level-0',
+ isGroup: true,
focusable: true,
formatter: undefined,
selectable: false,
@@ -1164,6 +1165,7 @@ describe('SlickDatView core file', () => {
cssClasses: 'slick-group-totals slick-group-level-1',
editorClass: null,
focusable: false,
+ isGroup: true,
formatter: expect.anything(),
selectable: false,
});
@@ -1260,6 +1262,7 @@ describe('SlickDatView core file', () => {
},
},
cssClasses: 'slick-group slick-group-level-0',
+ isGroup: true,
focusable: true,
formatter: undefined,
selectable: false,
diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts
index 34f12382d6..910bc1f74a 100644
--- a/packages/common/src/core/__tests__/slickGrid.spec.ts
+++ b/packages/common/src/core/__tests__/slickGrid.spec.ts
@@ -2122,6 +2122,36 @@ describe('SlickGrid core file', () => {
expect(slickRowElms[0].classList.contains('highlight-animate')).toBeFalsy();
expect(slickRowElms[1].classList.contains('highlight-animate')).toBeFalsy();
});
+
+ it('should return the correct header column by id when a hidden column precedes it', () => {
+ const columns = [
+ { id: 'a', field: 'a', name: 'A', hidden: true },
+ { id: 'b', field: 'b', name: 'B' },
+ { id: 'c', field: 'c', name: 'C' },
+ ] as Column[];
+ const rows = [{ id: 0, a: 'x', b: 'y', c: 'z' }];
+
+ grid = new SlickGrid(container, rows, columns, defaultOptions);
+ grid.init();
+
+ const headerElm = grid.getHeaderColumn('b');
+
+ expect(headerElm).toBeInstanceOf(HTMLDivElement);
+ expect(headerElm.dataset.id).toBe('b');
+ });
+
+ it('should return undefined from getHeaderColumn fallback when target column is hidden', () => {
+ const columns = [
+ { id: 'a', field: 'a', name: 'A', hidden: true },
+ { id: 'b', field: 'b', name: 'B' },
+ ] as Column[];
+ const rows = [{ id: 0, a: 'x', b: 'y' }];
+
+ grid = new SlickGrid(container, rows, columns, defaultOptions);
+ grid.init();
+
+ expect(grid.getHeaderColumn(0)).toBeUndefined();
+ });
});
describe('flashCell() method', () => {
diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts
index c21d491b3d..db6fa8518f 100755
--- a/packages/common/src/core/slickGrid.ts
+++ b/packages/common/src/core/slickGrid.ts
@@ -1640,12 +1640,19 @@ export class SlickGrid = Column, O e
*/
getHeaderColumn(columnIdOrIdx: number | string): HTMLDivElement {
const idx = typeof columnIdOrIdx === 'number' ? columnIdOrIdx : this.getColumnIndex(columnIdOrIdx);
- // prettier-ignore
- const targetHeader = this.hasFrozenColumns() ? ((idx <= this._options.frozenColumn!) ? this._headerL : this._headerR) : this._headerL;
- // prettier-ignore
- const targetIndex = this.hasFrozenColumns() ? ((idx <= this._options.frozenColumn!) ? idx : idx - this._options.frozenColumn! - 1) : idx;
+ const targetHeader = this.hasFrozenColumns() ? (idx <= this._options.frozenColumn! ? this._headerL : this._headerR) : this._headerL;
+ const targetIndex = this.hasFrozenColumns() ? (idx <= this._options.frozenColumn! ? idx : idx - this._options.frozenColumn! - 1) : idx;
+ const directMatch = targetHeader.children[targetIndex] as HTMLDivElement | undefined;
+ const targetColumnId = String(this.columns[idx]?.id ?? columnIdOrIdx);
+ const directMatchColumn = Utils.storage.get(directMatch, 'column') as C | undefined;
+ if (directMatch && (directMatch.dataset?.id === targetColumnId || String(directMatchColumn?.id) === targetColumnId)) {
+ return directMatch;
+ }
- return targetHeader.children[targetIndex] as HTMLDivElement;
+ return (
+ (Array.from(targetHeader.children).find((child) => (child as HTMLDivElement).dataset?.id === targetColumnId) as HTMLDivElement) ||
+ (undefined as any)
+ );
}
/** Get the Header Row DOM element */
@@ -4159,7 +4166,7 @@ export class SlickGrid = Column, O e
for (let i = 0, ii = columnCount; i < ii; i++) {
isRenderCell = true;
m = this.columns[i];
- if (m && !m.hidden) {
+ if (m && (!m.hidden || metadata?.isGroup)) {
colspan = 1;
rowspan = 1;
columnData = null;
@@ -5256,15 +5263,15 @@ export class SlickGrid = Column, O e
// Render missing cells.
cellsAdded = 0;
- let metadata = this.getItemMetadaWhenExists(row);
- metadata = metadata?.columns as ItemMetadata;
+ const metadata = this.getItemMetadaWhenExists(row);
+ const metadataCol = metadata?.columns;
const d = this.getDataItem(row);
let isFullColspan = false;
// TODO: shorten this loop (index? heuristics? binary search?)
for (let i = 0, ii = columnCount; i < ii; i++) {
- if (this.columns[i] && !this.columns[i].hidden) {
+ if (this.columns[i] && (!this.columns[i].hidden || metadata?.isGroup)) {
// Cells to the right are outside the range.
if (this.columnPosLeft[i] > range.rightPx) {
break;
@@ -5278,8 +5285,8 @@ export class SlickGrid = Column, O e
colspan = 1;
columnData = null;
- if (metadata) {
- columnData = metadata[this.columns[i].id as keyof ItemMetadata] || (metadata as any)[i];
+ if (metadataCol) {
+ columnData = metadataCol[this.columns[i].id as keyof ItemMetadata] || (metadataCol as any)[i];
colspan = columnData?.colspan ?? 1;
if (colspan === '*') {
colspan = ii - i;
diff --git a/packages/common/src/extensions/__tests__/slickGroupItemMetadataProvider.spec.ts b/packages/common/src/extensions/__tests__/slickGroupItemMetadataProvider.spec.ts
index 9b9f1feb0e..164ff36cd1 100644
--- a/packages/common/src/extensions/__tests__/slickGroupItemMetadataProvider.spec.ts
+++ b/packages/common/src/extensions/__tests__/slickGroupItemMetadataProvider.spec.ts
@@ -235,6 +235,7 @@ describe('GroupItemMetadataProvider Service', () => {
const output = service.getGroupRowMetadata({ count: 12, level: undefined as any, groupingKey: 'age', value: 33 }, 0);
expect(output).toEqual({
selectable: false,
+ isGroup: true,
focusable: mockOptions.groupFocusable,
cssClasses: `${mockOptions.groupCssClass} slick-group-level-0`,
formatter: service.getOptions().totalsFormatter,
@@ -255,6 +256,7 @@ describe('GroupItemMetadataProvider Service', () => {
const output = service.getGroupRowMetadata({ count: 12, level: 2, groupingKey: 'age', value: 33 }, 0);
expect(output).toEqual({
selectable: false,
+ isGroup: true,
focusable: mockOptions.groupFocusable,
cssClasses: `${mockOptions.groupCssClass} slick-group-level-2`,
formatter: undefined,
@@ -277,6 +279,7 @@ describe('GroupItemMetadataProvider Service', () => {
const output = service.getTotalsRowMetadata({ group: { count: 12, level: undefined as any, groupingKey: 'age', value: 33 } }, 0);
expect(output).toEqual({
editorClass: null,
+ isGroup: true,
selectable: false,
focusable: mockOptions.totalsFocusable,
cssClasses: `groupy-totals slick-group-level-0`,
@@ -288,6 +291,7 @@ describe('GroupItemMetadataProvider Service', () => {
const output = service.getTotalsRowMetadata({ group: { count: 12, level: 3, groupingKey: 'age', value: 33 } }, 0);
expect(output).toEqual({
editorClass: null,
+ isGroup: true,
focusable: false,
selectable: false,
cssClasses: `slick-group-totals slick-group-level-3`,
diff --git a/packages/common/src/extensions/slickGroupItemMetadataProvider.ts b/packages/common/src/extensions/slickGroupItemMetadataProvider.ts
index f074571d5d..fe69718121 100644
--- a/packages/common/src/extensions/slickGroupItemMetadataProvider.ts
+++ b/packages/common/src/extensions/slickGroupItemMetadataProvider.ts
@@ -9,7 +9,6 @@ import {
} from '../core/index.js';
import type {
Column,
- Formatter,
GridOption,
GroupingFormatterItem,
GroupItemMetadataProviderOption,
@@ -97,6 +96,7 @@ export class SlickGroupItemMetadataProvider implements SlickPlugin {
focusable: this._options.groupFocusable,
cssClasses: `${this._options.groupCssClass} slick-group-level-${item?.level || 0}`,
formatter: (this._options.includeHeaderTotals && this._options.totalsFormatter) || undefined,
+ isGroup: true,
columns: {
0: {
colspan: this._options.includeHeaderTotals ? '1' : '*',
@@ -108,19 +108,14 @@ export class SlickGroupItemMetadataProvider implements SlickPlugin {
}
// prettier-ignore
- getTotalsRowMetadata(item: { group: GroupingFormatterItem }, _row: number): {
- selectable: boolean;
- focusable: boolean | undefined;
- cssClasses: string;
- formatter: Formatter | undefined;
- editorClass: null;
- } {
+ getTotalsRowMetadata(item: { group: GroupingFormatterItem }, _row: number): ItemMetadata {
return {
selectable: false,
focusable: this._options.totalsFocusable,
cssClasses: `${this._options.totalsCssClass} slick-group-level-${item?.group?.level || 0}`,
formatter: this._options.totalsFormatter,
editorClass: null,
+ isGroup: true
};
}
diff --git a/packages/common/src/interfaces/itemMetadata.interface.ts b/packages/common/src/interfaces/itemMetadata.interface.ts
index 1a1d2311cf..6d9da38077 100644
--- a/packages/common/src/interfaces/itemMetadata.interface.ts
+++ b/packages/common/src/interfaces/itemMetadata.interface.ts
@@ -1,4 +1,4 @@
-import type { Column, Formatter, GroupTotalsFormatter } from './index.js';
+import type { Column, Editor, EditorConstructor, Formatter, GroupTotalsFormatter } from './index.js';
export type ColumnMetadata = Pick<
Column,
@@ -32,4 +32,10 @@ export interface ItemMetadata {
// properties describing metadata related to individual columns
[colIdOrIdx in string | number]: ColumnMetadata;
};
+
+ /** Any inline Editor class or Editor constructor, this is mostly used internally by SlickGrid */
+ editorClass?: Editor | EditorConstructor | null;
+
+ /** defined when the metadata is defined to be a group */
+ isGroup?: boolean;
}
diff --git a/test/cypress/e2e/example03.cy.ts b/test/cypress/e2e/example03.cy.ts
index f4296818fe..a89b87ca08 100644
--- a/test/cypress/e2e/example03.cy.ts
+++ b/test/cypress/e2e/example03.cy.ts
@@ -1,6 +1,18 @@
describe('Example 03 - Draggable Grouping', () => {
const preHeaders = ['', 'Common Factor', 'Period', 'Analysis', ''];
+ const originalTitles = ['', 'Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven', 'Action'];
const fullTitles = ['', 'Title', 'Duration', 'Start', 'Finish', 'Cost', '% Complete', 'Effort-Driven', 'Action'];
+ const gridMenuTitles = [
+ '',
+ 'Common Factor - Title',
+ 'Common Factor - Duration',
+ 'Period - Start',
+ 'Period - Finish',
+ 'Analysis - Cost',
+ 'Analysis - % Complete',
+ 'Analysis - Effort-Driven',
+ 'Action',
+ ];
const GRID_ROW_HEIGHT = 33;
it('should display Example title', () => {
@@ -20,7 +32,7 @@ describe('Example 03 - Draggable Grouping', () => {
cy.get('.grid3')
.find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
.children()
- .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ .each(($child, index) => expect($child.text()).to.eq(originalTitles[index]));
});
it('should initially be grouped by "Duration" when loading the grid', () => {
@@ -30,6 +42,54 @@ describe('Example 03 - Draggable Grouping', () => {
cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', '0');
});
+ it('should open Grid Menu and be able to unhide "Title" column', () => {
+ cy.get('button.slick-grid-menu-button').click({ force: true });
+ cy.get('.slick-grid-menu:visible')
+ .find('.slick-column-picker-list')
+ .children('li:visible:nth(0)')
+ .children('label')
+ .should('contain', 'Common Factor - Title');
+ // .click({ force: true });
+
+ cy.get('.slick-column-picker-list input[data-columnid="title"]')
+ .parent('.icon-checkbox-container')
+ .find('.sgi')
+ .should('have.class', 'sgi-icon-picker-uncheck');
+
+ cy.get('.slick-column-picker-list li')
+ .children()
+
+ .each(($child, index) => {
+ if (index <= 5) {
+ expect($child.text()).to.eq(gridMenuTitles[index]);
+ }
+ });
+
+ cy.get('.slick-grid-menu:visible')
+ .find('.slick-column-picker-list')
+ .children('li:visible:nth(0)')
+ .children('label')
+ .should('contain', 'Common Factor - Title')
+ .click();
+
+ cy.get('.slick-column-picker-list input[data-columnid="title"]')
+ .parent('.icon-checkbox-container')
+ .find('.sgi')
+ .should('have.class', 'sgi-icon-picker-check');
+
+ cy.get('.grid3')
+ .find('.slick-header:not(.slick-preheader-panel) .slick-header-columns')
+ .children()
+ .each(($child, index) => expect($child.text()).to.eq(fullTitles[index]));
+ });
+
+ it('should still be grouped by "Duration"', () => {
+ cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 0}px);"] > .slick-cell:nth(0) .slick-group-title`).contains(
+ /Duration: [0-9]/
+ );
+ cy.get(`[style="transform: translateY(${GRID_ROW_HEIGHT * 1}px);"] > .slick-cell:nth(2)`).should('contain', '0');
+ });
+
it('should clear all groups with "Clear all Grouping" and no longer expect any grouping', () => {
cy.get('[data-test="clear-grouping-btn"]').click();
cy.get('.grid3').find('.slick-group-toggle-all').should('be.hidden');