/*
* © 2017 Stratio Big Data Inc., Sucursal en España.
*
* This software is licensed under the Apache License, Version 2.0.
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the terms of the License for more details.
*
* SPDX-License-Identifier: Apache-2.0.
*/
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
import { JSONSchema4 } from 'json-schema';
import { StEgeo, StRequired } from '../decorators/require-decorators';
import { Order } from '../st-table/shared/order';
import { StDynamicTableUtils } from './utils/st-dynamic-table.utils';
import { StDynamicTableClickCellEvent, StDynamicTableHeader, StDynamicTableUserInterface } from './st-dynamic-table.model';
import { StTableIconClasses } from '../st-table/st-table.interface';
/**
* @description {Component} [Dynamic Table]
*
* The table component has been designed to be able to create a table deducing its columns using a json schema
*
* * @model
*
* [StDynamicTableHeader] {./st-dynamic-table.model.ts#StDynamicTableHeader}
* [StDynamicTableUISpecification] {./st-dynamic-table.model.ts#StDynamicTableUISpecification}
* [StDynamicTableUserInterface] {./st-dynamic-table.model.ts#StDynamicTableUserInterface}
*
* @example
*
* {html}
*
* ```
*
*
*
* ```
*
*/
@StEgeo()
@Component({
selector: 'st-dynamic-table',
templateUrl: './st-dynamic-table.component.html',
styleUrls: ['./st-dynamic-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StDynamicTableComponent {
/** @Input {Object([key: string]: any)[]} [items=''] Item list displayed as table rows */
@Input() @StRequired() items: { [key: string]: any }[];
/** @Input {string} [qaTag=''] Prefix used to generate the id values for qa tests */
@Input() qaTag: string;
/** @Input {boolean} [header=true] Boolean to show or hide the header */
@Input() header: boolean = true;
/**
* @Input {boolean} [sortable=true] Boolean to make sortable the table, To enable sorting of columns use
* the new "sortable" field inside stTableHeader model
*/
@Input() sortable: boolean = true;
/**
* @Input {boolean} [filterable=false] Boolean to make filterable the table, To enable filtering of columns use
* the new "filterable" field inside stTableHeader model (necessary define filterConfig).
*/
@Input() filterable: boolean = false;
/**
* @Input {boolean} [selectable=false] Boolean to show or hide a checkboxes in the first cell of rows
*/
@Input() selectable: boolean = false;
/**
* @Input {boolean} [selectableAll=false] Boolean to show or hide a checkbox in the header to select or
* deselect all rows
*/
@Input() selectableAll: boolean = false;
/** @Input {boolean[]} [selected=''] Boolean list to indicate if a row is selected */
@Input() selected?: boolean[] = [];
/** @Input {Order} [currentOrder=''] It specifies what is the current order applied to the table */
@Input() currentOrder: Order;
/** @Input {string} [customClasses=] Classes for adding styles to table tag from outside. These can be: separated-rows */
@Input() customClasses: string;
/** @Input {boolean} [fixedHeader=false] Boolean to fix the table header */
@Input() fixedHeader: boolean = false;
/** @Input {boolean} [stickyHoverMenu=false] Boolean to fix hover menu always visible */
@Input() stickyHoverMenu: boolean = false;
/** @Input {StTableIconClasses} [iconClasses=''] List of icon classes */
@Input() iconClasses?: StTableIconClasses = new StTableIconClasses();
/** @Input {number} [activeHoverMenu=] Position of the current active hover menu */
@Input() activeHoverMenu?: number;
/** @Input {boolean} [hasHoverMenu=] It specifies if a menu has to be displayed when user puts the mouse over
* the rows. Remember to add a cell with the selector st-table-row-hover for adding content to the menu
*/
@Input() hasHoverMenu?: boolean;
/** @Input {string} [hoverButton='icon-ellipsis'] It specifies the icon class of the hover button displayed when user puts mouse over a row
*/
@Input() hoverButton: string = 'icon-ellipsis';
/** @Input {boolean} [selectedAll=] It specifies if all rows are selected */
@Input() selectedAll?: boolean;
/** @Input {string} [locale=en-US] Locale used to format dates */
@Input() locale: string = 'en-US';
/** @Input {TemplateRef} [templateContentFilter=undefined] Reference to paint a custom template inside popover content */
@Input() templateContentFilter?: TemplateRef;
/** @Output {Order} [changeOrder=''] Event emitted with the new order which has to be applied to the table rows */
@Output() changeOrder: EventEmitter = new EventEmitter();
/** @Output {boolean} [selectAll=''] Event emitted when user interacts with the checkbox to select or deselect
* all rows
*/
@Output() selectAll: EventEmitter = new EventEmitter();
/** @Output {EventEmitter} [fields=] Event emitted when header fields are being loaded */
@Output() updateFields: EventEmitter = new EventEmitter();
/** @Output {string} [clickFilter=] Event emitted when using filters custom template */
@Output() clickFilter: EventEmitter = new EventEmitter();
/** @Output {StTableHeader[]} [selectFilters=] Event emitted when user interacts with filter button without a custom template */
@Output() selectFilters: EventEmitter = new EventEmitter();
/** @Output {EventEmitter = new EventEmitter();
/** @Output {Object(checked: boolean, row: number)} [selectRow=] Event emitted when user clicks on checkbox of a row */
@Output() selectRow: EventEmitter<{ checked: boolean, row: number }> = new EventEmitter<{ checked: boolean, row: number }>();
/** @Output {StDynamicTableClickCellEvent} [clickCell=] Event emitted when user clicks on a cell */
@Output() clickCell: EventEmitter = new EventEmitter();
public fields: StDynamicTableHeader[] = [];
public statusFilter: boolean[] = [];
private _jsonSchema: JSONSchema4;
private _uiDefinitions: StDynamicTableUserInterface;
private _templateContentFilter: TemplateRef;
private _fkSeparator: string = ' - ';
private _activeFilterFields: string[] = [];
constructor(private _cd: ChangeDetectorRef) {
}
/** @Input {JSONSchema4} [jsonSchema=] Json schema to define its structure */
@Input() @StRequired()
get jsonSchema(): JSONSchema4 {
return this._jsonSchema;
}
set jsonSchema(_jsonSchema: JSONSchema4) {
this._jsonSchema = _jsonSchema;
this._manageFieldsUpdate();
}
/** @Input {StDynamicTableUserInterface} [uiDefinitions=''] UI definition for each field */
@Input()
get uiDefinitions(): StDynamicTableUserInterface {
return this._uiDefinitions;
}
set uiDefinitions(_uiDefinitions: StDynamicTableUserInterface) {
this._uiDefinitions = _uiDefinitions;
this._manageFieldsUpdate();
}
/** @Input {string[]} [activeFilterFields=] List of current filtered fields */
@Input()
get activeFilterFields(): string[] {
return this._activeFilterFields;
}
set activeFilterFields(_activeFilterFields: string[]) {
this._activeFilterFields = _activeFilterFields;
this._updateStatusFilters();
}
public onFilterClick(selectedFilter: any): void {
this.clickFilter.emit(selectedFilter);
}
public onChangeOrder(order: Order): void {
if (order) {
this.changeOrder.emit(order);
}
}
public onSelectAll(checked: boolean): void {
this.selectAll.emit(checked);
}
public onSelectedFilters(selectedFilters: StDynamicTableHeader[]): void {
this.selectFilters.emit(selectedFilters);
}
public onShowHoverMenu(row: number): void {
this.showHoverMenu.emit(row);
}
public onLeaveRow(): void {
this.showHoverMenu.emit(undefined);
}
public onClickCell(value: any, field: StDynamicTableHeader): void {
if (field.clickable) {
this.clickCell.emit({
header: field,
value: value
});
}
}
public getCellContent(item: { [key: string]: any }, field: StDynamicTableHeader): string {
if (field.fk && field.group) {
const groupLabel = field.group.split(this._fkSeparator)
.map(_groupKey => item[_groupKey])
.join(this._fkSeparator);
return groupLabel.length > this._fkSeparator.length ? groupLabel : item[field.id];
}
const uiDefinition = this.uiDefinitions && this.uiDefinitions[field.id];
if (uiDefinition && uiDefinition.dateFormat) {
return StDynamicTableUtils.formatDate( item[field.id], uiDefinition.dateFormat, this.locale);
}
return item[field.id];
}
public getCellStyles(field: StDynamicTableHeader): any {
const uiDefinition = this.uiDefinitions && this.uiDefinitions[field.id];
return uiDefinition && uiDefinition.styles;
}
public onSelectRow(checkboxEvent: { checked: boolean, value: any }, row: number): void {
this.selectRow.emit({ checked: checkboxEvent.checked, row: row });
}
private _manageFieldsUpdate(): void {
this.fields = StDynamicTableUtils.getHeaderFieldsFromJsonSchema(this._jsonSchema, this._uiDefinitions);
this.updateFields.emit(this.fields);
this._updateStatusFilters();
this._cd.markForCheck();
}
private _updateStatusFilters(): void {
this.statusFilter = [];
if (this._activeFilterFields && this._activeFilterFields.length && this.fields && this.fields.length) {
this._activeFilterFields.forEach(_fieldId => {
const position = this.fields.findIndex(_field => _field.id === _fieldId);
if (position > -1) {
this.statusFilter[position] = true;
}
});
}
}
}