Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 1cea0dc

Browse files
authored
Merge pull request #1343 from ghiscoding/chore/cancellable-onbeforerowdetail
feat: (re)add option to cancel Row Detail opening
2 parents e101b63 + c0f8845 commit 1cea0dc

File tree

7 files changed

+237
-200
lines changed

7 files changed

+237
-200
lines changed

package.json

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@
5050
},
5151
"dependencies": {
5252
"@ngx-translate/core": "^15.0.0",
53-
"@slickgrid-universal/common": "~4.1.0",
54-
"@slickgrid-universal/custom-footer-component": "~4.1.0",
55-
"@slickgrid-universal/empty-warning-component": "~4.1.0",
56-
"@slickgrid-universal/event-pub-sub": "~4.1.0",
57-
"@slickgrid-universal/pagination-component": "~4.1.0",
58-
"@slickgrid-universal/row-detail-view-plugin": "~4.1.0",
59-
"@slickgrid-universal/rxjs-observable": "~4.1.0",
53+
"@slickgrid-universal/common": "~4.2.0",
54+
"@slickgrid-universal/custom-footer-component": "~4.2.0",
55+
"@slickgrid-universal/empty-warning-component": "~4.2.0",
56+
"@slickgrid-universal/event-pub-sub": "~4.2.0",
57+
"@slickgrid-universal/pagination-component": "~4.2.0",
58+
"@slickgrid-universal/row-detail-view-plugin": "~4.2.0",
59+
"@slickgrid-universal/rxjs-observable": "~4.2.0",
6060
"dequal": "^2.0.3",
6161
"dompurify": "^3.0.6",
6262
"rxjs": "^7.8.1",
@@ -87,24 +87,24 @@
8787
"@ngx-translate/http-loader": "^8.0.0",
8888
"@popperjs/core": "^2.11.8",
8989
"@release-it/conventional-changelog": "^8.0.1",
90-
"@slickgrid-universal/composite-editor-component": "~4.1.0",
91-
"@slickgrid-universal/custom-tooltip-plugin": "~4.1.0",
92-
"@slickgrid-universal/excel-export": "~4.1.0",
93-
"@slickgrid-universal/graphql": "~4.1.0",
94-
"@slickgrid-universal/odata": "~4.1.0",
95-
"@slickgrid-universal/text-export": "~4.1.0",
90+
"@slickgrid-universal/composite-editor-component": "~4.2.0",
91+
"@slickgrid-universal/custom-tooltip-plugin": "~4.2.0",
92+
"@slickgrid-universal/excel-export": "~4.2.0",
93+
"@slickgrid-universal/graphql": "~4.2.0",
94+
"@slickgrid-universal/odata": "~4.2.0",
95+
"@slickgrid-universal/text-export": "~4.2.0",
9696
"@types/dompurify": "^3.0.5",
9797
"@types/flatpickr": "^3.1.2",
9898
"@types/fnando__sparkline": "^0.3.7",
9999
"@types/jest": "^29.5.11",
100-
"@types/node": "^20.10.5",
100+
"@types/node": "^20.10.6",
101101
"@types/sortablejs": "^1.15.7",
102-
"@typescript-eslint/eslint-plugin": "^6.15.0",
103-
"@typescript-eslint/parser": "^6.15.0",
102+
"@typescript-eslint/eslint-plugin": "^6.16.0",
103+
"@typescript-eslint/parser": "^6.16.0",
104104
"bootstrap": "^5.3.2",
105105
"copyfiles": "^2.4.1",
106106
"custom-event-polyfill": "^1.0.7",
107-
"cypress": "^13.6.1",
107+
"cypress": "^13.6.2",
108108
"eslint": "^8.56.0",
109109
"fetch-jsonp": "^1.3.0",
110110
"font-awesome": "^4.7.0",
@@ -118,7 +118,7 @@
118118
"release-it": "^17.0.1",
119119
"rimraf": "^5.0.5",
120120
"rxjs": "^7.8.1",
121-
"sass": "^1.69.5",
121+
"sass": "^1.69.6",
122122
"servor": "^4.0.2",
123123
"stream-browserify": "^3.0.0",
124124
"ts-node": "^10.9.2",

src/app/examples/grid-rowdetail.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ <h2>
1515
<button class="btn btn-outline-secondary btn-xs" (click)="changeEditableGrid()" data-test="editable-grid-btn">
1616
Make Grid Editable
1717
</button>
18-
<button class="btn btn-outline-secondary btn-xs" (click)="closeAllRowDetail()" data-test="close-all-btn">
18+
<button class="btn btn-outline-secondary btn-xs" (click)="closeAllRowDetail()" data-test="collapse-all-btn">
1919
Close All Row Details
2020
</button>
2121
&nbsp;&nbsp;

src/app/examples/grid-rowdetail.component.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,17 @@ export class GridRowDetailComponent implements OnInit {
123123
viewComponent: RowDetailViewComponent,
124124

125125
// Optionally pass your Parent Component reference to your Child Component (row detail component)
126-
parent: this
126+
parent: this,
127+
128+
onBeforeRowDetailToggle: (e, args) => {
129+
// you coud cancel opening certain rows
130+
// if (args.item.rowId === 1) {
131+
// e.preventDefault();
132+
// return false;
133+
// }
134+
console.log('before toggling row detail', args.item);
135+
return true;
136+
},
127137
}
128138
};
129139

@@ -165,6 +175,7 @@ export class GridRowDetailComponent implements OnInit {
165175
}
166176

167177
changeEditableGrid() {
178+
this.rowDetailInstance.collapseAll();
168179
this.rowDetailInstance.addonOptions.useRowClick = false;
169180
this.gridOptions.autoCommitEdit = !this.gridOptions.autoCommitEdit;
170181
this.angularGrid?.slickGrid.setOptions({

src/app/modules/angular-slickgrid/extensions/__tests__/slickRowDetailView.spec.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ const gridOptionsMock = {
4747
useSimpleViewportCalc: true,
4848
saveDetailViewOnScroll: false,
4949
process: () => new Promise((resolve) => resolve('process resolved')),
50-
viewComponent: null,
50+
viewComponent: null as any,
5151
onExtensionRegistered: jest.fn(),
5252
onAsyncResponse: () => { },
5353
onAsyncEndUpdate: () => { },
@@ -309,11 +309,6 @@ describe('SlickRowDetailView', () => {
309309
plugin.register();
310310
plugin.onBeforeRowDetailToggle.notify({ item: columnsMock[0], grid: gridStub }, new SlickEventData(), gridStub);
311311

312-
// expect(handlerSpy).toHaveBeenCalledTimes(8); // there are an extra 2x on the grid itself
313-
// expect(handlerSpy).toHaveBeenCalledWith(
314-
// { notify: expect.anything(), subscribe: expect.anything(), unsubscribe: expect.anything(), },
315-
// expect.anything()
316-
// );
317312
expect(onAsyncRespSpy).not.toHaveBeenCalled();
318313
expect(onAsyncEndSpy).not.toHaveBeenCalled();
319314
expect(onAfterRowSpy).not.toHaveBeenCalled();
@@ -656,6 +651,28 @@ describe('SlickRowDetailView', () => {
656651
expect(disposeSpy).toHaveBeenCalled();
657652
expect(disposeAllSpy).toHaveBeenCalled();
658653
});
654+
655+
it('should call internal event handler subscribe and expect the "onBeforeRowDetailToggle" option to be called and return true when addon notify is called', () => {
656+
gridOptionsMock.rowDetailView!.onBeforeRowDetailToggle = undefined;
657+
const onAsyncRespSpy = jest.spyOn(gridOptionsMock.rowDetailView as RowDetailView, 'onAsyncResponse');
658+
const onAsyncEndSpy = jest.spyOn(gridOptionsMock.rowDetailView as RowDetailView, 'onAsyncEndUpdate');
659+
const onAfterRowSpy = jest.spyOn(gridOptionsMock.rowDetailView as RowDetailView, 'onAfterRowDetailToggle');
660+
// const onBeforeRowSpy = jest.spyOn(gridOptionsMock.rowDetailView as RowDetailView, 'onBeforeRowDetailToggle');
661+
const onRowOutViewSpy = jest.spyOn(gridOptionsMock.rowDetailView as RowDetailView, 'onRowOutOfViewportRange');
662+
const onRowBackViewSpy = jest.spyOn(gridOptionsMock.rowDetailView as RowDetailView, 'onRowBackToViewportRange');
663+
664+
plugin.init(gridStub);
665+
plugin.onBeforeRowDetailToggle = new SlickEvent();
666+
plugin.register();
667+
const result = plugin.onBeforeRowDetailToggle.notify({ item: columnsMock[0], grid: gridStub }, new SlickEventData(), gridStub);
668+
669+
expect(result.getReturnValue()).toEqual(true);
670+
expect(onAsyncRespSpy).not.toHaveBeenCalled();
671+
expect(onAsyncEndSpy).not.toHaveBeenCalled();
672+
expect(onAfterRowSpy).not.toHaveBeenCalled();
673+
expect(onRowOutViewSpy).not.toHaveBeenCalled();
674+
expect(onRowBackViewSpy).not.toHaveBeenCalled();
675+
});
659676
});
660677

661678
describe('possible error thrown', () => {

src/app/modules/angular-slickgrid/extensions/slickRowDetailView.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,9 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {
164164
this.handleOnBeforeRowDetailToggle(e, args);
165165

166166
if (this.rowDetailViewOptions && typeof this.rowDetailViewOptions.onBeforeRowDetailToggle === 'function') {
167-
this.rowDetailViewOptions.onBeforeRowDetailToggle(e, args);
167+
return this.rowDetailViewOptions.onBeforeRowDetailToggle(e, args);
168168
}
169+
return true;
169170
});
170171
}
171172

@@ -329,7 +330,7 @@ export class SlickRowDetailView extends UniversalSlickRowDetailView {
329330
*/
330331
protected handleOnBeforeRowDetailToggle(e: Event, args: { grid: SlickGrid; item: any; }) {
331332
// expanding
332-
if (args && args.item && args.item.__collapsed) {
333+
if (args?.item?.__collapsed) {
333334
// expanding row detail
334335
const viewInfo: CreatedView = {
335336
id: args.item[this.datasetIdPropName],

test/cypress/e2e/example21.cy.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ describe('Example 21 - Row Detail View', () => {
137137
.find('h3')
138138
.contains('Task 0');
139139

140-
cy.get('[data-test=close-all-btn]')
140+
cy.get('[data-test=collapse-all-btn]')
141141
.click();
142142

143143
cy.get('.slick-viewport-top.slick-viewport-left')
@@ -164,7 +164,7 @@ describe('Example 21 - Row Detail View', () => {
164164
});
165165

166166
it('should open a few Row Details, then sort by Title and expect all Row Details to be closed afterward', () => {
167-
const expectedTasks = ['Task 1', 'Task 10', 'Task 100', 'Task 101', 'Task 102', 'Task 103', 'Task 104'];
167+
const expectedTasks = ['Task 0', 'Task 1', 'Task 10', 'Task 100', 'Task 101', 'Task 102', 'Task 103', 'Task 104'];
168168

169169
cy.get('#grid21')
170170
.find('.slick-row:nth(0)')
@@ -247,24 +247,28 @@ describe('Example 21 - Row Detail View', () => {
247247
});
248248
});
249249

250-
it('should click open Row Detail of Task 102 then type a title filter of "Task 102" and expect Row Detail to be opened and still be rendered', () => {
250+
it('should click open Row Detail of Task 1 and Task 101 then type a title filter of "Task 101" and expect Row Detail to be opened and still be rendered', () => {
251251
cy.get('#grid21')
252252
.find('.slick-row:nth(4)')
253253
.click();
254254

255255
cy.get('#grid21')
256-
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_102 .container_102')
256+
.find('.slick-row:nth(1)')
257+
.click();
258+
259+
cy.get('#grid21')
260+
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_101')
257261
.as('detailContainer');
258262

259263
cy.get('@detailContainer')
260264
.find('h3')
261-
.contains('Task 102');
265+
.contains('Task 101');
262266

263267
cy.get('.search-filter.filter-title')
264-
.type('Task 102');
268+
.type('Task 101');
265269
});
266270

267-
it('should call "Clear all Filters" from Grid Menu and expect "Task 102" to still be rendered correctly', () => {
271+
it('should call "Clear all Filters" from Grid Menu and expect "Task 101" to still be rendered correctly', () => {
268272
cy.get('#grid21')
269273
.find('button.slick-grid-menu-button')
270274
.trigger('click')
@@ -278,15 +282,15 @@ describe('Example 21 - Row Detail View', () => {
278282
.click();
279283

280284
cy.get('#grid21')
281-
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_102 .container_102')
285+
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_101')
282286
.as('detailContainer');
283287

284288
cy.get('@detailContainer')
285289
.find('h3')
286-
.contains('Task 102');
290+
.contains('Task 101');
287291
});
288292

289-
it('should call "Clear all Sorting" from Grid Menu and expect "Task 102" to still be rendered correctly', () => {
293+
it('should call "Clear all Sorting" from Grid Menu and expect all row details to be collapsed', () => {
290294
cy.get('#grid21')
291295
.find('button.slick-grid-menu-button')
292296
.trigger('click')
@@ -302,45 +306,39 @@ describe('Example 21 - Row Detail View', () => {
302306
.find('.slick-sort-indicator-asc')
303307
.should('have.length', 0);
304308

305-
cy.get('#grid21')
306-
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_102 .container_102')
307-
.as('detailContainer');
308-
309-
cy.get('@detailContainer')
310-
.find('h3')
311-
.contains('Task 102');
309+
cy.get('.dynamic-cell-detail').should('have.length', 0);
312310
});
313311

314312
it('should close all row details & make grid editable', () => {
315-
cy.get('[data-test="close-all-btn"]').click();
313+
cy.get('[data-test="collapse-all-btn"]').click();
316314
cy.get('[data-test="editable-grid-btn"]').click();
317315
});
318316

319-
it('should click on 3rd row detail open icon and expect it to open', () => {
317+
it('should click on 5th row detail open icon and expect it to open', () => {
320318
cy.get('#grid21')
321-
.find('.slick-row:nth(2) .slick-cell:nth(0)')
319+
.find('.slick-row:nth(4) .slick-cell:nth(0)')
322320
.click();
323321

324322
cy.get('#grid21')
325-
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_100 .container_100')
323+
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_101')
326324
.as('detailContainer');
327325

328326
cy.get('@detailContainer')
329327
.find('h3')
330-
.contains('Task 100');
328+
.contains('Task 101');
331329
});
332330

333-
it('should click on 1st row "Title" cell to edit it and expect row detail to get closed', () => {
331+
it('should click on 2nd row "Title" cell to edit it and expect Task 5 row detail to get closed', () => {
334332
cy.get('#grid21')
335333
.find('.slick-row:nth(1) .slick-cell:nth(1)')
336334
.click();
337335

338336
cy.get('.editor-title')
339337
.invoke('val')
340-
.then(text => expect(text).to.eq('Task 10'));
338+
.then(text => expect(text).to.eq('Task 1'));
341339

342340
cy.get('#grid21')
343-
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_100 .container_100')
341+
.find('.slick-cell + .dynamic-cell-detail .innerDetailView_101')
344342
.should('not.exist');
345343
});
346344
});

0 commit comments

Comments
 (0)