Skip to content

Commit edfd0b2

Browse files
Add export button and filename options to tree table component (#428)
* Add export button and filename options to tree table component * Removed CpsTreeTAbleExportFormat. Regenerate docs
1 parent afb745c commit edfd0b2

File tree

6 files changed

+142
-13
lines changed

6 files changed

+142
-13
lines changed

projects/composition/src/app/api-data/cps-notification.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
"optional": true,
128128
"readonly": false,
129129
"type": "number",
130-
"description": "The duration (in milliseconds) that the notification will be displayed before automatically closing.\nValue 0 means that the notification is persistent and will not be automatically closed."
130+
"description": "The duration (in milliseconds) that the notification will be displayed before automatically closing.\r\nValue 0 means that the notification is persistent and will not be automatically closed."
131131
},
132132
{
133133
"name": "allowDuplicates",

projects/composition/src/app/api-data/cps-table.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,22 @@
107107
"readonly": false,
108108
"type": "boolean",
109109
"default": "true",
110-
"description": "Determines whether the 'Remove' button should be displayed in the row menu.\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
110+
"description": "Determines whether the 'Remove' button should be displayed in the row menu.\r\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
111111
},
112112
{
113113
"name": "showRowEditButton",
114114
"optional": false,
115115
"readonly": false,
116116
"type": "boolean",
117117
"default": "true",
118-
"description": "Determines whether the 'Edit' button should be displayed in the row menu.\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
118+
"description": "Determines whether the 'Edit' button should be displayed in the row menu.\r\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
119119
},
120120
{
121121
"name": "rowMenuItems",
122122
"optional": true,
123123
"readonly": false,
124124
"type": "CpsMenuItem[]",
125-
"description": "Custom items to be displayed in the row menu.\nNote: This setting only takes effect if 'showRowMenu' is true."
125+
"description": "Custom items to be displayed in the row menu.\r\nNote: This setting only takes effect if 'showRowMenu' is true."
126126
},
127127
{
128128
"name": "reorderableRows",
@@ -178,7 +178,7 @@
178178
"readonly": false,
179179
"type": "boolean",
180180
"default": "true",
181-
"description": "If true, automatically detects filter type based on values, otherwise sets 'text' filter type for all columns.\nNote: This setting only takes effect if 'filterableByColumns' is true."
181+
"description": "If true, automatically detects filter type based on values, otherwise sets 'text' filter type for all columns.\r\nNote: This setting only takes effect if 'filterableByColumns' is true."
182182
},
183183
{
184184
"name": "sortMode",
@@ -570,15 +570,15 @@
570570
"readonly": false,
571571
"type": "boolean",
572572
"default": "false",
573-
"description": "Determines whether columns are resizable.\nIn case of using a custom template for columns, it is also needed to add cpsTColResizable directive to th elements."
573+
"description": "Determines whether columns are resizable.\r\nIn case of using a custom template for columns, it is also needed to add cpsTColResizable directive to th elements."
574574
},
575575
{
576576
"name": "columnResizeMode",
577577
"optional": false,
578578
"readonly": false,
579579
"type": "\"expand\" | \"fit\"",
580580
"default": "fit",
581-
"description": "Determines how the columns are resized. It can be 'fit' (total width of the table stays the same) or 'expand' (total width of the table changes when resizing columns).\nNote: This setting only takes effect if 'resizableColumns' is true."
581+
"description": "Determines how the columns are resized. It can be 'fit' (total width of the table stays the same) or 'expand' (total width of the table changes when resizing columns).\r\nNote: This setting only takes effect if 'resizableColumns' is true."
582582
}
583583
]
584584
},

projects/composition/src/app/api-data/cps-tree-table.json

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,22 @@
123123
"readonly": false,
124124
"type": "boolean",
125125
"default": "true",
126-
"description": "Determines whether the 'Remove' button should be displayed in the row menu.\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
126+
"description": "Determines whether the 'Remove' button should be displayed in the row menu.\r\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
127127
},
128128
{
129129
"name": "showRowEditButton",
130130
"optional": false,
131131
"readonly": false,
132132
"type": "boolean",
133133
"default": "true",
134-
"description": "Determines whether the 'Edit' button should be displayed in the row menu.\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
134+
"description": "Determines whether the 'Edit' button should be displayed in the row menu.\r\nNote: This setting only takes effect if 'showRowMenu' is true and 'rowMenuItems' is not set."
135135
},
136136
{
137137
"name": "rowMenuItems",
138138
"optional": true,
139139
"readonly": false,
140140
"type": "CpsMenuItem[]",
141-
"description": "Custom items to be displayed in the row menu.\nNote: This setting only takes effect if 'showRowMenu' is true."
141+
"description": "Custom items to be displayed in the row menu.\r\nNote: This setting only takes effect if 'showRowMenu' is true."
142142
},
143143
{
144144
"name": "loading",
@@ -530,7 +530,39 @@
530530
"readonly": false,
531531
"type": "boolean",
532532
"default": "true",
533-
"description": "If true, automatically detects filter type based on values, otherwise sets 'text' filter type for all columns.\nNote: This setting only takes effect if 'filterableByColumns' is true."
533+
"description": "If true, automatically detects filter type based on values, otherwise sets 'text' filter type for all columns.\r\nNote: This setting only takes effect if 'filterableByColumns' is true."
534+
},
535+
{
536+
"name": "showExportBtn",
537+
"optional": false,
538+
"readonly": false,
539+
"type": "boolean",
540+
"default": "false",
541+
"description": "Determines whether to show export button in the toolbar."
542+
},
543+
{
544+
"name": "exportBtnDisabled",
545+
"optional": false,
546+
"readonly": false,
547+
"type": "boolean",
548+
"default": "false",
549+
"description": "Determines whether export button is disabled."
550+
},
551+
{
552+
"name": "exportFilename",
553+
"optional": false,
554+
"readonly": false,
555+
"type": "string",
556+
"default": "export",
557+
"description": "Filename to use when exporting data (without extension)."
558+
},
559+
{
560+
"name": "exportOriginalData",
561+
"optional": false,
562+
"readonly": false,
563+
"type": "any[]",
564+
"default": "[]",
565+
"description": "Original source data to use for export instead of processed tree table data."
534566
},
535567
{
536568
"name": "renderDataAsHTML",
@@ -554,15 +586,15 @@
554586
"readonly": false,
555587
"type": "boolean",
556588
"default": "false",
557-
"description": "Determines whether columns are resizable.\nIn case of using a custom template for columns, it is also needed to add cpsTTColResizable directive to th elements."
589+
"description": "Determines whether columns are resizable.\r\nIn case of using a custom template for columns, it is also needed to add cpsTTColResizable directive to th elements."
558590
},
559591
{
560592
"name": "columnResizeMode",
561593
"optional": false,
562594
"readonly": false,
563595
"type": "\"expand\" | \"fit\"",
564596
"default": "fit",
565-
"description": "Determines how the columns are resized. It can be 'fit' (total width of the table stays the same) or 'expand' (total width of the table changes when resizing columns).\nNote: This setting only takes effect if 'resizableColumns' is true."
597+
"description": "Determines how the columns are resized. It can be 'fit' (total width of the table stays the same) or 'expand' (total width of the table changes when resizing columns).\r\nNote: This setting only takes effect if 'resizableColumns' is true."
566598
}
567599
]
568600
},

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: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,30 @@ export class CpsTreeTableComponent
519519
*/
520520
@Input() autoColumnFilterType = true;
521521

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

0 commit comments

Comments
 (0)