*
* ```
*
*/
@StEgeo()
@Component({
selector: 'st-table',
templateUrl: './st-table.component.html',
styleUrls: ['./st-table.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StTableComponent implements OnInit {
/** @Input {StTableHeader[]} [fields=''] List of field displayed in the header */
@Input() @StRequired() fields: StTableHeader[];
/** @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=true] 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} [selectableAll=false] Boolean to show or hide a checkbox in the header to select or
* deselect all rows
*/
@Input() selectableAll: boolean = false;
/** @Input {Order} [currentOrder=''] It specifies what is the current order applied to the table */
@Input() currentOrder: Order;
/** @Input {TemplateRef} [templateContentFilter=undefined] Reference to paint a custom template inside popover content */
@Input() templateContentFilter?: TemplateRef;
/** @Input {boolean[]} [statusFilter=''] List of status filter by column, needed with templateContentFilter */
@Input() statusFilter?: boolean[];
/** @Input {StTableIconClasses} [iconClasses=''] List of icon classes */
@Input() iconClasses?: StTableIconClasses = new StTableIconClasses();
/** @Input {boolean} [fixedHeader=false] Boolean to fix the table header */
@Input()
@HostBinding('class.st-custom-scrollbar')
@HostBinding('class.fixed-header')
get fixedHeader(): boolean {
return this._fixedHeader;
}
set fixedHeader(newValue: boolean) {
this._fixedHeader = newValue;
}
/** @Input {boolean} [stickyHoverMenu=false] Boolean to fix hover menu always visible */
@Input()
@HostBinding('class.sticky-hover-menu')
get stickyHoverMenu(): boolean {
return this._stickyHoverMenu;
}
set stickyHoverMenu(newValue: boolean) {
this._stickyHoverMenu = newValue;
}
/** @Input {string} [customClasses=] Classes for adding styles to table tag from outside. These can be: separated-rows */
@Input()
get customClasses(): string {
return this._customClasses;
}
set customClasses(newValue: string) {
this.tableClasses[this._customClasses] = undefined;
this._customClasses = newValue;
this.tableClasses[this._customClasses] = this._customClasses;
}
/** @Input {boolean} [selectedAll=false] It specifies if all rows are selected */
@Input()
get selectedAll(): boolean {
return this._selectedAll;
}
set selectedAll(newValue: boolean) {
this._selectedAll = newValue;
this._cd.markForCheck();
}
/** @Input {boolean} [hasHoverMenu=false] 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()
get hasHoverMenu(): boolean {
return this._hasHoverMenu;
}
set hasHoverMenu(newValue: boolean) {
this._hasHoverMenu = newValue;
}
/** @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 {string} [clickFilter=] Event emitted when clicking on filters icon */
@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();
public tableClasses: any = {};
public visibleFilter: number = -1;
private _fixedHeader: boolean = false;
private _stickyHoverMenu: boolean = false;
private _selectedAll: boolean;
private _hasHoverMenu: boolean = false;
private _customClasses: string;
constructor(private _cd: ChangeDetectorRef) {
}
ngOnInit(): void {
if (this.filterable && !this.statusFilter) {
this.statusFilter = new Array(this.fields.length);
this.statusFilter.fill(false);
}
}
public getHeaderItemClass(field: StTableHeader): string {
let isOrderAsc = this.isSortedByFieldAndDirection(field, ORDER_TYPE.ASC);
return isOrderAsc ? this.iconClasses.sort.asc : this.iconClasses.sort.desc;
}
public isSortable(field: StTableHeader): boolean {
return field && field.sortable !== undefined ? field.sortable : this.sortable;
}
public isSortedByField(field: StTableHeader): boolean {
return this.currentOrder && this.currentOrder.orderBy === field.id;
}
public isFilterable(field: StTableHeader): boolean {
return this.filterable && ((_get(field, 'filters.filterConfig')) ||
(this.templateContentFilter && _get(field, 'filters')) ||
_get(field, 'filters.templateRef'));
}
public onHideFilterMenu(): void {
this.visibleFilter = -1;
this._cd.markForCheck();
}
public onChangeOrder(field: StTableHeader): void {
let _currentOrder: Order;
if (field && this.isSortable(field)) {
if (this.currentOrder && this.currentOrder.orderBy === field.id) {
_currentOrder = this.changeOrderDirection();
} else {
_currentOrder = new Order(field.id, ORDER_TYPE.ASC);
}
this.changeOrder.emit(_currentOrder);
}
}
public onSelectAll(event: any): void {
this.selectAll.emit(event.checked);
}
public onSelectFilters(): void {
let selectedFilters = _cloneDeep(this.fields);
selectedFilters = selectedFilters.filter((field) => {
if (_get(field, 'filters.filterConfig')) {
field.filters.filterConfig = field.filters.filterConfig.filter((conf) => conf.selected);
if (field.filters.filterConfig.length > 0) {
return field;
}
}
});
this.selectFilters.emit(selectedFilters);
}
public onChangeFilterVisibility(event: MouseEvent, index: number, field: StTableHeader): void {
event.stopPropagation();
this.visibleFilter = this.visibleFilter === index ? undefined : index;
this.clickFilter.emit(field);
this._cd.markForCheck();
}
public getFilterIconClasses(position: number): { [key: string]: boolean } {
const classes: { [key: string]: boolean } = {};
classes['st-table__filter-arrow'] = true;
classes[this.statusFilter[position] ? this.iconClasses.filter.selected : this.iconClasses.filter.enabled] = true;
return classes;
}
private changeOrderDirection(): Order {
let newDirection = this.currentOrder.type === ORDER_TYPE.ASC ? ORDER_TYPE.DESC : ORDER_TYPE.ASC;
return new Order(this.currentOrder.orderBy, newDirection);
}
private isSortedByFieldAndDirection(field: StTableHeader, orderType: ORDER_TYPE): boolean {
return this.isSortedByField(field) && this.currentOrder.type === orderType;
}
}