@codecabinet.online/codecabinet.online-sni-custom-grid-library
Version:
codecabinet.online created an astonishing grid library
464 lines • 333 kB
JavaScript
import { EventEmitter, Output } from '@angular/core';
import { Component, ContentChildren, ElementRef, Input, ViewChild } from '@angular/core';
import { Subject, fromEvent } from 'rxjs';
import { defaultDebounceTime, isNotEmpty } from '../../constants/constants';
import { gridSettings } from '../../constants/gridOptions';
import { CustomGridColumnComponent } from '../custom-grid-column/custom-grid-column.component';
import { columnTypes, customDetailTypes, detailsLoadMethod } from '../custom-grid-models/constants';
import { debounceTime } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "@angular/router";
import * as i2 from "../../services/notification.service";
import * as i3 from "@ngx-translate/core";
import * as i4 from "@progress/kendo-angular-dropdowns";
import * as i5 from "@progress/kendo-angular-dateinputs";
import * as i6 from "@progress/kendo-angular-inputs";
import * as i7 from "ng-apexcharts";
import * as i8 from "@angular/common";
import * as i9 from "@angular/forms";
import * as i10 from "../directives/zipcode.directive";
import * as i11 from "@ng-bootstrap/ng-bootstrap";
import * as i12 from "../directives/routeTransformerDirective.directive";
import * as i13 from "../../pipes/sanitize-html.pipe";
export class CustomGridComponent {
constructor(renderer, _router, _toastService, _translate) {
this.renderer = renderer;
this._router = _router;
this._toastService = _toastService;
this._translate = _translate;
this.rowHasDetails = false;
this.hasGridDetails = false;
this.hasFilters = false;
this.rowDetails = [];
this.disabledRows = [];
this.disabledReasons = [];
this.gridDetails = [];
this.gridDetailsOrder = [];
/*height of the table*/
this.overflowX = "";
/*overflow style - types : scroll,hidden,auto*/
this.overflowY = "";
/*if set, ignores default grid template*/
this.rowClass = [];
/*if set, ignores default grid noRecords*/
this.noRecordsInnerHTML = null;
/* Customization properties */
/*-------------------------------------------------------*/
this.popoverConfiguration = null;
this.rowCheckable = false;
this.checkedRows = [];
this.customDetails = [];
this.detailsTitle = "";
this.toggleDetailsText = null;
this.translationKey = "";
this.gridDetailsTrasnlationKey = "";
this.hasNumbering = false;
this.hasStockInputIcon = false;
this.dataLoaded = false;
this.displayedDetails = [];
this.popOverReturnOption = "id";
this.filters = [];
this.filtersChange = new Subject();
/* Output */
/*-------------------------------------------------------*/
this.triggerFilters = new EventEmitter();
this.popOver = new EventEmitter();
this.scroll = new EventEmitter();
this.detailsToggled = new EventEmitter();
this.toggleChanged = new EventEmitter();
this.imageEnlarge = new EventEmitter();
this.customDetailsAction = new EventEmitter();
this.tooltipHover = new EventEmitter();
this.modalClickHandler = new EventEmitter();
this.mapHandler = new EventEmitter();
this.checkedRowsChange = new EventEmitter();
/* Local properties */
/*-------------------------------------------------------*/
this.pageable = true;
this.hasPageSizeSelection = false;
this.pageSizes = [10, 20, 50, 100];
/* Local properties */
/*-------------------------------------------------------*/
this.dataSourceColumns = [];
this.columnsDefinition = [];
this.grid = [];
this.norecords = false;
this.columnTypes = columnTypes;
this.init = true;
this.allSelected = false;
this.hasSelected = false;
this.localCheckedRows = [];
this.customDetailTypes = customDetailTypes;
this.tooltipList = [];
this._periodRange = { start: null, end: null };
this.showDateRangePopup = false;
this.objectKeys = Object.keys;
this.filterSubscription = this.filtersChange.pipe(debounceTime(defaultDebounceTime)).subscribe(x => {
let filterEvent = { filters: this.filters, filterMethod: this.filterMethod };
this.triggerFilters.emit(filterEvent);
});
this.chartOptions = {
chart: {
height: 200,
type: "radialBar"
},
series: [67],
plotOptions: {
radialBar: {
hollow: {
margin: 15,
size: "65%",
},
dataLabels: {
value: {
offsetY: -7,
color: "#000",
fontSize: "16px",
show: true
}
},
}
},
labels: [""],
fill: {
colors: ["#5ec12d"],
}
};
}
ngOnDestroy() {
if (this.filterSubscription) {
this.filterSubscription.unsubscribe();
}
if (this.scrollWindow) {
this.scrollWindow.unsubscribe();
}
}
ngOnInit() {
let ls_page = localStorage.getItem(gridSettings.pageSize);
if (ls_page) {
this.pageSize = JSON.parse(ls_page);
}
}
ngOnChanges() {
this.norecords = this.dataSource && this.dataSource.length == 0;
if (this.dataSource && this.init) {
this.init = false;
this.dataSource.forEach(element => {
element.isExpanded = false;
// element.isSelected = false;
element.isDisabled = false;
if (this.detailsLoadMethod == detailsLoadMethod.server) {
element.isDetailLoaded = false;
}
});
}
var columnsDef = this.columns?.toArray().map(x => {
return {
field: isNotEmpty(x.filterKey) ? x.filterKey : x.field,
title: x.title,
};
});
var columnLabels = this.columns?.toArray().map(x => x.filterDataSource);
this.datasourcesDef = columnLabels ? this.renameKeys(columnLabels, this.dataSourceColumns) : null;
}
ngAfterViewInit() {
setTimeout(() => {
var columns = this.columns.toArray();
this.dataSourceColumns = columns.map(x => {
return {
field: isNotEmpty(x.filterKey) ? x.filterKey : x.field,
title: x.title,
filterKey: isNotEmpty(x.filterKey) ? x.filterKey : x.field,
highlightedAnchorKey: x.highlightedAnchorKey
};
});
let colProperties = columns.map(x => {
return {
width: x.width,
background: x.background,
redirectLink: x.redirectLink,
columnType: x.columnType,
disabled: x.disabled,
hasFilter: x.hasFilter,
stateClasses: x.stateClasses,
tooltipList: x.tooltipList,
filterKey: x.filterKey,
displayedItems: x.displayedItems,
missingText: x.missingText,
disabledTooltipList: x.disabledTooltipList,
hiddenContent: x.hiddenContent,
textAlign: x.textAlign,
props: x.props,
colTemplate: x.colTemplate,
iconHoverText: x.iconHoverText,
isRedirectActive: x.isRedirectActive,
columnClasses: x.columnClasses
};
});
this.columnsDefinition = this.renameKeys(colProperties, this.dataSourceColumns);
var columnLabels = this.columns?.toArray().map(x => x.filterDataSource);
this.datasourcesDef = columnLabels ? this.renameKeys(columnLabels, this.dataSourceColumns) : null;
// var filters = columns.map(x => this.filters[x.field]);
// this.filters = this.renameKeys(filters, this.dataSourceColumns);//not needed anymore
}, 0);
const SCROLLABLE_AREA = this.height && this.height.search("%") == -1 ? this.elementRef.nativeElement : window;
this.scrollWindow = fromEvent(SCROLLABLE_AREA, 'scroll').subscribe((event) => {
this.scrollHandler(event);
});
}
generateDynamicHtml(htmlTemplateProvided, row, stateClasses) {
// console.log("[DEBUG]: GenerateDynamicHtml" + htmlTemplateProvided);
// console.log(row);
const regex = /\{{(.*?)\}}/;
var matched = regex.exec(htmlTemplateProvided);
while (matched) {
htmlTemplateProvided = htmlTemplateProvided.replace(matched[0], row[matched[1]]);
matched = regex.exec(htmlTemplateProvided);
}
if (stateClasses?.length > 0) {
const regexClass = /\{#(.*?)\#}/;
var matchedClass = regexClass.exec(htmlTemplateProvided);
while (matchedClass) {
htmlTemplateProvided = htmlTemplateProvided.replace(matchedClass[0], this.selectClass(stateClasses, row, matchedClass[1]));
matchedClass = regexClass.exec(htmlTemplateProvided);
}
}
return htmlTemplateProvided;
}
renameKeys(obj, newKeys) {
const keyValues = Object.keys(obj).map(key => {
const newKey = newKeys[key] || key;
return { [newKey.field]: obj[key] };
});
return Object.assign({}, ...keyValues);
}
checkRedirectIsActive(isRedirectActive, row) {
return isRedirectActive != null && eval(isRedirectActive);
}
redirectRoute(route = null, id, isRedirectActive, row) {
if (isNotEmpty(route) && this.checkRedirectIsActive(isRedirectActive, row)) {
if (isNotEmpty(id)) {
this._router.navigate([route + '/' + id]);
}
else {
this._router.navigate([route]);
}
}
}
redirectUrl(link, row) {
if (this.checkDisabledRow(row)) {
return;
}
if (link.isExternal) {
window.location.href = link.url;
}
else {
this._router.navigate([link.url], { queryParams: link.queryParams });
}
}
/* Details */
toggleDetailsContainer(rowIndex, id = null) {
this.dataSource.forEach((element, index) => {
if (element.isExpanded && index != rowIndex) {
element.isExpanded = false;
}
});
var isExpanded = this.dataSource[rowIndex].isExpanded;
var isDetailLoaded = this.dataSource[rowIndex].isDetailLoaded;
this.dataSource[rowIndex].isExpanded = !isExpanded;
if (!isExpanded && this.detailsLoadMethod == detailsLoadMethod.server && !isDetailLoaded) {
this.dataSource[rowIndex].isDetailLoaded = true;
let event = { id: id, rowIndex: rowIndex };
this.detailsToggled.emit(event);
}
}
formatDate(date) {
var stringToDate = new Date(date);
var fullDate = stringToDate.toLocaleDateString(localStorage.getItem("selectedLanguage"));
return fullDate;
}
disabledSwitch(row, disabledExpression) {
return eval(disabledExpression);
}
disabledPopoverButtons(row, disabledExpression) {
return eval(disabledExpression);
}
hidePopoverButtons(row, hiddenExpression) {
return eval(hiddenExpression);
}
checkDisabledRow(row) {
if (this.disabledRows.find(y => {
return y.key != null ? row[this.dataSourcePK] == y.key : y.index == this.dataSource.indexOf(row);
}) != undefined) {
return true;
}
return false;
}
checkDisabledCheckboxRow(row) {
if (row.isDisabled) {
return true;
}
return this.checkDisabledRow(row);
}
selectClass(event, row, classTarget = null) {
return this.selectClassTemplate(event, row, classTarget);
}
selectRowClass(row) {
if (this.rowClass) {
return this.selectClassTemplate(this.rowClass, row);
}
}
selectClassTemplate(classArray, row, classTarget = null) {
var returnedClass = "default-class";
if (classArray) {
classArray.forEach(element => {
if (eval(element.expression) && (element.classTarget == classTarget || !classTarget || !element.classTarget)) {
returnedClass = element.className;
return;
}
});
}
return returnedClass;
}
disable(exp, row) {
return eval(exp);
}
hideCustomDetail(exp, row) {
return eval(exp);
}
evaluateExpression(exp, row) {
return eval(exp);
}
isNotEmpty(element) {
return isNotEmpty(element);
}
checkHiddenCell(row, expression) {
return !eval(expression);
}
/* Emitters */
/*-------------------------------------------------------*/
toggleValueChange(id) {
this.toggleChanged.emit(id);
}
popoverAction(action, rowData) {
let event = { action: action, id: undefined, rowData: undefined };
if (this.popOverReturnOption === "id") {
event.id = rowData[this.dataSourcePK];
}
if (this.popOverReturnOption === "rowData") {
event.rowData = rowData;
}
if (action != null) {
this.popOver.emit(event);
}
return;
}
scrollHandler(event) {
if (this.pageable) {
this.scroll.emit(event);
}
}
imageClickHandler(photo) {
this.imageEnlarge.emit(photo);
}
tooltipHoverHandler(event, rowIndex) {
let objEvent = { success: event, rowIndex: rowIndex, data: this.dataSource[rowIndex] };
this.tooltipHover.emit(objEvent);
}
modalHandler(row, colField) {
if (this.columnsDefinition[colField].disabled) {
return;
}
this.modalClickHandler.emit(row);
}
iconClickedHandler(row, colField) {
if (this.evaluateExpression(this.columnsDefinition[colField].disabled, row) || this.checkDisabledRow(row)) {
return;
}
let iconColumn = this.columns.toArray().find(x => x.field == colField);
if (iconColumn) {
iconColumn.iconClickHandler.emit(row);
}
}
cellActionHandler(row, colField) {
if (eval(this.columnsDefinition[colField].disabled) || this.checkDisabledRow(row)) {
return;
}
let column = this.columns.toArray().find(x => x.field == colField);
if (column && column.action /*.observers && column.action.observers.length > 0*/) {
column.action.emit(row);
}
}
redirectMap(event, row) {
if (this.checkDisabledRow(row)) {
return;
}
let eventObject = {
event: event,
row: row
};
this.mapHandler.emit(eventObject);
}
/* Handlers */
/*-------------------------------------------------------*/
changePageSize(event) {
localStorage.setItem(gridSettings.pageSize, JSON.stringify(event));
window.location.reload();
return;
}
selectHandler(event, rowIndex) {
setTimeout(() => {
this.dataSource[rowIndex].isSelected = event;
this.allSelected = this.dataSource.every(x => x.isSelected);
this.checkedRows = this.dataSource.filter(x => x.isSelected);
this.checkedRowsChange.emit(this.checkedRows);
});
}
selectAllHandler() {
setTimeout(() => {
this.dataSource.filter(x => (x.isSelected != this.allSelected &&
!this.checkDisabledRow(x) && !x.isDisabled)).forEach(x => { x.isSelected = this.allSelected; });
this.checkedRows = this.dataSource.filter(x => x.isSelected);
this.checkedRowsChange.emit(this.checkedRows);
});
}
customTemplateActionHandler(action, id) {
let event = { action: action, id: id };
if (action) {
this.customDetailsAction.emit(event);
}
}
isDecimal(value) {
return !isNaN(value);
}
valueChanged(event, popup) {
this.showDateRangePopup = false;
popup.show = false;
this.filtersChange.next(event);
}
clearDate(event, popup) {
this.showDateRangePopup = false;
popup.show = false;
if (this.filters["startDate"] || this.filters["endDate"]) {
this.filters["startDate"] = null;
this.filters["endDate"] = null;
}
this.filtersChange.next(event);
}
activateCalendar(popup) {
this.showDateRangePopup = true;
popup.show = true;
}
openPopup(event) {
if (!this.showDateRangePopup) {
event.preventDefault();
}
}
closePopup(event) {
if (this.showDateRangePopup) {
event.preventDefault();
}
}
}
CustomGridComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.11", ngImport: i0, type: CustomGridComponent, deps: [{ token: i0.Renderer2 }, { token: i1.Router }, { token: i2.NotificationService }, { token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
CustomGridComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.11", type: CustomGridComponent, selector: "custom-grid", inputs: { dataSource: "dataSource", dataSourcePK: "dataSourcePK", filtersDataType: "filtersDataType", rowHasDetails: "rowHasDetails", hasGridDetails: "hasGridDetails", hasFilters: "hasFilters", rowDetails: "rowDetails", disabledRows: "disabledRows", disabledReasons: "disabledReasons", gridDetails: "gridDetails", gridDetailsOrder: "gridDetailsOrder", width: "width", height: "height", overflowX: "overflowX", overflowY: "overflowY", rowTemplate: "rowTemplate", rowClass: "rowClass", noRecordsInnerHTML: "noRecordsInnerHTML", popoverConfiguration: "popoverConfiguration", noDataImg: "noDataImg", detailsLoadMethod: "detailsLoadMethod", rowCheckable: "rowCheckable", checkedRows: "checkedRows", customDetails: "customDetails", detailsTitle: "detailsTitle", toggleDetailsText: "toggleDetailsText", translationKey: "translationKey", gridDetailsTrasnlationKey: "gridDetailsTrasnlationKey", hasNumbering: "hasNumbering", hasStockInputIcon: "hasStockInputIcon", dataLoaded: "dataLoaded", displayedDetails: "displayedDetails", popOverReturnOption: "popOverReturnOption", filterable: "filterable", filters: "filters", filterMethod: "filterMethod", pageable: "pageable", hasPageSizeSelection: "hasPageSizeSelection" }, outputs: { triggerFilters: "triggerFilters", popOver: "popOver", scroll: "scroll", detailsToggled: "detailsToggled", toggleChanged: "toggleChanged", imageEnlarge: "imageEnlarge", customDetailsAction: "customDetailsAction", tooltipHover: "tooltipHover", modalClickHandler: "modalClickHandler", mapHandler: "mapHandler", checkedRowsChange: "checkedRowsChange" }, queries: [{ propertyName: "columns", predicate: CustomGridColumnComponent }], viewQueries: [{ propertyName: "elementRef", first: true, predicate: ["customgrid"], descendants: true, read: ElementRef }, { propertyName: "chart", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"custom-grid-wrap\" [ngStyle]=\"{'width':width,'height':height,'overflow-x': overflowX, 'overflow-y': overflowY}\" #customgrid>\n <ng-container *ngIf=\"(hasFilters || !norecords)\">\n <div class=\"custom-grid-table\" [ngStyle]=\"{'width':width}\">\n <div class=\"custom-grid-thead\">\n <div class=\"custom-grid-thead-tr header-border-custom-grid\">\n <div class=\"custom-grid-thead-cell cell-disabled\"></div> <!-- disabled row cell -->\n <div *ngIf=\"rowCheckable\" class=\"custom-grid-thead-cell cell-checkbox cell-fixed\"> <!-- row cell checkbox-->\n <input type=\"checkbox\"\n class=\"k-checkbox custom-grid-checkbox\" \n [(ngModel)]=\"allSelected\" \n (ngModelChange)=\"selectAllHandler()\"\n [disabled]=\"dataSourceColumns != null && dataSourceColumns.length == 0\">\n </div>\n <div *ngIf=\"hasNumbering\" class=\"custom-grid-thead-cell cell-numbering cell-fixed\"> <!-- row cell numbering-->\n {{'customGrid.numbering' | translate}}\n </div>\n <!-- row cells data-->\n <div *ngFor=\"let col of dataSourceColumns; let colIndex = index\"\n class=\"custom-grid-thead-cell cell-thead-filter {{columnsDefinition[col.field].columnClasses}}\"\n [hidden]=\"!columnsDefinition[col.field].props.rendered\"\n [ngClass]=\"{\n 'cell-empty': !col.title, 'cell-data': col.title,\n 'cell-date': !datasourcesDef[col.field] && columnsDefinition[col.field].columnType == columnTypes.date || columnsDefinition[col.field].columnType == columnTypes.daterange\n }\"\n >\n <a class=\"table-header-title-custom-grid a-header-custom-grid\" *ngIf=\"col.title\">\n {{ col.title | translate }}\n </a>\n </div>\n <div *ngIf=\"popoverConfiguration != null\" class=\"custom-grid-thead-cell cell-popover cell-fixed\"></div> <!-- disabled row cell popover -->\n </div> <!-- END custom-grid-thead-tr -->\n <div class=\"custom-grid-thead-tr custom-grid-thead-filters\">\n <div class=\"custom-grid-thead-cell cell-disabled\"></div> <!-- disabled row cell -->\n <div *ngIf=\"rowCheckable\" class=\"custom-grid-thead-cell cell-checkbox cell-fixed\"></div> <!-- disabled row cell checkbox -->\n <div *ngIf=\"hasNumbering\" class=\"custom-grid-thead-cell cell-numbering cell-fixed\"></div> <!-- disabled row cell numbering -->\n <!-- row cells data-->\n <div class=\"custom-grid-thead-cell cell-thead-filter {{columnsDefinition[col.field].columnClasses}}\" \n *ngFor=\"let col of dataSourceColumns ; let colIndex = index\"\n [ngClass]=\"{\n 'cell-date': !datasourcesDef[col.field] && columnsDefinition[col.field].columnType == columnTypes.date || columnsDefinition[col.field].columnType == columnTypes.daterange,\n 'cell-empty': !columnsDefinition[col.field].hasFilter,\n 'cell-data': datasourcesDef[col.field] || (!datasourcesDef[col.field] && columnsDefinition[col.field].hasFilter),\n 'cell-dropdown': datasourcesDef[col.field]\n }\"\n >\n \n <ng-container *ngIf=\"datasourcesDef[col.field]; else notDropdown\">\n <div class=\"custom-grid-filter-container custom-grid-combobox\" *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <kendo-combobox placeholder=\"{{'common.actions.filter' | translate}}\"\n [data]=\"datasourcesDef[col.field]\"\n [(ngModel)]=\"filters[col.filterKey]\" \n (ngModelChange)=\"filtersChange.next($event)\"\n valueField=\"id\"\n textField=\"name\"\n [valuePrimitive]=\"true\">\n </kendo-combobox>\n </div>\n </ng-container>\n <ng-template #notDropdown>\n <ng-container [ngSwitch]=\"columnsDefinition[col.field].columnType\">\n <ng-container *ngIf=\"columnsDefinition[col.field].hasFilter\">\n <ng-container *ngSwitchDefault>\n <div class=\"custom-grid-filter-container\" *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <i class=\"icon icon-search wa-icon wa-icon-search\"></i>\n <input type=\"text\" placeholder=\"{{'common.actions.filter' | translate}}\"\n class=\"filter-header-box-custom-grid\" [(ngModel)]=\"filters[col.filterKey]\" (ngModelChange)=\"filtersChange.next($event)\">\n </div>\n </ng-container>\n \n <ng-container *ngSwitchCase=\"columnTypes.text\">\n <div class=\"custom-grid-filter-container\" *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <i class=\"icon icon-search wa-icon wa-icon-search\"></i>\n <input type=\"text\" placeholder=\"{{'common.actions.filter' | translate}}\"\n class=\"filter-header-box-custom-grid\" [(ngModel)]=\"filters[col.filterKey]\" (ngModelChange)=\"filtersChange.next($event)\">\n </div>\n </ng-container>\n \n <ng-container *ngSwitchCase=\"columnTypes.date\">\n <kendo-datepicker class=\"custom-grid-filter-container kendo-datepicker-placeholder\" [format]=\"'d'\" [(ngModel)]=\"filters[col.filterKey]\"\n (ngModelChange)=\"filtersChange.next($event)\" *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <kendo-datepicker-messages today=\"{{ 'calendar.today' | translate }}\"\n toggle=\"{{ 'calendar.toggle' | translate }}\"></kendo-datepicker-messages>\n </kendo-datepicker>\n </ng-container>\n \n <ng-container *ngSwitchCase=\"columnTypes.daterange\">\n <kendo-daterange class=\"custom-grid-filter-container custom-grid-date-range\" *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <div class=\"custom-grid-date-range-anchor d-flex align-items-center\" #anchor (click)=\"activateCalendar(customGridDateRangePopup)\">\n <label class=\"custom-grid-date-range-label d-flex align-items-center\">\n <kendo-dateinput kendoDateRangeStartInput\n [(value)]=\"filters['startDate']\" \n placeholder=\"{{ 'customGrid.startDate' | translate }}\"\n (valueChange)=\"filters['endDate'] = null\"\n class=\"daterange-dateinput\">\n </kendo-dateinput>\n </label>\n <label class=\"custom-grid-date-range-label d-flex align-items-center\">\n <kendo-dateinput kendoDateRangeEndInput\n [(value)]=\"filters['endDate']\" \n placeholder=\"{{ 'customGrid.endDate' | translate }}\"\n class=\"daterange-dateinput\">\n </kendo-dateinput>\n <span class=\"k-icon k-i-calendar\"></span>\n </label>\n </div>\n <kendo-daterange-popup #customGridDateRangePopup (open)=\"openPopup($event)\" (close)=\"closePopup($event)\"\n [anchor]=\"anchor\" \n [anchorAlign]=\"{ horizontal: 'center', vertical: 'bottom'}\"\n [popupAlign]=\"{ horizontal: 'center', vertical: 'top' }\"\n >\n <ng-template kendoDateRangePopupTemplate [ngIf]=\"true\">\n <kendo-multiviewcalendar kendoDateRangeSelection>\n </kendo-multiviewcalendar>\n <div class=\"custom-grid-filter-btn-section\">\n <button class=\"custom-grid-clear-daterange\" \n (click)=\"clearDate($event, customGridDateRangePopup)\">\n {{'common.actions.clear' | translate}}\n </button>\n <button class=\"custom-grid-filter-daterange\" \n (click)=\"valueChanged($event, customGridDateRangePopup)\">\n {{'common.actions.filter' | translate}}\n </button>\n </div> \n </ng-template>\n </kendo-daterange-popup>\n </kendo-daterange>\n </ng-container>\n \n <ng-container *ngSwitchCase=\"columnTypes.textnumber\">\n <div class=\"custom-grid-filter-container\" *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <i class=\"icon icon-search wa-icon wa-icon-search\"></i>\n <input type=\"number\" min=\"0\" zipcodedirective placeholder=\"{{'common.actions.filter' | translate}}\"\n class=\"filter-header-box-custom-grid\" [(ngModel)]=\"filters[col.filterKey]\" (ngModelChange)=\"filtersChange.next($event)\">\n </div>\n </ng-container>\n \n </ng-container>\n </ng-container>\n </ng-template>\n </div>\n <div *ngIf=\"popoverConfiguration != null\" class=\"custom-grid-thead-cell cell-popover cell-fixed\"></div> <!-- disabled row cell popover -->\n </div> <!-- END custom-grid-thead-tr -->\n </div> <!-- END custom-grid-thead -->\n <div class=\"custom-grid-tbody\" *ngIf=\"!norecords\">\n <ng-container *ngFor=\"let row of dataSource; let rowIndex = index\">\n <ng-container *ngIf=\"row\">\n <ng-container *ngIf=\"rowTemplate; else defaultRowTemplate\">\n <ng-container *ngFor=\"let col of dataSourceColumns; let colIndex = index\">\n <div [innerHtml]=\"rowTemplate | sanitizeHtml\"></div>\n </ng-container>\n </ng-container>\n\n <!-- custom-grid-tbody-tr row data-->\n <ng-template #defaultRowTemplate>\n <div class=\"custom-grid-tbody-tr row-box-custom-grid {{selectRowClass(row)}}\"\n [ngClass]=\"{'custom-grid-disabled-row': checkDisabledRow(row), 'row-has-details': rowHasDetails}\">\n <div *ngIf=\"rowCheckable\" class=\"custom-grid-tbody-cell cell-checkbox cell-fixed\"> <!-- row cell checkbox-->\n <input type=\"checkbox\" \n class=\"k-checkbox custom-grid-checkbox\" \n [(ngModel)]=\"row.isSelected\" \n (ngModelChange)=\"selectHandler($event, rowIndex)\" \n [disabled]=\"checkDisabledCheckboxRow(row)\"\n >\n </div>\n <div class=\"custom-grid-tbody-cell cell-disabled\"> <!-- row cell disabled -->\n <ng-container *ngIf=\"checkDisabledRow(row)\">\n <i class=\"icon icon-warning-circle wa-icon wa-icon-warning-circle tooltip-trigger\"\n [ngbTooltip]=\"reasonDisabled\" placement=\"right\"></i>\n <ng-template #reasonDisabled>\n <div class=\"tooltip-container\">\n <ng-container *ngFor=\"let reason of disabledReasons; let reasonIndex = index\">\n <div class=\"tooltip-title\">\n {{reason.title | translate}}\n </div>\n <div class=\"tooltip-content\">\n {{reason.description | translate}}\n </div>\n </ng-container>\n </div>\n </ng-template>\n </ng-container>\n </div>\n <div *ngIf=\"hasNumbering\" class=\"custom-grid-tbody-cell cell-numbering cell-fixed\"> <!-- row cell numbering-->\n {{rowIndex + 1}}.\n </div>\n <!-- row cells data-->\n <ng-container *ngFor=\"let col of dataSourceColumns; let colIndex = index\">\n <ng-container *ngIf=\"!columnsDefinition[col.field].redirectLink; else linkColumn\">\n <ng-container *ngIf=\"columnsDefinition[col.field].colTemplate; else withoutTemplate\">\n <div class=\"custom-grid-tbody-cell cell-data {{columnsDefinition[col.field].columnClasses}}\">\n <div [innerHtml]=\"generateDynamicHtml(columnsDefinition[col.field].colTemplate, row, columnsDefinition[col.field].stateClasses)\"\n class=\"grid-colTemplate-container\">\n </div>\n </div>\n </ng-container>\n\n <ng-template #withoutTemplate>\n <ng-container [ngSwitch]=\"columnsDefinition[col.field].columnType\">\n <ng-container *ngSwitchDefault>\n <div class=\"custom-grid-tbody-cell cell-data {{columnsDefinition[col.field].columnClasses}}\"\n [ngClass]=\"{\n 'custom-grid-disabled-col': evaluateExpression(columnsDefinition[col.field].disabled, row)\n }\"\n (click)=\"cellActionHandler(row, col.field)\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <span [ngClass]=\"selectClass(columnsDefinition[col.field].stateClasses,row)\"\n *ngIf=\"checkHiddenCell(row, columnsDefinition[col.field].hiddenContent)\">\n {{isNotEmpty(row[col.field]) ? row[col.field] : (columnsDefinition[col.field].missingText | translate)}}\n </span>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"columnTypes.text || columnTypes.textnumber\">\n <div class=\"custom-grid-tbody-cell cell-data cell-text {{columnsDefinition[col.field].columnClasses}}\"\n [ngClass]=\"{\n 'custom-grid-disabled-col': evaluateExpression(columnsDefinition[col.field].disabled, row),\n 'position-relative': row[col.highlightedAnchorKey]\n }\"\n (click)=\"cellActionHandler(row, col.field)\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <div [class.div-container-highlight]=\"row[col.highlightedAnchorKey]\">\n <div [ngClass]=\"selectClass(columnsDefinition[col.field].stateClasses,row)\"\n [ngStyle]=\"{'text-align': columnsDefinition[col.field].textAlign}\"\n *ngIf=\"checkHiddenCell(row, columnsDefinition[col.field].hiddenContent)\">\n {{isNotEmpty(row[col.field]) ? row[col.field] : (columnsDefinition[col.field].missingText | translate)}}\n </div>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"columnTypes.number\">\n <div class=\"custom-grid-tbody-cell cell-data cell-number {{columnsDefinition[col.field].columnClasses}}\"\n [ngClass]=\"{\n 'custom-grid-disabled-col': evaluateExpression(columnsDefinition[col.field].disabled, row)\n }\"\n (click)=\"cellActionHandler(row, col.field)\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <span [ngClass]=\"selectClass(columnsDefinition[col.field].stateClasses,row)\"\n [ngStyle]=\"{'text-align': columnsDefinition[col.field].textAlign}\"\n *ngIf=\"checkHiddenCell(row, columnsDefinition[col.field].hiddenContent)\">\n {{isNotEmpty(row[col.field]) ? (row[col.field] | number : '1.2-2') : (columnsDefinition[col.field].missingText | translate)}}\n </span>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"columnTypes.date\">\n <div class=\"custom-grid-tbody-cell cell-data cell-date {{columnsDefinition[col.field].columnClasses}}\"\n [ngClass]=\"{\n 'custom-grid-disabled-col': evaluateExpression(columnsDefinition[col.field].disabled, row)\n }\"\n (click)=\"cellActionHandler(row, col.field)\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <span [ngClass]=\"selectClass(columnsDefinition[col.field].stateClasses,row)\"\n [ngStyle]=\"{'text-align': columnsDefinition[col.field].textAlign}\"\n *ngIf=\"checkHiddenCell(row, columnsDefinition[col.field].hiddenContent)\">\n {{isNotEmpty(row[col.field]) ? formatDate(row[col.field]) : (columnsDefinition[col.field].missingText | translate)}}\n </span>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"columnTypes.daterange\">\n <div class=\"custom-grid-tbody-cell cell-data cell-daterange {{columnsDefinition[col.field].columnClasses}}\"\n [ngClass]=\"{\n 'custom-grid-disabled-col': evaluateExpression(columnsDefinition[col.field].disabled, row)\n }\"\n (click)=\"cellActionHandler(row, col.field)\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\">\n <span [ngClass]=\"selectClass(columnsDefinition[col.field].stateClasses,row)\"\n [ngStyle]=\"{'text-align': columnsDefinition[col.field].textAlign}\"\n *ngIf=\"checkHiddenCell(row, columnsDefinition[col.field].hiddenContent)\">\n {{isNotEmpty(row[\"startDate\"]) && isNotEmpty(row[\"endDate\"]) ? \n formatDate(row[\"startDate\"]) + ' - ' + formatDate(row[\"endDate\"]) :\n (columnsDefinition[col.field].missingText | translate)}}\n </span>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"columnTypes.switch\">\n <div class=\"custom-grid-tbody-cell cell-data cell-switch {{columnsDefinition[col.field].columnClasses}}\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\"\n >\n <ng-container *ngIf=\"checkHiddenCell(row, columnsDefinition[col.field].hiddenContent)\">\n <kendo-switch [(ngModel)]=\"row.supplierConfirmed\"\n name=\"isActive_{{rowIndex}}_{{colIndex}}\"\n (valueChange)=\"toggleValueChange(row[dataSourcePK])\"\n id=\"isActive_{{rowIndex}}_{{colIndex}}\" class=\"toggle\" \n [onLabel]=\"' '\" [offLabel]=\"' '\" [disabled]=\"disabledSwitch(row,columnsDefinition[col.field].disabled)\">\n </kendo-switch>\n </ng-container>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"columnTypes.list\">\n <div class=\"custom-grid-tbody-cell cell-data cell-list {{columnsDefinition[col.field].columnClasses}}\"\n [ngClass]=\"{\n 'custom-grid-disabled-col': evaluateExpression(columnsDefinition[col.field].disabled, row)\n }\"\n *ngIf=\"columnsDefinition[col.field].props.rendered\"\n >\n <div class=\"row\">\n <div [ngClass]=\"columnsDefinition[col.field].tooltipList ? 'col-md-9' : 'col-md-12'\">\n <p *ngFor=\"let listItem of row[col.field]; let indexListItem = index\"\n class=\"mb-0\"\n [ngStyle]=\"{'text-align': columnsDefinition[col.field].textAlign}\">\n <ng-container *ngFor=\"let objProperty of columnsDefinition[col.field].displayedItems; let indexObjProp = index\">\n {{ objProperty.type == \"number\" ? (listItem[objProperty.item] | number : '1.2-2') : listItem[objProperty.item] }}\n </ng-container>\n </p>\n </div>\n\n <div *ngIf=\"row[col.field].length > 0 && columnsDefinition[col.field].tooltipList\" class=\"col-md-3\">\n <div (mouseenter)=\"tooltipHoverHandler($event, rowIndex)\">\n <i class=\"icon icon-info-circle wa-icon wa-icon-info-circle\"\n [ngbTooltip]=\"stocks\" placement=\"top\"></i>\n </div>\n </div>\n </div>\n <!-- refactor list dinamic -->\n </div>\n\n <ng-template #stocks>\n <div class=\"d-flex\">\n <div class=\"tooltip-container\">\n <span class=\"tooltipItem-title\">{{'customGrid.tooltipTitle' | translate}}</span><br>\n <ng-container *ngFor=\"let ttItem of row.farmStock; let tooltipItem = index\">\n <div class=\"\">\n