sdk-datagrid
Version:
Customizable (Angular) datagrid with data options for manipulation, and charts for visualization.
1,152 lines • 291 kB
JavaScript
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { Sorts } from './enums/sorts';
import { Clone } from './utils/clone';
import { SDKDataGridColumn } from './models/datagrid-column';
import { SDKDataGridOptions, StorageType } from './models/datagrid-options';
import { SDKDataGridCustomFilter } from './models/datagrid-custom-filter';
import { SDKDataGridSettings } from './models/datagrid-settings';
import { SDKDataGridMessage } from './models/datagrid-message';
import * as i0 from "@angular/core";
import * as i1 from "@angular/router";
import * as i2 from "@angular/common";
import * as i3 from "ng-dynamic-component";
import * as i4 from "sdk-select";
import * as i5 from "sdk-tabs";
import * as i6 from "sdk-textbox";
import * as i7 from "./options/settings/settings-option.component";
import * as i8 from "./options/columns/columns-option.component";
import * as i9 from "./options/sort/sort-option.component";
import * as i10 from "./options/filter/filter-option.component";
import * as i11 from "./options/formula/formula-option.component";
import * as i12 from "./options/export/export-option.component";
import * as i13 from "./options/chart/chart-option.component";
export class SDKDatagridComponent {
/**************************************************************************
* Private Variables
**************************************************************************/
/**************************************************************************
* Component Lifecycle Methods
**************************************************************************/
constructor(route) {
this.route = route;
/**************************************************************************
* Input/Output Parameters for updating the Grid
**************************************************************************/
this.updateGrid = false; // Applies changes/data to the grid.
this.updateGridChange = new EventEmitter(); // Callback to set updateGrid variable.
this.editRecordIndexChange = new EventEmitter(); // Callback to set editRecordIndex variable.
/**************************************************************************
* Input/Output Parameters for dataset change
**************************************************************************/
this.datasets = []; // List of datasets.
this.activeDataset = ""; // The current selected dataset.
this.activeDatasetChange = new EventEmitter(); // Callback to set activeDataset variable.
/**************************************************************************
* Input/Output Parameters for updating columns
**************************************************************************/
this.columns = []; // The columns to be used for the grid.
this.columnHeaderStyle = ""; // Style used for column headers.
this.columnsChange = new EventEmitter(); // Callback to set columns variable.
/**************************************************************************
* Input/Output Parameters for updating custom filters
**************************************************************************/
this.customFilters = []; // Custom filters added to standard filter provided in loaddata callback (filters).
this.customFiltersChange = new EventEmitter(); // Callback to set custom filters variable.
/**************************************************************************
* Input/Output Parameters for exporting data
**************************************************************************/
this.dataExport = ""; // The data to export.
this.dataExportChange = new EventEmitter(); // Callback to set dataExport variable.
/**************************************************************************
* Input/Output Parameters for settings data
**************************************************************************/
this.settings = []; // Options that are saved outside the grid. This value should be set to the value retieved from the datagrid @Output method "settingsSavedEvent". Consider it a passthrough value.
this.clearSettingsCache = false; // Clears any grid storage of settings.
this.savedSettingsEvent = new EventEmitter(); // Used as a callback to save settings.
this.clearSettingsCacheChange = new EventEmitter(); // Callback to set clearSettingsCache variable.
/**************************************************************************
* Required Output Parameters
**************************************************************************/
this.loadDataEvent = new EventEmitter(); // Callback with grid changes.
/**************************************************************************
* Optional Input/Output Parameters
**************************************************************************/
this.name = ""; // Unique name of the grid (per page).
this.title = ""; // Title of the grid.
this.titleStyle = ""; // Style used for title.
this.fontFamily = ""; // font-family used for grid.
this.data = ""; // The data to display in the grid.
this.rowValues = [10, 25, 50, 100, 500, 1000]; // Sets the values used for records per page.
this.defaultRows = 100; // Default value for records per page.
this.saveGridDataEvent = new EventEmitter(); // Callback for saving changes to data.
this.deleteGridDataEvent = new EventEmitter(); // Callback for deleting data.
this.selectedRowsChangedEvent = new EventEmitter(); // Callback for row changes.
this.selectedRowActionEvent = new EventEmitter(); // // Callback for row actions. NOTE: The return object is { record: [the record], index: [the record index] }
/**************************************************************************
* Addon Parameters (Option Icon/Modal Window)
**************************************************************************/
this.optionAddons = [];
this.windowAddons = [];
/**************************************************************************
* Processing Parameters
**************************************************************************/
this.error = ""; // Any errors that occur during processing.
this.isDebug = false; // Turns on debugging.
this.showGrid = false;
this.editGrid = false;
this.totalPages = new Array(0);
this.deleteRecords = new Array(0);
this.editRecords = false;
/**************************************************************************
* Component Variables based on Input parameters
**************************************************************************/
this._editRecordIndex = undefined;
this._datasets = [];
this._activeDataset = "";
this._selectedDataset = "";
this._name = "";
this._options = new SDKDataGridOptions();
this._menuOptions = false;
this._data = "";
this._columns = [];
this._customFilters = [];
this._settings = [];
this._rows = 100;
this._page = 1;
this._selectedPage = "";
this._total = 0;
this._isExporting = false;
/**************************************************************************
* Options Variables
**************************************************************************/
this.optionTitle = "";
this.dataMode = "data";
this.dataClass = "";
this.columnBadge = "0";
this.filterBadge = "0";
this.sortBadge = "0";
this.formulaBadge = "0";
this.chartBadge = "0";
this.showReset = false;
this.showNote = false;
this.lockGrid = false;
/**************************************************************************
* Tooltip Variables
**************************************************************************/
this.tooltipTimer = null;
this.tooltipAutoCloseTimer = null;
this.tooltipVisible = false;
this.tooltipStyles = {};
this.recordIndex = null;
this.recordData = null;
/**************************************************************************
* Addon Variables
* - option(Inputs/Outputs): Used with the Addon icons.
* - window(Inputs/Outputs): Used with the Addon modal.
**************************************************************************/
this.optionInputs = {};
this.windowInputs = {};
this.optionOutputs = {
showDataOptionsEvent: (event) => this.showDataOptions(event),
};
this.windowOutputs = {
closeEvent: () => this.closeDataOptions(),
applyEvent: (event) => this.applyDataOptions(event),
};
/**************************************************************************
* Message Variable
**************************************************************************/
this.showMessage = false;
this.message = new SDKDataGridMessage();
}
ngOnChanges(_args) {
this.showLog("START Method: ngOnChanges >>>");
// this.showLog(["[Input]", Clone.deepCopy(_args)]);
// Handles update grid event
if (_args.updateGrid !== undefined) {
this.showLog(["updateGrid", _args.updateGrid.currentValue]);
if (_args.updateGrid.currentValue) {
if (_args.updateGrid.previousValue === undefined) {
this.setDatasets();
this.setActiveDataset(); // MUST be called before setName() - active dataset is used in setting the name.
this.setName();
this.setOptions();
this.setColumns();
this.setCustomFilters();
this.setSettings(); // MUST be called after setColumns() and setCustomFilters() in case a setting is set to active.
setTimeout(() => {
this.loadData("Initial Load", this._rows, 1);
}, 10);
}
else {
this.showLog("!!! Updating Grid !!!");
this.showInputValues();
this.setGrid();
this.setDatasets();
this.setActiveDataset(); // MUST be called before setName() - active dataset is used in setting the name.
this.setName();
this.setOptions();
this.setColumns();
this.setCustomFilters();
this.setSettings(); // MUST be called after setColumns() and setCustomFilters() in case a setting is set to active.
this.setBadges();
this.setData();
this.setRows();
this.setPage();
this.setTotal();
this.setSelectedPage();
this.showLog("!!! Grid Updated !!!");
this.showGrid = true;
setTimeout(() => {
this.editRecordIndexChange.emit(undefined);
}, 10);
}
setTimeout(() => {
this.updateGridChange.emit(false);
}, 10);
}
}
// Handles edit mode event
if (_args.editRecordIndex) {
this.setEditRecordIndex();
}
// Handles "all data" export
if (_args.dataExport !== undefined && _args.dataExport.currentValue !== undefined && _args.dataExport.currentValue !== "") {
this.exportData(true, _args.dataExport.currentValue);
}
this.showLog(">>> END Method: ngOnChanges");
}
/**************************************************************************
* Change Methods
**************************************************************************/
showInputValues() {
this.showLog("*** START: Input Values ***");
this.showLog(["editRecordIndex:", this.editRecordIndex]);
this.showLog(["datasets:", this.datasets]);
this.showLog(["activeDataset:", this.activeDataset]);
this.showLog(["name:", this.name]);
this.showLog(["title:", this.title]);
this.showLog(["titleStyle:", this.titleStyle]);
this.showLog(["settings:", Clone.deepCopy(this.settings)]);
this.showLog(["options:", Clone.deepCopy(this.options)]);
this.showLog(["data:", Clone.deepCopy(this.data)]);
this.showLog(["columns:", Clone.deepCopy(this.columns)]);
this.showLog(["customFilters:", Clone.deepCopy(this.customFilters)]);
this.showLog(["rowValues:", this.rowValues]);
this.showLog(["defaultRows:", this.defaultRows]);
this.showLog(["rows:", this.rows]);
this.showLog(["page:", this.page]);
this.showLog(["total:", this.total]);
this.showLog("*** END: Input Values ***");
}
setGrid() {
this.showLog("START Method: setGrid >>>");
this.showLog(["Set Styles", this.fontFamily]);
if (this.sdkdatagrid) {
if (this.fontFamily !== "") {
this.sdkdatagrid.nativeElement.style.setProperty("--font-family", this.fontFamily);
}
}
if (this.sdkdatagridcontent) {
this.sdkdatagridcontent.nativeElement.scrollTop = 0;
}
this.showLog(">>> END Method: setGrid");
}
setDatasets() {
this.showLog("START Method: setDatasets >>>");
this.showLog(["[Input]", this.datasets]);
this._datasets = this.datasets ?? [];
this.datasetTabs = [];
this._datasets.forEach((dataset) => {
this.datasetTabs.push({
title: dataset,
type: null,
inputs: {},
outputs: {}
});
});
this.showLog(["[Output]", this._datasets]);
this.showLog(">>> END Method: setDatasets");
}
setActiveDataset() {
this.showLog("START Method: setActiveDataset >>>");
this.showLog(["[Input]", this.activeDataset]);
this._activeDataset = this.activeDataset !== "" ? this.activeDataset : this._datasets.length > 0 ? this._datasets[0] : "";
// Initialize then let sdk-select handle value moving forward.
if (this._selectedDataset === "") {
this._selectedDataset = this._activeDataset;
}
this.showLog(["[Output]", this._activeDataset]);
this.showLog(">>> END Method: setActiveDataset");
}
setName() {
this.showLog("START Method: setName >>>");
this.showLog(["[Input]", this.name]);
if (this.route.url) {
this.route.url.subscribe(([url]) => {
if (url) {
const { path } = url;
if (url.path)
this._name = `${url.path}_${this.route.component?.name}_${this.name}_${this._activeDataset}`;
}
});
}
if (this._name === "") {
this._name = `${this.route.component?.name}_${this.name}_${this._activeDataset}`;
}
this._name = this._name.replaceAll(/[^a-zA-Z0-9]/g, "_");
this.showLog(["[Output]", this._name]);
this.showLog(">>> END Method: setName");
}
setOptions() {
this.showLog("START Method: setOptions >>>");
this.showLog(["[Input]", Clone.deepCopy(this.options)]);
this._options = new SDKDataGridOptions();
if (this.options) {
Object.getOwnPropertyNames(this._options).forEach((prop) => {
const descriptor = Object.getOwnPropertyDescriptor(this.options, prop);
if (descriptor) {
this._options[prop] = this.options[prop];
}
});
}
if (this._options.minimizeOptions !== undefined) {
this._menuOptions = false;
}
this.showLog(["[Output]", Clone.deepCopy(this._options)]);
this.showLog(">>> END Method: setOptions");
}
setColumns() {
this.showLog("START Method: setColumns >>>");
this.showLog(["[Input]", Clone.deepCopy(this.columns)]);
this._columns = [];
let _tmp = Clone.deepCopy(this.columns);
if (!_tmp || _tmp.length === 0) {
_tmp = [];
if (this.data && this.data.length > 0) {
let data = Clone.deepCopy(this.data[0]);
for (let key in data) {
_tmp.push({ Name: key.toString() });
}
}
}
_tmp.forEach((column, index) => {
this.initializeColumn(new SDKDataGridColumn(), column, index);
});
// Load all left-side action columns.
_tmp.filter((column) => column.isAction && column.actionSide === "left").forEach((column) => {
this._columns.push({ ...column });
});
// Load all non-action columns.
_tmp.filter((column) => !column.isAction).forEach((column) => {
this._columns.push({ ...column });
});
// Load all right-side action columns.
_tmp.filter((column) => column.isAction && column.actionSide === "right").forEach((column) => {
this._columns.push({ ...column });
});
this.showLog(["[Output]", Clone.deepCopy(this._columns)]);
this.showLog(">>> END Method: setColumns");
}
setCustomFilters() {
this.showLog("START Method: setCustomFilters >>>");
this.showLog(["[Input]", Clone.deepCopy(this.customFilters)]);
this._customFilters = [];
let _tmp = Clone.deepCopy(this.customFilters);
if (_tmp && _tmp.length > 0) {
_tmp.forEach((filter, index) => {
this.initializeCustomFilter(new SDKDataGridCustomFilter(), filter, index);
this._customFilters.push({ ...filter });
});
}
this.showLog(["[Output]", Clone.deepCopy(this._customFilters)]);
this.showLog(">>> END Method: setCustomFilters");
}
setSettings() {
this.showLog("START Method: setSettings >>>");
if (!this._options.settings) {
this.settings = [];
// REMOVES SETTINGS FROM "GRID" STORAGE IF FORCED
if (this.clearSettingsCache) {
this.showLog("!!! Clear Settings Cache !!!");
let storageItemName = `SDK-DATAGRID_${this._name}`;
localStorage.removeItem(storageItemName);
sessionStorage.removeItem(storageItemName);
setTimeout(() => {
this.clearSettingsCacheChange.emit(false);
}, 10);
}
else {
// LOAD SETTINGS FROM "GRID" STORAGE
let storageItemName = `SDK-DATAGRID_${this._name}`;
let storage = this._options.settingsStorage === StorageType.Local ? localStorage.getItem(storageItemName) : sessionStorage.getItem(storageItemName);
if (storage) {
this.settings = JSON.parse(storage);
}
}
}
else {
let storageItemName = `SDK-DATAGRID_${this._name}`;
localStorage.removeItem(storageItemName);
sessionStorage.removeItem(storageItemName);
}
this.showLog(["[Input]", Clone.deepCopy(this.settings)]);
this._settings = [];
let _tmp = Clone.deepCopy(this.settings);
_tmp.forEach((setting) => {
let _setting = new SDKDataGridSettings();
Object.getOwnPropertyNames(_setting).forEach((prop) => {
const descriptor = Object.getOwnPropertyDescriptor(setting, prop);
if (!descriptor) {
setting[prop] = _setting[prop];
}
});
this._settings.push({ ...setting });
});
let ndx = this._settings.findIndex((setting) => setting.Active);
if (ndx > -1) {
this._columns = Clone.deepCopy(this._settings[ndx].Columns);
this._columns.forEach((column, index) => {
let columnNdx = this.columns.findIndex((c) => c.Name === column.Name);
if (columnNdx > -1) {
this.initializeColumn(this.columns[columnNdx], column, index);
}
});
this._customFilters = Clone.deepCopy(this._settings[ndx].CustomFilters);
this._customFilters.forEach((filter, index) => {
let filternNdx = this.customFilters.findIndex((f) => f.Name === filter.Name);
if (filternNdx > -1) {
this.initializeCustomFilter(this.customFilters[filternNdx], filter, index);
}
});
}
this.showLog(["[Output]", Clone.deepCopy(this._settings)]);
this.showLog(">>> END Method: setSettings");
}
setBadges() {
this.showLog("START Method: setBadges >>>");
this.showNote = this._columns.filter((column) => column.FriendlyName !== "").length > 0 ? true : false;
let columnCount = this._columns.filter((column, index) => index !== column._original.index).length > 0 ? 1 : 0;
columnCount += this._columns.filter((column) => column.isVisible !== column._original.isVisible || column.FriendlyName !== column._original.FriendlyName).length;
this.columnBadge = columnCount.toString();
let filterCount = this._columns.filter((column) => column.Filter).length;
filterCount += this._customFilters.filter((filter) => filter.Filter).length;
this.filterBadge = filterCount.toString();
this.sortBadge = this._columns.filter((column) => column.Sort).length.toString();
let formulaCount = 0;
this._columns.filter((column) => column.Formulas).forEach((column) => {
formulaCount += column.Formulas.length;
});
this.formulaBadge = formulaCount.toString();
if (this.columnBadge !== "0" || this.filterBadge !== "0" || this.sortBadge !== "0" || this.formulaBadge !== "0") {
this.showReset = true;
}
else {
this.showReset = false;
}
this.showLog(">>> END Method: setBadges");
}
setData() {
this.showLog("START Method: setData >>>");
this.showLog(["[Input]", Clone.deepCopy(this.data)]);
this._data = Clone.deepCopy(this.data);
this.showLog(["[Output]", Clone.deepCopy(this._data)]);
this.showLog(">>> END Method: setData");
}
setRows() {
this.showLog("START Method: setRows >>>");
this.showLog(["[Input]", this.rows, "(Default)", this.defaultRows]);
this._rows = this.rows ?? this.defaultRows;
this.showLog(["[Output]", this._rows]);
this.showLog(">>> END Method: setRows");
}
setPage() {
this.showLog("START Method: setPage >>>");
this.showLog(["[Input]", this.page]);
this._page = this.page ?? 1;
this.showLog(["[Output]", this._page]);
this.showLog(">>> END Method: setPage");
}
setTotal() {
this.showLog("START Method: setTotal >>>");
this.showLog(["[Input]", this.total]);
if (this.total === undefined) {
this._total = this._data.length;
}
else {
this._total = this.total;
}
this.showLog(["[Output]", this._total]);
this.showLog(">>> END Method: setTotal");
}
setSelectedPage() {
this.showLog("START Method: setSelectedPage >>>");
if (this.totalPages.length === 0 || this.totalPages.length !== Math.ceil(this._total / this._rows)) {
this.showLog("Updating pages...");
this.totalPages = new Array(0);
for (let p = 0; p < Math.ceil(this._total / this._rows); p++) {
let start = (p * this._rows) + 1;
let end = (start + this._rows) - 1;
if (end > this._total)
end = this._total;
this.totalPages.push(start.toString() + " - " + end.toString());
}
}
let rowStart = ((this._page - 1) * this._rows) + 1;
let rowEnd = (rowStart + this._rows) - 1;
if (rowEnd > this._total)
rowEnd = this._total;
this._selectedPage = rowStart.toString() + " - " + rowEnd.toString();
this.showLog(["[Output]", this._selectedPage]);
this.showLog(">>> END Method: setSelectedPage");
}
setEditRecordIndex() {
this.showLog("START Method: setEditRecordIndex >>>");
this.showLog(["[Input]", this.editRecordIndex]);
this._editRecordIndex = this.editRecordIndex;
this.showLog(["[Output]", this._editRecordIndex]);
this.showLog(">>> END Method: setEditRecordIndex");
}
/**************************************************************************
* Data Methods
**************************************************************************/
loadData(action, rows, page) {
this.showLog("START Method: loadData >>>");
this.showLog(["action", action, "rows", rows, "page", page]);
this.editRecordIndexChange.emit(undefined);
this.columnsChange.emit(this._columns);
this.customFiltersChange.emit(this._customFilters);
this.setAddonInputs();
this.loadDataEvent.emit({ action: action, rows: rows, page: page });
this.showLog(">>> END Method: loadData");
}
selectDataset(event) {
this.showLog("START Method: selectDataset (Dropdown) >>>");
this.showLog(["[Input]", event[0]]);
this.activeDatasetChange.emit(event[0]);
setTimeout(() => {
this.setActiveDataset(); // MUST be called before setName() - active dataset is used in setting the name.
this.setName();
this.setSettings(); // MUST be called in case columns are saved.
this.loadData(`Dataset Change`, this._rows, 1);
}, 10);
this.showLog(">>> END Method: selectDataset (Dropdown)");
}
datasetChanged(event) {
this.showLog("START Method: datasetChanged (Tab) >>>");
this.showLog(["[Input]", event]);
if (event.from) {
this.activeDatasetChange.emit(event.to.title);
setTimeout(() => {
this.setActiveDataset(); // MUST be called before setName() - active dataset is used in setting the name.
this.setName();
this.setSettings(); // MUST be called in case columns are saved.
this.loadData(`Dataset Change`, this._rows, 1);
}, 10);
}
this.showLog(">>> END Method: datasetChanged (Tab)");
}
saveData() {
this.showLog("START Method: saveData >>>");
if (this.missingData()) {
this.message = {
Title: "Missing Data",
Text: "You are missing some required data.",
OKText: "OK",
OK: () => {
this.showMessage = false;
}
};
}
else {
this.message = {
Title: "Save Changes",
Text: "Are you sure?",
OKText: "YES",
CancelText: "NO",
OK: () => {
this.showMessage = false;
this.editGrid = false;
this.editRecords = false;
if (this.saveGridDataEvent.observed) {
this.saveGridDataEvent.emit(this._data);
}
this.editRecordIndexChange.emit(undefined);
this.updateGridChange.emit(false);
},
Cancel: () => {
this.showMessage = false;
}
};
}
this.showMessage = true;
this.showLog(">>> END Method: saveData");
}
deleteData() {
this.showLog("START Method: deleteData >>>");
this.showLog(["records", this.deleteRecords]);
if (this.deleteRecords.length > 0) {
this.editRecords = this.hasDataChanged();
if (this.editRecords) {
this.message = {
Title: "Save Changes",
Text: "You've made changes to the data.<br /><br />Would you like to save them before continuing?",
OKText: "YES",
CancelText: "NO",
OK: () => {
this.editRecords = false;
if (this.saveGridDataEvent.observed) {
this.saveGridDataEvent.emit(this._data);
}
this.editRecordIndexChange.emit(undefined);
this.updateGridChange.emit(false);
this.deleteData();
},
Cancel: () => {
this.editRecords = false;
this._data = Clone.deepCopy(this.data);
this.deleteData();
}
};
}
else {
this.message = {
Title: "Delete record(s)",
Text: "Are you sure?",
OKText: "YES",
CancelText: "NO",
OK: () => {
this.showMessage = false;
if (this.deleteGridDataEvent.observed) {
this.deleteGridDataEvent.emit(this.deleteRecords);
}
this.deleteRecords = [];
},
Cancel: () => {
this.showMessage = false;
}
};
}
this.showMessage = true;
}
this.showLog(">>> END Method: deleteData");
}
selectRecord(index) {
let ndx = this.deleteRecords.findIndex((record) => record === index);
if (ndx > -1) {
this.deleteRecords.splice(ndx, 1);
}
else {
this.deleteRecords.push(index);
}
}
isRecordSelected(index) {
let ndx = this.deleteRecords.findIndex((record) => record === index);
if (ndx > -1) {
return true;
}
else {
return false;
}
}
cancelEdit() {
this.showLog("START Method: cancelEdit >>>");
this.editRecords = this.hasDataChanged();
if (this.editRecords) {
this.message = {
Title: "Cancel Changes",
Text: "You've made changes to the data.<br /><br />Are you sure you want to cancel without saving them?",
OKText: "YES",
CancelText: "NO",
OK: () => {
this.showMessage = false;
this.editGrid = false;
this.editRecords = false;
this.deleteRecords = [];
this.loadData("Cancel Changes", this._rows, this._page);
},
Cancel: () => {
this.showMessage = false;
}
};
this.showMessage = true;
}
else {
this.editGrid = false;
this.editRecords = false;
this.deleteRecords = [];
}
this.showLog(">>> END Method: cancelEdit");
}
hasDataChanged() {
return !(this.data.length === this._data.length &&
this.data.every((element_1) => this._data.some((element_2) => Object.keys(element_1).every((key) => element_1[key] === element_2[key]))));
}
missingData() {
return this._data.some((record) => {
return this._columns.filter((column) => column.required)
.some((column) => record[column.Name] === "");
});
}
/**************************************************************************
* Options Methods
**************************************************************************/
showDataOptions(type) {
this.showLog("START Method: showDataOptions >>>");
this.showLog(["type", type]);
this.lockGrid = true;
this.dataClass = this._options.panelOverlay ? "overlay" : "expand";
this.dataMode = "data";
this.optionTitle = type;
if (type === "export") {
this.dataExportChange.emit(""); // Clears out value
}
this.setAddonInputs();
this.showLog(">>> END Method: showDataOptions");
}
toggleDataMode(type, autoClose = false) {
// this.dataMode = type;
// if (this.dataMode === "data" && this.optionTitle === "Chart") {
// this.dataClass = "";
// this.optionTitle = "";
// }
// if (this.dataMode === "chart") {
// if (this.chart && this.chart !== "") {
// this.applyChartOptions(this.chart, autoClose);
// }
// }
}
closeDataOptions() {
this.showLog("START Method: closeDataOptions >>>");
this.optionTitle = "";
this.dataClass = "";
this.lockGrid = false;
this.setAddonInputs();
this.showLog(">>> END Method: closeDataOptions");
}
resetAllOptions() {
this.showLog("START Method: resetAllOptions >>>");
this.message = {
Title: "Reset ALL Options",
Text: "Are you sure?",
OKText: "YES",
CancelText: "NO",
OK: () => {
this.showMessage = false;
this.dataMode = "data";
this.optionTitle = "";
this.dataClass = "";
this._columns.sort((a, b) => (a._original.index > b._original.index) ? 1 : -1);
this._columns.forEach((column) => {
column.FriendlyName = column._original.FriendlyName;
column.isVisible = column._original.isVisible;
column.Sort = column._original.Sort;
column.Filter = column._original.Filter;
column.Formulas = column._original.Formulas;
});
this._customFilters.forEach((filter) => {
filter.Filter = filter._original.Filter;
});
if (this._options.settings) {
this.saveSettings(this._settings, true);
}
else {
// REMOVE SETTINGS FROM "GRID" STORAGE
let storageItemName = `SDK-DATAGRID_${this._name}`;
if (this._options.settingsStorage === StorageType.Local) {
localStorage.removeItem(storageItemName);
}
else {
sessionStorage.removeItem(storageItemName);
}
this.settings = [];
}
this.showReset = false;
this.loadData("Reset ALL Options", this._rows, 1);
},
Cancel: () => {
this.showMessage = false;
}
};
this.showMessage = true;
this.showLog(["columns", this._columns, "customFilters", this._customFilters]);
this.showLog(">>> END Method: resetAllOptions");
}
applyOptions(event) {
this.showLog("START Method: applyOptions >>>");
this.showLog(["[Input]", event]);
let action = "Options";
if (event?.option)
action = event.option;
if (event?.columns)
this._columns = event.columns;
if (event?.customFilters)
this._customFilters = event.customFilters;
if (this._options.settings) {
this.saveSettings(this._settings, true);
}
else {
// ADD SETTINGS TO "GRID" STORAGE
let storageItemName = `SDK-DATAGRID_${this._name}`;
let settings = [{
Name: "[sdk-datagrid Settings]",
Columns: this._columns,
CustomFilters: this._customFilters,
Active: true
}];
if (this._options.settingsStorage === StorageType.Local) {
localStorage.setItem(storageItemName, JSON.stringify(settings));
}
else {
sessionStorage.setItem(storageItemName, JSON.stringify(settings));
}
}
let rows = this._rows;
let page = this._page;
if (this.optionTitle !== "columns") {
page = 1;
}
if (this._options.autoClosePanel) {
this.closeDataOptions();
}
this.loadData(`Apply ${action}`, rows, page);
this.showLog(">>> END Method: applyOptions");
}
/**************************************************************************
* Addon Methods
**************************************************************************/
applyDataOptions(event) {
this.showLog("START Method: applyDataOptions >>>");
this.showLog(["option", this.optionTitle]);
if (event?.columns)
this._columns = event.columns;
if (event?.customFilters)
this._customFilters = event.customFilters;
this.editRecordIndexChange.emit(undefined);
this.columnsChange.emit(this._columns);
this.customFiltersChange.emit(this._customFilters);
this.loadDataEvent.emit({ action: this.optionTitle, rows: this._rows, page: 1, addon: event });
this.setAddonInputs();
this.showLog(">>> END Method: applyDataOptions");
}
setAddonInputs() {
this.optionInputs = {
optionTitle: this.optionTitle,
};
this.windowInputs = {
dataClass: this.dataClass,
optionTitle: this.optionTitle,
columns: this._columns ?? [],
customFilters: this._customFilters ?? []
};
}
/**************************************************************************
* Settings Methods
**************************************************************************/
applySettingsOptions(event) {
this.showLog("START Method: applySettingsOptions >>>");
this.showLog(["[Input]", event]);
if (event?.columns) {
this._columns = Clone.deepCopy(event.columns);
this._columns.forEach((column, index) => {
let columnNdx = this.columns.findIndex((c) => c.Name === column.Name);
if (columnNdx > -1) {
this.initializeColumn(this.columns[columnNdx], column, index);
}
});
}
if (event?.customFilters) {
this._customFilters = Clone.deepCopy(event.customFilters);
this._customFilters.forEach((filter, index) => {
let filternNdx = this.customFilters.findIndex((f) => f.Name === filter.Name);
if (filternNdx > -1) {
this.initializeCustomFilter(this.customFilters[filternNdx], filter, index);
}
});
}
let rows = this._rows;
let page = 1;
if (this._options.autoClosePanel) {
this.closeDataOptions();
}
this.loadData("Apply Settings", rows, page);
this.showLog(">>> END Method: applySettingsOptions");
}
saveSettings(event, resetActive = false) {
this.showLog("START Method: saveSettings >>>");
this.showLog(["[Input]", event]);
let settings = event.filter((setting) => setting.Name !== "[Current Settings]");
if (resetActive) {
settings.forEach((setting) => {
setting.Active = false;
});
}
this._settings = settings;
this.savedSettingsEvent.emit(this._settings);
this.showLog(">>> END Method: saveSettings");
}
/**************************************************************************
* Export Methods
**************************************************************************/
applyExportOptions(event) {
this.showLog("START Method: applyExportOptions >>>");
this.showLog(["[Input]", event]);
this._isExporting = true;
setTimeout(() => {
let includeAllData = event;
if (includeAllData) {
this.loadDataEvent.emit({ action: "Export Data" });
}
else {
this.exportData(false, Clone.deepCopy(this._data));
}
}, 100);
this.showLog(">>> END Method: applyExportOptions");
}
exportData(includeAllData, data) {
this.showLog("START Method: exportData >>>");
this.showLog(["includeAllData", includeAllData]);
if (!includeAllData) {
data = this.adjustExportColumns(data);
}
let dataArray = JSON.parse(JSON.stringify(data));
let link = document.createElement("a");
link.href = 'data:text/csv;charset=utf-8,' + this.convertToCSV(dataArray);
link.download = "export.csv";
link.click();
this._isExporting = false;
if (this._options.autoClosePanel) {
this.closeDataOptions();
}
this.showLog(">>> END Method: exportData");
}
adjustExportColumns(tmp) {
let rows = [];
tmp.forEach((row) => {
let columns = {};
this._columns.forEach((column) => {
if (column.isVisible && !column.isAction) {
if (column.FriendlyName !== "") {
columns[column.FriendlyName] = row[column.Name];
}
else if (column.DisplayName !== "") {
columns[column.DisplayName] = row[column.Name];
}
else {
columns[column.Name] = row[column.Name];
}
}
});
rows.push(columns);
});
return rows;
}
convertToCSV(objArray) {
let csv = "";
for (let row = 0; row < objArray.length; row++) {
let output = "";
// Add column names as first row.
if (csv === "") {
for (let column in objArray[row]) {
if (output !== "") {
output += ",";
}
output += column;
}
csv += `${output}\r\n`;
output = "";
}
for (let column in objArray[row]) {
if (output !== "") {
output += ",";
}
if (objArray[row][column]) {
let data = `"${objArray[row][column].toString().replace(/"/g, '""')}"`;
output += data;
}
else {
output += "";
}
}
csv += `${encodeURIComponent(output)}\r\n`;
}
return csv;
}
/**************************************************************************
* Row Methods
**************************************************************************/
takeAction(args) {
this.showLog("START Method: takeAction >>>");
this.showLog(["[Input]", args]);
if (this.selectedRowActionEvent.observed) {
this.selectedRowActionEvent.emit(args);
}
this.showLog(">>> END Method: takeAction");
}
setTooltip(event, index, record) {
if (!this.tooltipTemplate)
return;
if (index !== this.recordIndex) {
this.tooltipVisible = false;
this.tooltipStyles = {
position: 'fixed',
zIndex: '9999',
top: `0px`,
left: `0px`,
visibility: 'hidden'
};
this.recordIndex = index;
this.recordData = record;
}
}
showTooltip(event, index, record) {
if (!this.tooltipTemplate)
return;
clearTimeout(this.tooltipTimer);
clearTimeout(this.tooltipAutoCloseTimer);
if (!this.tooltipVisible) {
this.tooltipTimer = setTimeout(() => {
this.tooltipVisible = true;
this.setTooltipPosition(event);
}, 1000);
}
this.tooltipAutoCloseTimer = setTimeout(() => {
this.hideTooltip(event, -1, -1);
}, 5000);
}
keepTooltipAlive() {
if (!this.tooltipTemplate)
return;
clearTimeout(this.tooltipTimer);
clearTimeout(this.tooltipAutoCloseTimer);
this.tooltipVisible = true;
}
hideTooltip(event, index, record) {
if (!this.tooltipTemplate)
return;
clearTimeout(this.tooltipTimer);
clearTimeout(this.tooltipAutoCloseTimer);
if (this.tooltipVisible && index !== this.recordIndex) {
this.tooltipVisible = false;
this.recordIndex = null;
this.recordData = null;
this.tooltipStyles = {
position: 'fixed',
zIndex: '9999',
top: `0px`,
left: `0px`,
visibility: 'hidden'
};
}
}
setTooltipPosition(event) {
if (!this.tooltipTemplate)
return;
let offsetY = 5;
let offsetX = 5;
setTimeout(() => {
let tooltip = this.sdktooltip.nativeElement;
if (tooltip && (event.clientY + tooltip.offsetHeight) > (window.innerHeight - 50)) {
offsetY = (tooltip.offsetHeight * -1) - 5;
}
if (tooltip && (event.clientX + tooltip.offsetWidth) > (window.innerWidth - 100)) {
offsetX = (tooltip.offsetWidth * -1) - 5;
}
this.tooltipStyles = {
position: 'fixed',
zIndex: '9999',
top: `${event.clientY + offsetY}px`,
left: `${event.clientX + offsetX}px`,
visibility: 'visible'
};
}, 1);
}
// Used to remember where the scrollbar was on click-throughs (drill-downs).
// protected onScroll(args: any) {
// // if (this.selectedRowActionEvent.observed) {
// // this._scrollTop = args.target.scrollTop;
// // }
// }
/**************************************************************************
* Expand/Collapse Rows
**************************************************************************/
expandAll() {
this.setExpandedForAll(true);
}
collapseAll() {
this.setExpandedForAll(false);
}
toggleExpanded(rowItem) {
rowItem["Expanded"] = !rowItem["Expanded"];
}
isFirstColumn(column) {
let visibleColumns = this._columns.filter(c => c.isVisible);
return visibleColumns.length > 0 && column.Name === visibleColumns[0].Name;
}
setExpandedForAll(isExpanded) {
let dataItems = this._data;
dataItems.forEach((item) => {
item["Expanded"] = isExpanded;
});
}
/**************************************************************************
* Column Methods
**************************************************************************/
getColumnName(column) {
let originalName = column.Name;
if (column.FriendlyName !== "") {
originalName = `${column.FriendlyName} *`;
}
else if (column.DisplayName !== "") {
originalName = column.DisplayName;
}
return originalName;
}
getOriginalColumnName(column) {
let originalName = column.Name;
if (column.DisplayName && column.DisplayName !== "") {
originalName = column.DisplayName;
}
return `Orig. Name:\n${originalName}`;
}
hasVisibleColumns() {
return this._columns.filter((column) => column.isVisible);
}
hasFormulas() {
return this._columns.filter((column) => column.Formulas);
}
isColumnObject(value) {
if (typeof (value) === "object") {
return true;
}
else {
return false;
}
}
sortColumn(column) {
let ndx = this._columns.findIndex((c) => c.Name === column.Name);
let sort = null;
if (ndx > -1 && !this._columns[ndx].isAction && this._columns[ndx].showSort) {
sort = this._columns[ndx].Sort;
if (sort) {
this._columns[ndx].Sort.direction = (this._columns[ndx].Sort?.direction === Sorts.ASC) ? Sorts.DESC : Sorts.ASC;
}
else {
this._columns[ndx].Sort = { direction: Sorts.ASC, position: 0 };
}
this.applyOptions({ columns: this._columns });
}
}
/**************************************************************************
* Page Methods
**************************************************************************/
getRows(event) {
this.showLog("START Method: getRows >>>");
this.showLog(["rows", event[0]]);
this.loadData("Rows/Page Change", parseInt(event[0]), 1);
this.showLog(">>> END Method: getRows");
}
getPage(event) {
this.showLog("START Method: getPage >>>");
this.showLog(["page", Array.isArray(event) ? Math.ceil(parseInt(event[0].split(" - ")[1]) / this._rows) : event]);
if (A