Skip to content

Commit dac1489

Browse files
Add export button and filename options to tree table component
1 parent afb745c commit dac1489

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

projects/composition/src/app/pages/tree-table-page/tree-table-page.component.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
sortMode="multiple"
1414
[resizableColumns]="true"
1515
[columnResizeMode]="'expand'"
16+
[showExportBtn]="true"
17+
[exportFilename]="'virtual-tree-data'"
1618
toolbarTitle="Tree table with a paginator, resizable columns, multiple sorting and individual filtering">
1719
<ng-template #header>
1820
<th

projects/cps-ui-kit/src/lib/components/cps-tree-table/cps-tree-table.component.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,20 @@
117117
(clicked)="onClickActionBtn()">
118118
</cps-button>
119119
</div>
120+
<div
121+
*ngIf="showExportBtn"
122+
class="cps-treetable-tbar-export-btn ml-2"
123+
[ngClass]="{ 'btn-disabled': exportBtnDisabled }">
124+
<cps-button
125+
label="Export"
126+
[disabled]="exportBtnDisabled"
127+
color="prepared"
128+
type="solid"
129+
icon="export"
130+
[size]="toolbarSize"
131+
(clicked)="onExportData()">
132+
</cps-button>
133+
</div>
120134
<div
121135
*ngIf="showColumnsToggleBtn && columns.length > 0"
122136
class="cps-treetable-tbar-coltoggle-btn"

projects/cps-ui-kit/src/lib/components/cps-tree-table/cps-tree-table.component.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import { CpsTreeTableColumnResizableDirective } from './directives/cps-tree-tabl
5454
export function treeTableFactory(tableComponent: CpsTreeTableComponent) {
5555
return tableComponent.primengTreeTable;
5656
}
57+
export type CpsTreeTableExportFormat = 'csv' | 'xlsx' | 'json';
5758

5859
/**
5960
* CpsTreeTableSize is used to define the size of the tree table.
@@ -519,6 +520,30 @@ export class CpsTreeTableComponent
519520
*/
520521
@Input() autoColumnFilterType = true;
521522

523+
/**
524+
* Determines whether to show export button in the toolbar.
525+
* @group Props
526+
*/
527+
@Input() showExportBtn = false;
528+
529+
/**
530+
* Determines whether export button is disabled.
531+
* @group Props
532+
*/
533+
@Input() exportBtnDisabled = false;
534+
535+
/**
536+
* Filename to use when exporting data (without extension).
537+
* @group Props
538+
*/
539+
@Input() exportFilename = 'export';
540+
541+
/**
542+
* Original source data to use for export instead of processed tree table data.
543+
* @group Props
544+
*/
545+
@Input() exportOriginalData: any[] = [];
546+
522547
/**
523548
* If set to true, row data are rendered using innerHTML.
524549
* @group Props
@@ -1377,4 +1402,61 @@ export class CpsTreeTableComponent
13771402
if (selection && !Array.isArray(selection)) selection = [selection];
13781403
this.rowsSelected.emit(selection);
13791404
}
1405+
1406+
onExportData() {
1407+
if (this.exportBtnDisabled) return;
1408+
this.exportJSON();
1409+
}
1410+
1411+
exportJSON() {
1412+
try {
1413+
const exportData = this.getExportData();
1414+
const jsonString = JSON.stringify(exportData, null, 2);
1415+
const blob = new Blob([jsonString], {
1416+
type: 'application/json;charset=utf-8'
1417+
});
1418+
1419+
const downloadLink = this.document.createElement('a');
1420+
downloadLink.href = URL.createObjectURL(blob);
1421+
downloadLink.download = `${this.exportFilename}.json`;
1422+
downloadLink.click();
1423+
} catch (error) {
1424+
console.error('Error exporting JSON:', error);
1425+
}
1426+
}
1427+
1428+
getExportData(): any[] {
1429+
// If original data is provided, use it directly for export
1430+
if (this.exportOriginalData && this.exportOriginalData.length > 0) {
1431+
return this.exportOriginalData;
1432+
}
1433+
1434+
// Create a deep copy of the tree data without circular references
1435+
return this.removeCircularReferences(this.primengTreeTable?.value || []);
1436+
}
1437+
1438+
private removeCircularReferences(nodes: any[]): any[] {
1439+
return nodes.map((node) => {
1440+
const cleanNode: any = {};
1441+
1442+
// Copy all properties except 'parent' to avoid circular references
1443+
Object.keys(node).forEach((key) => {
1444+
if (key !== 'parent') {
1445+
if (
1446+
key === 'children' &&
1447+
Array.isArray(node.children) &&
1448+
node.children.length > 0
1449+
) {
1450+
// Recursively clean children
1451+
cleanNode.children = this.removeCircularReferences(node.children);
1452+
} else {
1453+
// Copy other properties as is
1454+
cleanNode[key] = node[key];
1455+
}
1456+
}
1457+
});
1458+
1459+
return cleanNode;
1460+
});
1461+
}
13801462
}

0 commit comments

Comments
 (0)