Skip to content

Commit c37b4ee

Browse files
authored
feat!: switch to column hidden property and always keep all columns (#1299)
* feat!: switch to column `hidden` property and always keep all columns
1 parent 179c8ac commit c37b4ee

28 files changed

Lines changed: 391 additions & 320 deletions

.github/pull_request_template.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!-- PR title should be using conventional commit with a length below 73 chars. See https://www.conventionalcommits.org/en/v1.0.0/ -->
2+
<!-- if this PR fixes an issue, please add it on a separate line for proper linking and following this structure "fixes #123" (replace 123 with the correct issue number) -->
3+
4+
## Summary
5+
6+
<!-- Describe the purpose of this pull request and link any related issue. -->
7+
8+
## Why
9+
10+
<!-- Optional reasons explaining why you think this PR can be useful -->
11+
12+
## Changes
13+
14+
<!-- List the important implementation or documentation changes. -->
15+
16+
## Validation
17+
18+
<!-- List the tests, builds, lint, formatting, or other checks that were run. -->
19+
20+
## Comments
21+
22+
<!-- Any other optional comments or website links to add -->
23+
24+
## AI / LLM assistance
25+
26+
- AI / LLM assistance used:
27+
- [ ] No
28+
- [ ] Yes
29+
- If **Yes**:
30+
- **which tool/model**:
31+
- **how was it used**:
32+
33+
## Checklist
34+
35+
- [ ] The changes are limited to only one scope (if not please explain why in the comments above).
36+
- [ ] Tests were added or updated where appropriate.
37+
- [ ] Documentation was updated where appropriate.

cypress/e2e/example-0031-row-span-employees.cy.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ describe('Example - colspan/rowspan - Employees Timesheets', { retries: 1 }, ()
2323
cy.get('.grid-canvas-right .slick-cell:not(.frozen)').should('have.length.above', 60);
2424
});
2525

26+
it('should hide Employee ID with hidden while keeping the complete column definition list', () => {
27+
cy.get('[data-test="toggle-employee-id"]').click();
28+
cy.get('#myGrid .slick-header-column').should('have.length', 18);
29+
cy.get('[data-row=0] > .slick-cell.l0').should('not.exist');
30+
cy.get('[data-test="toggle-employee-id"]').click();
31+
cy.get('#myGrid .slick-header-column').should('have.length', 19);
32+
});
33+
2634
describe('Spanning', () => {
2735
it('should expect "Davolio", "Check Mail", and "Development" to all have rowspan of 2 in morning hours', () => {
2836
cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
@@ -450,25 +458,25 @@ describe('Example - colspan/rowspan - Employees Timesheets', { retries: 1 }, ()
450458
cy.get('[data-test="toggle-employee-id"]').click();
451459
});
452460

453-
it('should expect EmployeeID to follow columns at index 0 column index', () => {
454-
cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should('contain', 'Davolio');
455-
cy.get(`[data-row=0] > .slick-cell.l0.r0.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
461+
it('should preserve the original cell indexes while EmployeeID is hidden', () => {
462+
cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should('contain', 'Davolio');
463+
cy.get(`[data-row=0] > .slick-cell.l1.r1.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
456464

457-
cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should('contain', 'Check Mail');
458-
cy.get(`[data-row=2] > .slick-cell.l1.r3.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
465+
cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should('contain', 'Check Mail');
466+
cy.get(`[data-row=2] > .slick-cell.l2.r4.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
459467

460-
cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should('contain', 'Development');
461-
cy.get(`[data-row=8] > .slick-cell.l6.r8.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
468+
cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should('contain', 'Development');
469+
cy.get(`[data-row=8] > .slick-cell.l7.r9.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 2));
462470
});
463471

464-
it('should expect "Lunch Break" to be moved to the left by 1 index less', () => {
465-
cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should('contain', 'Lunch Break');
466-
cy.get(`[data-row=0] > .slick-cell.l9.r11.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10));
472+
it('should preserve the original Lunch Break cell index', () => {
473+
cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should('contain', 'Lunch Break');
474+
cy.get(`[data-row=0] > .slick-cell.l10.r12.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 10));
467475
});
468476

469-
it('should expect "Development" to be moved to the left by 1 index less', () => {
470-
cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should('contain', 'Development');
471-
cy.get(`[data-row=1] > .slick-cell.l12.r13.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5));
477+
it('should preserve the original afternoon Development cell index', () => {
478+
cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should('contain', 'Development');
479+
cy.get(`[data-row=1] > .slick-cell.l13.r14.rowspan`).should(($el) => expect(parseInt(`${$el.outerHeight()}`, 10)).to.eq(GRID_ROW_HEIGHT * 5));
472480
});
473481
});
474482

cypress/e2e/example-colspan.cy.ts

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
describe('Example - Column Span & Header Grouping', { retries: 1 }, () => {
2-
const GRID_ROW_HEIGHT = 25;
3-
const fullTitles = ['Title', 'Duration', '% Complete', 'Start', 'Finish', 'Effort Driven'];
2+
const fullTitles = ['Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
43
for (let i = 0; i < 30; i++) {
54
fullTitles.push(`Mock${i}`);
65
}
@@ -19,31 +18,48 @@ describe('Example - Column Span & Header Grouping', { retries: 1 }, () => {
1918
});
2019

2120
it('should expect 1st row to be 1 column spanned to the entire width', () => {
22-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 0');
23-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell.l0.r5`).should('exist');
24-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 0}px;"] > .slick-cell:nth(1)`).should('not.exist');
21+
cy.get('[data-row=0] > .slick-cell:nth(0)').should('contain', 'Task 0');
22+
cy.get('[data-row=0] > .slick-cell.l0.r5').should('exist');
23+
cy.get('[data-row=0] > .slick-cell:nth(1)').should('not.exist');
2524
});
2625

2726
it('should expect 2nd row to be 4 columns and not be spanned', () => {
28-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 1');
29-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell.l0.r0`).should('exist');
30-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
31-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(1).l1.r3`).should('exist');
32-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
33-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 1}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
27+
cy.get('[data-row=1] > .slick-cell:nth(0)').should('contain', 'Task 1');
28+
cy.get('[data-row=1] > .slick-cell.l0.r0').should('exist');
29+
cy.get('[data-row=1] > .slick-cell:nth(1)').should('contain', '5 days');
30+
cy.get('[data-row=1] > .slick-cell:nth(1).l1.r3').should('exist');
31+
cy.get('[data-row=1] > .slick-cell:nth(2)').contains(/\d+$/);
32+
cy.get('[data-row=1] > .slick-cell:nth(3)').contains(/(true|false)/);
3433
});
3534

3635
it('should expect 3rd row to be 1 column spanned to the entire width', () => {
37-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 2');
38-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell.l0.r5`).should('exist');
39-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 2}px;"] > .slick-cell:nth(1)`).should('not.exist');
36+
cy.get('[data-row=2] > .slick-cell:nth(0)').should('contain', 'Task 2');
37+
cy.get('[data-row=2] > .slick-cell.l0.r5').should('exist');
38+
cy.get('[data-row=2] > .slick-cell:nth(1)').should('not.exist');
4039
});
4140

42-
it('should expect 4th row to be 4 columns and not be spanned', () => {
43-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(0)`).should('contain', 'Task 3');
44-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(1)`).should('contain', '5 days');
45-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(2)`).should('contain', '01/05/2009');
46-
cy.get(`[style*="top: ${GRID_ROW_HEIGHT * 3}px;"] > .slick-cell:nth(3)`).contains(/(true|false)/);
41+
it('should expect 4th row to contain the Duration colspan followed by the analysis columns', () => {
42+
cy.get('[data-row=3] > .slick-cell:nth(0)').should('contain', 'Task 3');
43+
cy.get('[data-row=3] > .slick-cell:nth(1)').should('contain', '5 days');
44+
cy.get('[data-row=3] > .slick-cell:nth(2)').contains(/\d+$/);
45+
cy.get('[data-row=3] > .slick-cell:nth(3)').contains(/(true|false)/);
46+
});
47+
48+
it('should hide Finish while keeping it in getColumns and preserve the original colspan indexes', () => {
49+
cy.get('[data-test="hide-finish-column"]').click();
50+
cy.get('#myGrid .slick-header-column').should('have.length', 5);
51+
cy.get('[data-row=1] > .slick-cell.l1.r3').should('contain', '5 days');
52+
cy.get('[data-row=1] > .slick-cell.l4.r4').contains(/\d+$/);
53+
cy.get('[data-row=1] > .slick-cell.l5.r5').contains(/(true|false)/);
54+
cy.get('[data-test="hide-finish-column"]').click();
55+
});
56+
57+
it('should spread Duration colspan across hidden columns when enabled', () => {
58+
cy.get('[data-test="hide-finish-column"]').click();
59+
cy.get('[data-test="spread-colspan-button"]').click();
60+
cy.get('[data-row=1] > .slick-cell.l1.r4').should('contain', '5 days');
61+
cy.get('[data-test="spread-colspan-button"]').click();
62+
cy.get('[data-test="hide-finish-column"]').click();
4763
});
4864

4965
describe('Basic Key Navigations', () => {

cypress/e2e/example-frozen-columns-and-column-group.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ describe('Example - Row Grouping Titles', () => {
102102
});
103103

104104
it('should be able to call column picker from the pre-header', () => {
105-
const fullPreTitlesWithoutId = ['Common Factor', 'Period', 'Period', 'Analysis'];
105+
const fullPreTitlesWithoutId = ['Common Factor', 'Period', 'Analysis'];
106106
const fullTitlesWithoutId = ['Title', 'Duration', 'Start', 'Finish', '% Complete', 'Effort Driven'];
107107
const fullTitlesWithGroup = ['#', 'Common Factor - Title', 'Common Factor - Duration', 'Period - Start', 'Period - Finish', 'Analysis - % Complete', 'Analysis - Effort Driven'];
108108

cypress/e2e/example-variable-row-height-frozen.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ describe('Example - Variable Row Height with Frozen Columns/Rows', { retries: 1
4747
it('should scroll both panes to a far row (top) keeping pane agreement', () => {
4848
cy.contains('button', 'Scroll both to row 300').click();
4949
// scrollRowToTop lands row 300 as the first visible row in both grids' scrolling panes
50-
cy.window().then(win => {
50+
cy.window().should(win => {
5151
expect((win as any).gridA.getViewport().top).to.eq(300);
5252
expect((win as any).gridB.getViewport().top).to.eq(300);
5353
});

cypress/e2e/example-variable-row-height-spans.cy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('Example - Variable Row Height with Cell Spans', { retries: 1 }, () =>
4949
it('should scroll a far span head to the top with consistent geometry', () => {
5050
cy.contains('button', 'Scroll far span').click();
5151
// scrollRowToTop lands row 299 as the first visible row (not merely into view at the bottom)
52-
cy.window().then(win => {
52+
cy.window().should(win => {
5353
expect((win as any).grid.getViewport().top).to.eq(299);
5454
});
5555
cy.get('#myGrid .slick-row[data-row=299] > .slick-cell.l0')

examples/example-0031-row-span-employees.html

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -245,29 +245,12 @@ <h2>
245245
// if column index(es) aren't changing then "invalidateRows()" or "invalidate()" might be sufficient
246246
// however, when column index(es) changed then you will have to call "remapAllColumnsRowSpan()" to clear & reevaluate the rowspan cache
247247
function toggleEmployeeIdVisibility() {
248-
const newMetadata = {};
249248
showEmployeeId = !showEmployeeId;
250-
251-
// direction to calculate new column indexes (-1 or +1 on the column index)
252-
// e.g. metadata = `{0:{columns:{1:{rowspan: 2}}}}` if we hide then new result is `{0:{columns:{0:{rowspan: 2}}}}`
253-
const dir = showEmployeeId ? 1 : -1;
254-
for (let row of Object.keys(metadata)) {
255-
newMetadata[row] = { columns: {} };
256-
for (let col of Object.keys(metadata[row].columns)) {
257-
newMetadata[row].columns[Number(col) + dir] = metadata[row].columns[col];
258-
}
259-
}
260-
261-
// update column definitions
262-
if (showEmployeeId) {
263-
columns.unshift({ id: "employeeID", name: "Employee ID", field: "employeeID", width: 100 });
264-
} else {
265-
columns.splice(0, 1);
266-
}
267-
grid.setColumns(columns);
268-
269-
// update & remap rowspans
270-
metadata = newMetadata;
249+
// Keep the complete column list and switch visibility with the hidden property.
250+
// This is the breaking-change behavior introduced by the column visibility migration.
251+
grid.setOptions({ frozenColumn: showEmployeeId ? 0 : -1 });
252+
grid.updateColumnById("employeeID", { hidden: !showEmployeeId });
253+
grid.updateColumns();
271254
grid.remapAllColumnsRowSpan();
272255
grid.invalidate();
273256
}
@@ -372,4 +355,4 @@ <h2>
372355
}
373356
</script>
374357
</body>
375-
</html>
358+
</html>

examples/example-colspan.html

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ <h2>
2020
<ul>
2121
<li>column span</li>
2222
</ul>
23+
<div style="margin-bottom: 10px">
24+
<button class="btn" data-test="hide-finish-column" onclick="toggleFinishColumn()">Hide/Show Finish Column</button>
25+
<button class="btn" data-test="spread-colspan-button" onclick="toggleSpreadHiddenColspan()">Toggle Spreading of ColSpan with Hidden Columns</button>
26+
</div>
2327
<h2>View Source:</h2>
2428
<ul>
2529
<li><A href="https://github.com/6pac/SlickGrid/blob/master/examples/example-colspan.html" target="_sourcewindow"> View the source for this example on Github</a></li>
@@ -41,18 +45,20 @@ <h2>View Source:</h2>
4145
<script>
4246
var grid;
4347
var columns = [
44-
{id: "title", name: "Title", field: "title"},
45-
{id: "duration", name: "Duration", field: "duration"},
46-
{id: "%", name: "% Complete", field: "percentComplete", selectable: false, width: 100},
47-
{id: "start", name: "Start", field: "start"},
48-
{id: "finish", name: "Finish", field: "finish"},
49-
{id: "effort-driven", name: "Effort Driven", field: "effortDriven", width: 100}
48+
{id: "title", name: "Title", field: "title", columnGroup: "Common Factor"},
49+
{id: "duration", name: "Duration", field: "duration", columnGroup: "Common Factor"},
50+
{id: "start", name: "Start", field: "start", columnGroup: "Period"},
51+
{id: "finish", name: "Finish", field: "finish", columnGroup: "Period"},
52+
{id: "%", name: "% Complete", field: "percentComplete", selectable: false, width: 100, columnGroup: "Analysis"},
53+
{id: "effort-driven", name: "Effort Driven", field: "effortDriven", width: 100, columnGroup: "Analysis"}
5054
];
5155

5256
var options = {
5357
enableCellNavigation: true,
54-
enableColumnReorder: false
58+
enableColumnReorder: false,
59+
spreadHiddenColspan: false
5560
};
61+
var isSpreadHiddenColspan = false;
5662

5763
document.addEventListener("DOMContentLoaded", function() {
5864
var data = [];
@@ -91,6 +97,19 @@ <h2>View Source:</h2>
9197

9298
grid.setSelectionModel(new Slick.CellSelectionModel());
9399
});
100+
101+
function toggleFinishColumn() {
102+
var finishColumn = grid.getColumnById("finish");
103+
grid.updateColumnById("finish", { hidden: !finishColumn.hidden });
104+
grid.updateColumns();
105+
}
106+
107+
function toggleSpreadHiddenColspan() {
108+
isSpreadHiddenColspan = !isSpreadHiddenColspan;
109+
grid.setOptions({ spreadHiddenColspan: isSpreadHiddenColspan });
110+
grid.resetActiveCell();
111+
grid.invalidate();
112+
}
94113
</script>
95114
</body>
96115
</html>

examples/example-draggable-header-grouping.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ <h2>View Source:</h2>
164164

165165
for (var i = 0; i < columns.length; i++) {
166166
m = columns[i];
167-
if (m) {
167+
if (m && !m.hidden) {
168168
if (lastColumnGroup === m.columnGroup && i > 0) {
169169
widthTotal += m.width || 0;
170170
headerElm.style.width = `${widthTotal - headerColumnWidthDiff}px`;

examples/example-frozen-columns-and-column-group-hidden-col.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ <h2>
4646
<br/>
4747
<h2>View Source:</h2>
4848
<ul>
49-
<li><A href="https://github.com/6pac/SlickGrid/blob/master/examples/example-frozen-columns-and-column-group.html" target="_sourcewindow"> View the source for this example on Github</a></li>
49+
<li><A href="https://github.com/6pac/SlickGrid/blob/master/examples/example-frozen-columns-and-column-group-hidden-col.html" target="_sourcewindow"> View the source for this example on Github</a></li>
5050
</ul>
5151
</div>
5252
</div>
@@ -220,14 +220,14 @@ <h2>View Source:</h2>
220220

221221
document.querySelector('#chkHideColumn1').addEventListener("change", function(e) {
222222
let hideCol = document.querySelector('#chkHideColumn1').checked || false;
223-
columns[2].hidden = hideCol;
223+
grid.updateColumnById('duration', { hidden: hideCol });
224224
grid.updateColumns();
225225
CreateAddlHeaderRow();
226226
});
227227

228228
document.querySelector('#chkHideColumn2').addEventListener("change", function(e) {
229229
let hideCol = document.querySelector('#chkHideColumn2').checked || false;
230-
columns[4].hidden = hideCol;
230+
grid.updateColumnById('finish', { hidden: hideCol });
231231
grid.updateColumns();
232232
CreateAddlHeaderRow();
233233
});

0 commit comments

Comments
 (0)