9 } from '@angular/core';
11 import * as _ from 'lodash';
13 import { CellTemplate } from '../../enum/cell-template.enum';
14 import { CdTableColumn } from '../../models/cd-table-column';
15 import { CdDatePipe } from '../../pipes/cd-date.pipe';
16 import { TableComponent } from '../table/table.component';
24 * Display the given data in a 2 column data table. The left column
25 * shows the 'key' attribute, the right column the 'value' attribute.
26 * The data table has the following characteristics:
27 * - No header and footer is displayed
28 * - The relation of the width for the columns 'key' and 'value' is 1:3
29 * - The 'key' column is displayed in bold text
32 selector: 'cd-table-key-value',
33 templateUrl: './table-key-value.component.html',
34 styleUrls: ['./table-key-value.component.scss']
36 export class TableKeyValueComponent implements OnInit, OnChanges {
37 @ViewChild(TableComponent, { static: true })
38 table: TableComponent;
43 autoReload: any = 5000;
45 renderObjects = false;
46 // Only used if objects are rendered
48 appendParentKey = true;
52 // If set, the classAddingTpl is used to enable different css for different values
54 customCss?: { [css: string]: number | string | ((any) => boolean) };
56 columns: Array<CdTableColumn> = [];
60 * The function that will be called to update the input data.
63 fetchData = new EventEmitter();
65 constructor(private datePipe: CdDatePipe) {}
72 cellTransformation: CellTemplate.bold
80 this.columns[1].cellTransformation = CellTemplate.classAdding;
82 // We need to subscribe the 'fetchData' event here and not in the
83 // HTML template, otherwise the data table will display the loading
84 // indicator infinitely if data is only bound via '[data]="xyz"'.
85 // See for 'loadingIndicator' in 'TableComponent::ngOnInit()'.
86 if (this.fetchData.observers.length > 0) {
87 this.table.fetchData.subscribe(() => {
88 // Forward event triggered by the 'cd-table' data table.
89 this.fetchData.emit();
101 return; // Wait for data
103 this.tableData = this._makePairs(this.data);
106 _makePairs(data: any): Item[] {
109 return; // Wait for data
110 } else if (_.isArray(data)) {
111 temp = this._makePairsFromArray(data);
112 } else if (_.isObject(data)) {
113 temp = this._makePairsFromObject(data);
115 throw new Error('Wrong data format');
117 temp = temp.map((v) => this._convertValue(v)).filter((o) => o); // Filters out undefined
118 return _.sortBy(this.renderObjects ? this.insertFlattenObjects(temp) : temp, 'key');
121 _makePairsFromArray(data: any[]): Item[] {
123 const first = data[0];
124 if (_.isArray(first)) {
125 if (first.length === 2) {
126 temp = data.map((a) => ({
131 throw new Error('Wrong array format: [string, any][]');
133 } else if (_.isObject(first)) {
134 if (_.has(first, 'key') && _.has(first, 'value')) {
138 (previous: any[], item) => previous.concat(this._makePairsFromObject(item)),
146 _makePairsFromObject(data: object): Item[] {
147 return Object.keys(data).map((k) => ({
153 private insertFlattenObjects(temp: Item[]): any[] {
154 return _.flattenDeep(
156 const value = item.value;
157 const isObject = _.isObject(value);
158 if (!isObject || _.isEmpty(value)) {
164 return this.splitItemIntoItems(item);
170 * Split item into items will call _makePairs inside _makePairs (recursion), in oder to split
171 * the object item up into items as planned.
173 private splitItemIntoItems(v: { key: string; value: object }): Item[] {
174 return this._makePairs(v.value).map((item) => {
175 if (this.appendParentKey) {
176 item.key = v.key + ' ' + item.key;
182 _convertValue(v: Item): Item {
183 if (_.isArray(v.value)) {
184 if (_.isEmpty(v.value) && this.hideEmpty) {
187 v.value = v.value.map((item) => (_.isObject(item) ? JSON.stringify(item) : item)).join(', ');
188 } else if (_.isObject(v.value)) {
189 if ((this.hideEmpty && _.isEmpty(v.value)) || !this.renderObjects) {
192 } else if (_.isString(v.value)) {
193 if (v.value === '' && this.hideEmpty) {
196 if (this.isDate(v.value)) {
197 v.value = this.datePipe.transform(v.value) || v.value;
205 const sep = '[ -:.TZ]';
206 const n = '\\d{2}' + sep;
207 // year - m - d - h : m : s . someRest Z (if UTC)
208 return s.match(new RegExp('^\\d{4}' + sep + n + n + n + n + n + '\\d*' + 'Z?$'));