From 2e5682c113b36225982887b738f00ebc293525f4 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 12 May 2026 10:29:22 -0400 Subject: [PATCH 1/5] fix(common): resolve getHeaderColumn with hidden leading columns --- .../common/src/core/__tests__/slickGrid.spec.ts | 17 +++++++++++++++++ packages/common/src/core/slickGrid.ts | 17 ++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 34f12382d..80ded0d55 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -2122,6 +2122,23 @@ 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'); + }); }); describe('flashCell() method', () => { diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index c21d491b3..4d3cbf7bc 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 */ From c29f9139c871c693fb6b3f27248950ae3e7205c1 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 12 May 2026 10:40:54 -0400 Subject: [PATCH 2/5] chore: increase code coverage for new code --- .../common/src/core/__tests__/slickGrid.spec.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 80ded0d55..910bc1f74 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -2139,6 +2139,19 @@ describe('SlickGrid core file', () => { 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', () => { From 385826aa8cfbc1ffcecef14cbaf482fa9347bf53 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 12 May 2026 21:53:17 -0400 Subject: [PATCH 3/5] chore: add some Cypress E2E testing --- demos/vanilla/src/examples/example03.html | 4 ++ demos/vanilla/src/examples/example03.ts | 1 + test/cypress/e2e/example03.cy.ts | 62 ++++++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/demos/vanilla/src/examples/example03.html b/demos/vanilla/src/examples/example03.html index f271da75d..b93ea06b3 100644 --- a/demos/vanilla/src/examples/example03.html +++ b/demos/vanilla/src/examples/example03.html @@ -19,6 +19,10 @@

+
+ Please note that the grid below initially has its first column "Title" hidden by default for E2E testing. +
+
diff --git a/demos/vanilla/src/examples/example03.ts b/demos/vanilla/src/examples/example03.ts index c40f8043c..a6d2995d1 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, sortable: true, editor: { model: Editors.longText, diff --git a/test/cypress/e2e/example03.cy.ts b/test/cypress/e2e/example03.cy.ts index f4296818f..a89b87ca0 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'); From 92d1bf15361d2750fd70d96b7aa2b65258a348cd Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 12 May 2026 22:45:12 -0400 Subject: [PATCH 4/5] docs: add documentation for hidding columns --- docs/TOC.md | 1 + docs/column-functionalities/visibility.md | 56 +++++++++++++ frameworks/angular-slickgrid/docs/TOC.md | 1 + .../docs/column-functionalities/visibility.md | 72 ++++++++++++++++ frameworks/aurelia-slickgrid/docs/TOC.md | 1 + .../docs/column-functionalities/visibility.md | 72 ++++++++++++++++ frameworks/slickgrid-react/docs/TOC.md | 1 + .../docs/column-functionalities/visibility.md | 76 +++++++++++++++++ .../slickgrid-dataview-objects.md | 6 +- frameworks/slickgrid-vue/docs/TOC.md | 1 + .../docs/column-functionalities/visibility.md | 82 +++++++++++++++++++ 11 files changed, 366 insertions(+), 3 deletions(-) create mode 100644 docs/column-functionalities/visibility.md create mode 100644 frameworks/angular-slickgrid/docs/column-functionalities/visibility.md create mode 100644 frameworks/aurelia-slickgrid/docs/column-functionalities/visibility.md create mode 100644 frameworks/slickgrid-react/docs/column-functionalities/visibility.md create mode 100644 frameworks/slickgrid-vue/docs/column-functionalities/visibility.md diff --git a/docs/TOC.md b/docs/TOC.md index 7006be676..572426419 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 000000000..1402c7868 --- /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 d22363749..8b8e7523b 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 000000000..f63027d71 --- /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/aurelia-slickgrid/docs/TOC.md b/frameworks/aurelia-slickgrid/docs/TOC.md index 6726319c1..8c91a4757 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 000000000..7cd4c58dc --- /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 181477029..8a7f62a07 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 000000000..7cbcd67ee --- /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 876d0fc2b..9ed99cc93 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 9b6cc4d91..12f4c0acd 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 000000000..5da6f15ff --- /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 + + + +``` From eea71df1f18846b2fc548a4cec12d8a4699297ef Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Wed, 13 May 2026 01:18:55 -0400 Subject: [PATCH 5/5] chore: should work when hidden column is index 0 --- .../src/examples/slickgrid/example18.ts | 1 + .../aurelia/test/cypress/e2e/example18.cy.ts | 58 ++++++++++++++++++- .../src/examples/slickgrid/Example18.tsx | 1 + demos/react/test/cypress/e2e/example18.cy.ts | 58 ++++++++++++++++++- demos/vanilla/src/examples/example03.ts | 2 +- demos/vue/src/components/Example18.vue | 1 + demos/vue/test/cypress/e2e/example18.cy.ts | 58 ++++++++++++++++++- .../src/demos/examples/example18.component.ts | 1 + .../test/cypress/e2e/example18.cy.ts | 58 ++++++++++++++++++- .../src/core/__tests__/slickDataView.spec.ts | 3 + packages/common/src/core/slickGrid.ts | 12 ++-- .../slickGroupItemMetadataProvider.spec.ts | 4 ++ .../slickGroupItemMetadataProvider.ts | 11 +--- .../src/interfaces/itemMetadata.interface.ts | 8 ++- 14 files changed, 256 insertions(+), 20 deletions(-) diff --git a/demos/aurelia/src/examples/slickgrid/example18.ts b/demos/aurelia/src/examples/slickgrid/example18.ts index dde14856f..bc4be3af9 100644 --- a/demos/aurelia/src/examples/slickgrid/example18.ts +++ b/demos/aurelia/src/examples/slickgrid/example18.ts @@ -64,6 +64,7 @@ export class Example18 { width: 70, minWidth: 50, cssClass: 'cell-title', + hidden: true, // column initially hidden filterable: true, sortable: true, grouping: { diff --git a/demos/aurelia/test/cypress/e2e/example18.cy.ts b/demos/aurelia/test/cypress/e2e/example18.cy.ts index eae744afc..dd795e35c 100644 --- a/demos/aurelia/test/cypress/e2e/example18.cy.ts +++ b/demos/aurelia/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/demos/react/src/examples/slickgrid/Example18.tsx b/demos/react/src/examples/slickgrid/Example18.tsx index 2d6b539fe..9d726d15d 100644 --- a/demos/react/src/examples/slickgrid/Example18.tsx +++ b/demos/react/src/examples/slickgrid/Example18.tsx @@ -56,6 +56,7 @@ const Example18: React.FC = () => { width: 70, minWidth: 50, cssClass: 'cell-title', + hidden: true, // column initially hidden filterable: true, sortable: true, grouping: { diff --git a/demos/react/test/cypress/e2e/example18.cy.ts b/demos/react/test/cypress/e2e/example18.cy.ts index b9807b0bc..397df8aa6 100644 --- a/demos/react/test/cypress/e2e/example18.cy.ts +++ b/demos/react/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/demos/vanilla/src/examples/example03.ts b/demos/vanilla/src/examples/example03.ts index a6d2995d1..5a774f282 100644 --- a/demos/vanilla/src/examples/example03.ts +++ b/demos/vanilla/src/examples/example03.ts @@ -94,7 +94,7 @@ export default class Example03 { name: 'Title', field: 'title', columnGroup: 'Common Factor', - hidden: true, + 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 a3fe49122..56d07fdf2 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 b9807b0bc..397df8aa6 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/frameworks/angular-slickgrid/src/demos/examples/example18.component.ts b/frameworks/angular-slickgrid/src/demos/examples/example18.component.ts index 87e22c2de..dae9b619a 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 855b1a5f6..a2f067c37 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/packages/common/src/core/__tests__/slickDataView.spec.ts b/packages/common/src/core/__tests__/slickDataView.spec.ts index 770b5a6b9..779a72187 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/slickGrid.ts b/packages/common/src/core/slickGrid.ts index 4d3cbf7bc..db6fa8518 100755 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -4166,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; @@ -5263,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; @@ -5285,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 9b9f1feb0..164ff36cd 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 f074571d5..fe6971812 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 1a1d2311c..6d9da3807 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; }