Skip to content

Commit 91c48a2

Browse files
committed
fix(tree): using initiallyCollapsed change internal toggled state
- if we defined `initiallyCollapsed` as true, we should expect the internal toggle state change to be updated accordingly - also add extra arguments to the `applyToggledItemStateChanges()` method to skip a full toggle and also another argument to optionally trigger an item toggled event
1 parent 60ae015 commit 91c48a2

File tree

2 files changed

+88
-17
lines changed

2 files changed

+88
-17
lines changed

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

+53-10
Original file line numberDiff line numberDiff line change
@@ -332,13 +332,14 @@ describe('SortService', () => {
332332
const beginUpdateSpy = jest.spyOn(dataViewStub, 'beginUpdate');
333333
const endUpdateSpy = jest.spyOn(dataViewStub, 'endUpdate');
334334
const updateItemSpy = jest.spyOn(dataViewStub, 'updateItem');
335-
// const pubSubSpy = jest.spyOn(pubSubServiceStub, 'publish');
335+
const rxStartSpy = jest.spyOn(sharedService.onTreeFullToggleStart, 'next');
336+
const rxEndSpy = jest.spyOn(sharedService.onTreeFullToggleEnd, 'next');
336337

337338
service.init(gridStub);
338339
service.toggleTreeDataCollapse(true);
339340

340-
// expect(pubSubSpy).toHaveBeenCalledWith(`onTreeFullToggleStart`, { collapsing: true });
341-
// expect(pubSubSpy).toHaveBeenCalledWith(`onTreeFullToggleEnd`, { type: 'full-collapse', previousFullToggleType: 'full-collapse', toggledItems: null, });
341+
expect(rxStartSpy).toHaveBeenCalledWith({ collapsing: true });
342+
expect(rxEndSpy).toHaveBeenCalledWith({ type: 'full-collapse', previousFullToggleType: 'full-collapse', toggledItems: null, });
342343
expect(dataGetItemsSpy).toHaveBeenCalled();
343344
expect(beginUpdateSpy).toHaveBeenCalled();
344345
expect(updateItemSpy).toHaveBeenNthCalledWith(1, 0, { __collapsed: true, __hasChildren: true, id: 0, file: 'TXT', size: 5.8 });
@@ -356,13 +357,14 @@ describe('SortService', () => {
356357
const beginUpdateSpy = jest.spyOn(dataViewStub, 'beginUpdate');
357358
const endUpdateSpy = jest.spyOn(dataViewStub, 'endUpdate');
358359
const updateItemSpy = jest.spyOn(dataViewStub, 'updateItem');
359-
// const pubSubSpy = jest.spyOn(pubSubServiceStub, 'publish');
360+
const rxStartSpy = jest.spyOn(sharedService.onTreeFullToggleStart, 'next');
361+
const rxEndSpy = jest.spyOn(sharedService.onTreeFullToggleEnd, 'next');
360362

361363
service.init(gridStub);
362364
service.toggleTreeDataCollapse(true);
363365

364-
// expect(pubSubSpy).toHaveBeenCalledWith(`onTreeFullToggleStart`, { collapsing: true });
365-
// expect(pubSubSpy).toHaveBeenCalledWith(`onTreeFullToggleEnd`, { type: 'full-collapse', previousFullToggleType: 'full-collapse', toggledItems: null, });
366+
expect(rxStartSpy).toHaveBeenCalledWith({ collapsing: true });
367+
expect(rxEndSpy).toHaveBeenCalledWith({ type: 'full-collapse', previousFullToggleType: 'full-collapse', toggledItems: null, });
366368
expect(dataGetItemsSpy).toHaveBeenCalled();
367369
expect(dataGetItemsSpy).toHaveBeenCalled();
368370
expect(beginUpdateSpy).toHaveBeenCalled();
@@ -376,13 +378,14 @@ describe('SortService', () => {
376378
const beginUpdateSpy = jest.spyOn(dataViewStub, 'beginUpdate');
377379
const endUpdateSpy = jest.spyOn(dataViewStub, 'endUpdate');
378380
const updateItemSpy = jest.spyOn(dataViewStub, 'updateItem');
379-
// const pubSubSpy = jest.spyOn(pubSubServiceStub, 'publish');
381+
const rxStartSpy = jest.spyOn(sharedService.onTreeFullToggleStart, 'next');
382+
const rxEndSpy = jest.spyOn(sharedService.onTreeFullToggleEnd, 'next');
380383

381384
service.init(gridStub);
382385
service.toggleTreeDataCollapse(false);
383386

384-
// expect(pubSubSpy).toHaveBeenCalledWith(`onTreeFullToggleStart`, { collapsing: false });
385-
// expect(pubSubSpy).toHaveBeenCalledWith(`onTreeFullToggleEnd`, { type: 'full-expand', previousFullToggleType: 'full-expand', toggledItems: null, });
387+
expect(rxStartSpy).toHaveBeenCalledWith({ collapsing: false });
388+
expect(rxEndSpy).toHaveBeenCalledWith({ type: 'full-expand', previousFullToggleType: 'full-expand', toggledItems: null, });
386389
expect(dataGetItemsSpy).toHaveBeenCalled();
387390
expect(beginUpdateSpy).toHaveBeenCalled();
388391
expect(updateItemSpy).toHaveBeenNthCalledWith(1, 0, { __collapsed: false, __hasChildren: true, id: 0, file: 'TXT', size: 5.8 });
@@ -391,20 +394,60 @@ describe('SortService', () => {
391394
});
392395

393396
describe('applyToggledItemStateChanges method', () => {
394-
it('should execute the method', () => {
397+
it('should execute the method and expect a full toggle or items', () => {
395398
const dataGetItemsSpy = jest.spyOn(dataViewStub, 'getItems').mockReturnValue(mockFlatDataset);
396399
jest.spyOn(dataViewStub, 'getItemById').mockReturnValue(mockFlatDataset[3]);
397400
jest.spyOn(SharedService.prototype, 'hierarchicalDataset', 'get').mockReturnValue(mockHierarchical);
398401
const beginUpdateSpy = jest.spyOn(dataViewStub, 'beginUpdate');
399402
const endUpdateSpy = jest.spyOn(dataViewStub, 'endUpdate');
400403
const updateItemSpy = jest.spyOn(dataViewStub, 'updateItem');
404+
const rxToggleSpy = jest.spyOn(sharedService.onTreeItemToggled, 'next');
401405

402406
service.init(gridStub);
403407
service.applyToggledItemStateChanges([{ itemId: 4, isCollapsed: true }]);
404408

405409
expect(dataGetItemsSpy).toHaveBeenCalled();
406410
expect(beginUpdateSpy).toHaveBeenCalled();
407411
expect(updateItemSpy).toHaveBeenNthCalledWith(1, 4, { __collapsed: true, __hasChildren: true, id: 4, file: 'MP3', size: 3.4 });
412+
expect(rxToggleSpy).not.toHaveBeenCalled();
413+
expect(endUpdateSpy).toHaveBeenCalled();
414+
});
415+
416+
it('should execute the method but without calling "getItems" to skip doing a full toggle of items', () => {
417+
const dataGetItemsSpy = jest.spyOn(dataViewStub, 'getItems').mockReturnValue(mockFlatDataset);
418+
jest.spyOn(dataViewStub, 'getItemById').mockReturnValue(mockFlatDataset[3]);
419+
jest.spyOn(SharedService.prototype, 'hierarchicalDataset', 'get').mockReturnValue(mockHierarchical);
420+
const beginUpdateSpy = jest.spyOn(dataViewStub, 'beginUpdate');
421+
const endUpdateSpy = jest.spyOn(dataViewStub, 'endUpdate');
422+
const updateItemSpy = jest.spyOn(dataViewStub, 'updateItem');
423+
const rxToggleSpy = jest.spyOn(sharedService.onTreeItemToggled, 'next');
424+
425+
service.init(gridStub);
426+
service.applyToggledItemStateChanges([{ itemId: 4, isCollapsed: true }], 'full-collapse', false, true);
427+
428+
expect(dataGetItemsSpy).not.toHaveBeenCalled();
429+
expect(beginUpdateSpy).toHaveBeenCalled();
430+
expect(updateItemSpy).toHaveBeenNthCalledWith(1, 4, { __collapsed: true, __hasChildren: true, id: 4, file: 'MP3', size: 3.4 });
431+
expect(rxToggleSpy).toHaveBeenCalledWith({ fromItemId: 4, previousFullToggleType: 'full-collapse', toggledItems: [{ itemId: 4, isCollapsed: true }], type: 'toggle-collapse' });
432+
expect(endUpdateSpy).toHaveBeenCalled();
433+
});
434+
435+
it('should execute the method and also trigger an event when specified', () => {
436+
const dataGetItemsSpy = jest.spyOn(dataViewStub, 'getItems').mockReturnValue(mockFlatDataset);
437+
jest.spyOn(dataViewStub, 'getItemById').mockReturnValue(mockFlatDataset[3]);
438+
jest.spyOn(SharedService.prototype, 'hierarchicalDataset', 'get').mockReturnValue(mockHierarchical);
439+
const beginUpdateSpy = jest.spyOn(dataViewStub, 'beginUpdate');
440+
const endUpdateSpy = jest.spyOn(dataViewStub, 'endUpdate');
441+
const updateItemSpy = jest.spyOn(dataViewStub, 'updateItem');
442+
const rxToggleSpy = jest.spyOn(sharedService.onTreeItemToggled, 'next');
443+
444+
service.init(gridStub);
445+
service.applyToggledItemStateChanges([{ itemId: 4, isCollapsed: true }], 'full-collapse', true, true);
446+
447+
expect(dataGetItemsSpy).toHaveBeenCalled();
448+
expect(beginUpdateSpy).toHaveBeenCalled();
449+
expect(updateItemSpy).toHaveBeenNthCalledWith(1, 4, { __collapsed: true, __hasChildren: true, id: 4, file: 'MP3', size: 3.4 });
450+
expect(rxToggleSpy).toHaveBeenCalledWith({ fromItemId: 4, previousFullToggleType: 'full-collapse', toggledItems: [{ itemId: 4, isCollapsed: true }], type: 'toggle-collapse' });
408451
expect(endUpdateSpy).toHaveBeenCalled();
409452
});
410453
});

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

+35-7
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,11 @@ export class TreeDataService {
9494
* Apply different tree toggle state changes by providing an array of parentIds that are designated as collapsed (or not).
9595
* User will have to provide an array of `parentId` and `isCollapsed` boolean and the code will only apply the ones that are tagged as collapsed, everything else will be expanded
9696
* @param {Array<TreeToggledItem>} treeToggledItems - array of parentId which are tagged as changed
97+
* @param {ToggleStateChangeType} previousFullToggleType - optionally provide the previous full toggle type ('full-expand' or 'full-collapse')
98+
* @param {Boolean} shouldPreProcessFullToggle - should we pre-process a full toggle on all items? defaults to True
99+
* @param {Boolean} shouldTriggerEvent - should we trigger a toggled item event? defaults to False
97100
*/
98-
applyToggledItemStateChanges(treeToggledItems: TreeToggledItem[], previousFullToggleType?: Exclude<ToggleStateChangeType, 'toggle'> | Exclude<ToggleStateChangeTypeString, 'toggle'>) {
101+
applyToggledItemStateChanges(treeToggledItems: TreeToggledItem[], previousFullToggleType?: Exclude<ToggleStateChangeType, 'toggle'> | Exclude<ToggleStateChangeTypeString, 'toggle'>, shouldPreProcessFullToggle = true, shouldTriggerEvent = false) {
99102
if (Array.isArray(treeToggledItems)) {
100103
const collapsedPropName = this.getTreeDataOptionPropName('collapsedPropName');
101104
const hasChildrenPropName = this.getTreeDataOptionPropName('hasChildrenPropName');
@@ -107,17 +110,42 @@ export class TreeDataService {
107110
// we first need to put back the previous full toggle state (whether it was a full collapse or expand) by collapsing/expanding everything depending on the last toggled that was called `isLastFullToggleCollapsed`
108111
const previousFullToggle = previousFullToggleType ?? this._lastToggleStateChange.previousFullToggleType;
109112
const shouldCollapseAll = previousFullToggle === 'full-collapse';
110-
(this.dataView.getItems() || []).forEach((item: any) => {
111-
// collapse/expand the item but only when it's a parent item with children
112-
if (item[hasChildrenPropName]) {
113-
item[collapsedPropName] = shouldCollapseAll;
114-
}
115-
});
113+
114+
// when full toggle type is provided, we also need to update our internal reference of our current toggle state
115+
if (previousFullToggleType) {
116+
this._lastToggleStateChange.previousFullToggleType = previousFullToggleType;
117+
}
118+
119+
// typically (optionally and defaults to true) if we want to reapply some toggled items we probably want to be in the full toggled state as it was at the start
120+
// collapse/expand from the last full toggle state, all the items which are parent items with children
121+
if (shouldPreProcessFullToggle) {
122+
(this.dataView.getItems() || []).forEach((item: any) => {
123+
if (item[hasChildrenPropName]) {
124+
item[collapsedPropName] = shouldCollapseAll;
125+
}
126+
});
127+
}
116128

117129
// then we reapply only the ones that changed (provided as argument to the function)
118130
for (const collapsedItem of treeToggledItems) {
119131
const item = this.dataView.getItemById(collapsedItem.itemId);
120132
this.updateToggledItem(item, collapsedItem.isCollapsed);
133+
134+
if (shouldTriggerEvent) {
135+
const parentFoundIdx = this._currentToggledItems.findIndex(treeChange => treeChange.itemId === collapsedItem.itemId);
136+
if (parentFoundIdx >= 0) {
137+
this._currentToggledItems[parentFoundIdx].isCollapsed = collapsedItem.isCollapsed;
138+
} else {
139+
this._currentToggledItems.push({ itemId: collapsedItem.itemId, isCollapsed: collapsedItem.isCollapsed });
140+
}
141+
142+
this.sharedService.onTreeItemToggled.next({
143+
...this._lastToggleStateChange,
144+
fromItemId: collapsedItem.itemId,
145+
toggledItems: this._currentToggledItems,
146+
type: collapsedItem.isCollapsed ? ToggleStateChangeType.toggleCollapse : ToggleStateChangeType.toggleExpand
147+
} as TreeToggleStateChange);
148+
}
121149
}
122150

123151
// close the update transaction & call a refresh which will trigger a re-render with filters applied (including expand/collapse)

0 commit comments

Comments
 (0)