diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts index d02235cd5e2..c8b02b03ac6 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-integration.spec.ts @@ -198,6 +198,73 @@ describe('IgxTreeGrid - Integration #tGrid', () => { treeGrid = fix.componentInstance.treeGrid; }); + it('should preserve the order of records on inner levels', () => { + fix = TestBed.createComponent(IgxTreeGridPrimaryForeignKeyComponent); + fix.componentInstance.sortByName = true; + fix.detectChanges(); + treeGrid = fix.componentInstance.treeGrid; + + const expectedFlatData = [ + { + "ID": 1, + "ParentID": -1, + "Name": "Casey Houston", + "JobTitle": "Vice President", + "Age": 32 + }, + { + "ID": 2, + "ParentID": 1, + "Name": "Gilberto Todd", + "JobTitle": "Director", + "Age": 41 + }, + { + "ID": 7, + "ParentID": 2, + "Name": "Debra Morton", + "JobTitle": "Associate Software Developer", + "Age": 35 + }, + { + "ID": 3, + "ParentID": 2, + "Name": "Tanya Bennett", + "JobTitle": "Director", + "Age": 29 + }, + { + "ID": 4, + "ParentID": 1, + "Name": "Jack Simon", + "JobTitle": "Software Developer", + "Age": 33 + }, + { + "ID": 10, + "ParentID": -1, + "Name": "Eduardo Ramirez", + "JobTitle": "Manager", + "Age": 53 + }, + { + "ID": 9, + "ParentID": 10, + "Name": "Leslie Hansen", + "JobTitle": "Associate Software Developer", + "Age": 44 + }, + { + "ID": 6, + "ParentID": -1, + "Name": "Erma Walsh", + "JobTitle": "CEO", + "Age": 52 + }, + ] + expect(treeGrid.flatData).toEqual(expectedFlatData); + }); + it('should transform a non-tree column into a tree column when pinning it', () => { TreeGridFunctions.verifyTreeColumn(fix, 'ID', 5); diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.pipes.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.pipes.ts index 319724f9538..64271708e8d 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.pipes.ts @@ -53,30 +53,44 @@ export class IgxTreeGridHierarchizingPipe implements PipeTransform { return primaryKey ? rowData[primaryKey] : rowData; } - private hierarchizeFlatData(collection: any[], primaryKey: string, foreignKey: string, - map: Map, flatData: any[]): - ITreeGridRecord[] { - const result: ITreeGridRecord[] = []; - const missingParentRecords: ITreeGridRecord[] = []; + /** + * Converts a flat array of data into a hierarchical (tree) structure, + * preserving the original order of the records among siblings. + * + * It uses a two-pass approach: + * 1. Creates all ITreeGridRecord objects and populates the Map for quick lookup. + * 2. Links the records by iterating again, ensuring children are added to + * their parent's children array in the order they appeared in the + * original collection. + * + * @param collection The flat array of data to be hierarchized. This is the array whose order should be preserved. + * @param primaryKey The name of the property in the data objects that serves as the unique identifier (e.g., 'id'). + * @param foreignKey The name of the property in the data objects that links to the parent's primary key (e.g., 'parentId'). + * @param map A pre-existing Map object (key: primaryKey value, value: ITreeGridRecord) used to store and quickly look up all created records. + * @param flatData The original flat data array. Used for passing to the setIndentationLevels method (not directly used for hierarchy building). + * @returns An array of ITreeGridRecord objects representing the root nodes of the hierarchy, ordered as they appeared in the original collection. + */ + private hierarchizeFlatData( + collection: any[], + primaryKey: string, + foreignKey: string, + map: Map, + flatData: any[] + ): ITreeGridRecord[] { collection.forEach(row => { const record: ITreeGridRecord = { key: this.getRowID(primaryKey, row), data: row, children: [] }; - const parent = map.get(row[foreignKey]); - if (parent) { - record.parent = parent; - parent.children.push(record); - } else { - missingParentRecords.push(record); - } - map.set(row[primaryKey], record); }); - missingParentRecords.forEach(record => { - const parent = map.get(record.data[foreignKey]); + const result: ITreeGridRecord[] = []; + collection.forEach(row => { + const record: ITreeGridRecord = map.get(row[primaryKey])!; + const parent = map.get(row[foreignKey]); + if (parent) { record.parent = parent; parent.children.push(record); diff --git a/projects/igniteui-angular/src/lib/test-utils/tree-grid-components.spec.ts b/projects/igniteui-angular/src/lib/test-utils/tree-grid-components.spec.ts index 122aaa8a80f..9d0706598a8 100644 --- a/projects/igniteui-angular/src/lib/test-utils/tree-grid-components.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/tree-grid-components.spec.ts @@ -159,10 +159,17 @@ export class IgxTreeGridWithNoScrollsComponent { `, imports: [IgxTreeGridComponent, IgxColumnComponent, IgxPaginatorComponent] }) -export class IgxTreeGridPrimaryForeignKeyComponent { +export class IgxTreeGridPrimaryForeignKeyComponent implements OnInit { @ViewChild(IgxTreeGridComponent, { static: true }) public treeGrid: IgxTreeGridComponent; - public data = SampleTestData.employeePrimaryForeignKeyTreeData(); + public data = []; public paging = false; + public sortByName = false; + + public ngOnInit(): void { + this.data = !this.sortByName + ? SampleTestData.employeePrimaryForeignKeyTreeData() + : SampleTestData.employeePrimaryForeignKeyTreeData().sort((a, b) => a.Name.localeCompare(b.Name)); + } } @Component({