From 60059340850fe53c22ac810d8c66c0fc3ad6bca3 Mon Sep 17 00:00:00 2001 From: Linus Schlumberger Date: Mon, 9 Dec 2024 13:51:52 +0100 Subject: [PATCH] feat(tree): allow specifying key where tree status is saved --- .../src/lib/components/body/body.component.ts | 14 +++++- .../lib/components/datatable.component.html | 1 + .../src/lib/components/datatable.component.ts | 14 ++++-- projects/ngx-datatable/src/lib/utils/tree.ts | 49 ++++++++++++++++--- src/app/tree/client-tree.component.ts | 12 +++-- src/assets/data/company_tree.json | 18 +++---- 6 files changed, 84 insertions(+), 24 deletions(-) diff --git a/projects/ngx-datatable/src/lib/components/body/body.component.ts b/projects/ngx-datatable/src/lib/components/body/body.component.ts index aa6ef90a1..b44655e2b 100644 --- a/projects/ngx-datatable/src/lib/components/body/body.component.ts +++ b/projects/ngx-datatable/src/lib/components/body/body.component.ts @@ -40,6 +40,7 @@ import { DataTableSummaryRowComponent } from './summary/summary-row.component'; import { DataTableSelectionComponent } from './selection.component'; import { DataTableGhostLoaderComponent } from './ghost-loader/ghost-loader.component'; import { ProgressBarComponent } from './progress-bar.component'; +import { getByNestedIndex } from '../../utils/tree'; @Component({ selector: 'datatable-body', @@ -138,7 +139,7 @@ import { ProgressBarComponent } from './progress-bar.component'; [expanded]="getRowExpanded(group)" [rowClass]="rowClass" [displayCheck]="displayCheck" - [treeStatus]="group?.treeStatus" + [treeStatus]="getTreeStatus(group)" [ghostLoadingIndicator]="ghostLoadingIndicator" [draggable]="rowDraggable" [verticalScrollVisible]="verticalScrollVisible" @@ -172,7 +173,7 @@ import { ProgressBarComponent } from './progress-bar.component'; [expanded]="getRowExpanded(group)" [rowClass]="rowClass" [displayCheck]="displayCheck" - [treeStatus]="group?.treeStatus" + [treeStatus]="getTreeStatus(group)" [ghostLoadingIndicator]="ghostLoadingIndicator" [draggable]="rowDraggable" [verticalScrollVisible]="verticalScrollVisible" @@ -394,6 +395,8 @@ export class DataTableBodyComponent = new EventEmitter(); @Output() page: EventEmitter = new EventEmitter(); @Output() activate: EventEmitter> = new EventEmitter(); @@ -958,6 +961,13 @@ export class DataTableBodyComponent): TreeStatus { + return getByNestedIndex(row, this.treeStatusKey); + } + onTreeAction(row: TRow) { this.treeAction.emit({ row }); } diff --git a/projects/ngx-datatable/src/lib/components/datatable.component.html b/projects/ngx-datatable/src/lib/components/datatable.component.html index d51309697..10d9a7560 100644 --- a/projects/ngx-datatable/src/lib/components/datatable.component.html +++ b/projects/ngx-datatable/src/lib/components/datatable.component.html @@ -73,6 +73,7 @@ [rowDraggable]="rowDraggable" [rowDragEvents]="rowDragEvents" [rowDefTemplate]="rowDefTemplate" + [treeStatusKey]="treeStatusKey" > diff --git a/projects/ngx-datatable/src/lib/components/datatable.component.ts b/projects/ngx-datatable/src/lib/components/datatable.component.ts index 8b4097603..44893c02f 100644 --- a/projects/ngx-datatable/src/lib/components/datatable.component.ts +++ b/projects/ngx-datatable/src/lib/components/datatable.component.ts @@ -443,6 +443,11 @@ export class DatatableComponent */ @Input() treeToRelation: string; + /** + * The key of the row used to store the tree status, can be nested by separating keys with "." + */ + @Input() treeStatusKey = 'treeStatus'; + /** * A flag for switching summary row on / off */ @@ -862,7 +867,8 @@ export class DatatableComponent this._internalRows = groupRowsByParents( this._internalRows, optionalGetterForProp(this.treeFromRelation), - optionalGetterForProp(this.treeToRelation) + optionalGetterForProp(this.treeToRelation), + this.treeStatusKey ); if (this._rows && this._groupRowsBy) { @@ -1205,7 +1211,8 @@ export class DatatableComponent this._internalRows = groupRowsByParents( this._internalRows, optionalGetterForProp(this.treeFromRelation), - optionalGetterForProp(this.treeToRelation) + optionalGetterForProp(this.treeToRelation), + this.treeStatusKey ); // Always go to first page when sorting to see the newly sorted data @@ -1306,7 +1313,8 @@ export class DatatableComponent this._internalRows = groupRowsByParents( this._internalRows, optionalGetterForProp(this.treeFromRelation), - optionalGetterForProp(this.treeToRelation) + optionalGetterForProp(this.treeToRelation), + this.treeStatusKey ); } } diff --git a/projects/ngx-datatable/src/lib/utils/tree.ts b/projects/ngx-datatable/src/lib/utils/tree.ts index 4fd4dcf4c..cd3a068fe 100644 --- a/projects/ngx-datatable/src/lib/utils/tree.ts +++ b/projects/ngx-datatable/src/lib/utils/tree.ts @@ -1,5 +1,6 @@ import { getterForProp } from './column-prop-getters'; import { TableColumnProp } from '../types/table-column.type'; +import { TreeStatus } from '../types/public.types'; export type OptionalValueGetter = (row: any) => any | undefined; export function optionalGetterForProp(prop: TableColumnProp): OptionalValueGetter { @@ -45,14 +46,15 @@ export function optionalGetterForProp(prop: TableColumnProp): OptionalValueGette export function groupRowsByParents( rows: TRow[], from?: OptionalValueGetter, - to?: OptionalValueGetter + to?: OptionalValueGetter, + statusIndex = 'treeStatus' ): TRow[] { if (from && to) { const nodeById = {}; const l = rows.length; let node: TreeNode | null = null; - nodeById[0] = new TreeNode(); // that's the root node + nodeById[0] = new TreeNode(null, statusIndex); // that's the root node const uniqIDs = rows.reduce((arr, item) => { const toValue = to(item); @@ -64,7 +66,7 @@ export function groupRowsByParents( for (let i = 0; i < l; i++) { // make TreeNode objects for each item - nodeById[to(rows[i])] = new TreeNode(rows[i]); + nodeById[to(rows[i])] = new TreeNode(rows[i], statusIndex); } for (let i = 0; i < l; i++) { @@ -91,25 +93,60 @@ export function groupRowsByParents( } } +export const getByNestedIndex = (obj: any, index: string) => { + console.log(obj); + let prop: any = obj; + index.split('.').forEach(indexPart => { + if (prop !== undefined) { + prop = prop[indexPart]; + } + }); + console.log(prop); + return prop; +}; + +export const createWithNestedIndex = (index: string, val: any) => { + const rootProp: any = {}; + let prop: any = rootProp; + const splitIndex = index.split('.'); + splitIndex.forEach((indexPart, i) => { + if (i === splitIndex.length - 1) { + prop[indexPart] = val; + return; + } + if (prop[indexPart] === undefined) { + prop[indexPart] = {}; + } + prop = prop[indexPart]; + }); + return rootProp; +}; + class TreeNode { public row: any; public parent: any; public children: any[]; + private statusIndex: string; - constructor(row: any | null = null) { + constructor(row: any | null = null, statusIndex = 'treeStatus') { if (!row) { row = { level: -1, - treeStatus: 'expanded' + ...createWithNestedIndex(statusIndex, 'expanded') }; } this.row = row; this.parent = null; this.children = []; + this.statusIndex = statusIndex; + } + + get treeStatus(): TreeStatus { + return getByNestedIndex(this.row, this.statusIndex); } flatten(f: any, recursive: boolean) { - if (this.row.treeStatus === 'expanded') { + if (this.treeStatus === 'expanded') { for (let i = 0, l = this.children.length; i < l; i++) { const child = this.children[i]; f.apply(child, Array.prototype.slice.call(arguments, 2)); diff --git a/src/app/tree/client-tree.component.ts b/src/app/tree/client-tree.component.ts index ac229f307..364379f7f 100644 --- a/src/app/tree/client-tree.component.ts +++ b/src/app/tree/client-tree.component.ts @@ -25,6 +25,7 @@ import { Employee } from '../data.model'; rowHeight="auto" [treeFromRelation]="'manager'" [treeToRelation]="'name'" + [treeStatusKey]="'options.treeStatus'" [rows]="rows" (treeAction)="onTreeAction($event)" > @@ -49,7 +50,7 @@ import { Employee } from '../data.model'; styles: ['.icon {height: 10px; width: 10px; }', '.disabled {opacity: 0.5; }'] }) export class ClientTreeComponent { - rows: (Employee & { treeStatus: TreeStatus })[] = []; + rows: (Employee & { options: { treeStatus: TreeStatus } })[] = []; ColumnMode = ColumnMode; @@ -72,10 +73,13 @@ export class ClientTreeComponent { onTreeAction(event: any) { const row = event.row; - if (row.treeStatus === 'collapsed') { - row.treeStatus = 'expanded'; + if (!row.options) { + row.options = {}; + } + if (row.options.treeStatus === 'collapsed') { + row.options.treeStatus = 'expanded'; } else { - row.treeStatus = 'collapsed'; + row.options.treeStatus = 'collapsed'; } this.rows = [...this.rows]; } diff --git a/src/assets/data/company_tree.json b/src/assets/data/company_tree.json index f8ec6069e..3251777d0 100644 --- a/src/assets/data/company_tree.json +++ b/src/assets/data/company_tree.json @@ -4,58 +4,58 @@ "gender": "female", "company": "Johnson, Johnson and Partners, LLC CMP DDC", "age": 22, - "treeStatus": "collapsed" + "options": { "treeStatus": "collapsed" } }, { "name": "Claudine Neal", "gender": "female", "company": "Sealoud", "age": 55, - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } }, { "name": "Beryl Rice", "gender": "female", "company": "Velity", "age": 67, - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } }, { "name": "Wilder Gonzales", "gender": "male", "company": "Geekko", - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } }, { "name": "Georgina Schultz", "gender": "female", "company": "Suretech", - "treeStatus": "collapsed" + "options": { "treeStatus": "collapsed" } }, { "name": "Carroll Buchanan", "gender": "male", "company": "Ecosys", - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } }, { "name": "Valarie Atkinson", "gender": "female", "company": "Hopeli", - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } }, { "name": "Schroeder Mathews", "gender": "male", "company": "Polarium", "manager": "Ethel Price", - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } }, { "name": "Lynda Mendoza", "gender": "female", "company": "Dogspa", "manager": "Georgina Schultz", - "treeStatus": "disabled" + "options": { "treeStatus": "disabled" } } ]