import { CommonModule } from '@angular/common'; import { NgModule, Component, Input, OnInit, AfterViewInit, OnChanges, NO_ERRORS_SCHEMA } from '@angular/core'; import { RdComponent } from '../../base/rdComponent'; import Handsontable from 'handsontable'; import { HotTableModule, HotTableRegisterer } from '@handsontable/angular'; export type ColumnTypes = 'text' | 'numeric' | 'date' | 'time' | 'checkbox' | 'password' | 'dropdown'; export interface SpreadSheetColumn { id: any, title: any type?: ColumnTypes, readOnly?: boolean, hashLength?: number, // use for password -> 10 timeFormat?: string, // use for time -> 'h:mm:ss a' dateFormat?: string, // use for date -> 'YYYY-MM-DD', correctFormat?: boolean, // force selected date or time format source?: Array, // use for dropdown -> ["red","green","blue"] } @Component({ selector: 'rd-spreadsheet', template: ` ` }) export class SpreadSheet extends RdComponent implements OnInit, OnChanges, AfterViewInit { @Input("rd-data") data: Array; @Input("rd-settings") customSettings: Handsontable.GridSettings; public id = "spreadsheet" + Math.random().toFixed(4); public instance: Handsontable; private searchPlugin; private exportPlugin; private hotRegisterer = new HotTableRegisterer(); baseSettings: Handsontable.GridSettings = { data: [], // columns: [], stretchH: 'all', search: true, formulas: true, filters: true, rowHeaders: true, colHeaders: true, dropdownMenu: true, columnSorting: true, contextMenu: true, comments: true, width: '100%', // height: window.innerHeight * .7, manualRowMove: true, manualColumnMove: true, manualRowResize: true, manualColumnResize: true, manualColumnFreeze: true, autoColumnSize: { useHeaders: true }, headerTooltips: { rows: false, columns: true, onlyTrimmed: true }, cells: function () { return { renderer: "cellBgRenderer" } } }; ngOnInit() { Handsontable.renderers.registerRenderer("cellBgRenderer", this.cellBgRenderer); } ngOnChanges(changes) { if (changes.customSettings) { this.baseSettings = { ...this.baseSettings, ...this.customSettings }; if (this.instance) this.instance.updateSettings(this.baseSettings); } if (changes.data && this.instance) this.instance.loadData(this.data); } ngAfterViewInit() { this.instance = this.hotRegisterer.getInstance(this.id); this.searchPlugin = this.instance.getPlugin("search"); this.exportPlugin = this.instance.getPlugin("exportFile"); } //#region Plugins search(text) { this.searchPlugin.query(text); this.instance.render(); } export() { this.exportPlugin.downloadFile('csv', { bom: false, columnDelimiter: ',', columnHeaders: false, exportHiddenColumns: true, exportHiddenRows: true, fileExtension: 'csv', filename: 'Export-CSV-file_[YYYY]-[MM]-[DD]', mimeType: 'text/csv', rowDelimiter: '\r\n', rowHeaders: true }); } //#endregion loadFileData(dataJson) { let allHeads = []; let parsedData = JSON.parse(dataJson); let settings = { data: [], // columns: [], colHeaders: [] } /** Headers */ for (let item of parsedData) allHeads = allHeads.concat(Object.keys(item)); settings.colHeaders = Array.from(new Set(allHeads)); /** Columns */ /** when baseSettings -> data : Array */ // for (let index in settings.colHeaders) settings.columns.push({ data: index }); /** when baseSettings -> data : Array */ // for (let col of settings.colHeaders) settings.columns.push({ data: col, type: "text" }); /** data-complate */ for (let item of parsedData) { let valueArr = []; for (let head of settings.colHeaders) { if (!item.hasOwnProperty(head)) item[head] = ""; valueArr.push(item[head]); } settings.data.push(valueArr); } this.instance.updateSettings(settings); } cellBgRenderer(instance, td, row, col, prop, value, cellProperties) { Handsontable.renderers.TextRenderer.apply(this, arguments); if (value) td.style.background = '#fff'; else td.style.background = '#eee'; } formulasInfoTooltip = "
    " + "
  • Arithmetic operations such as: +, -, /, *, %, ^
  • " + "
  • Logical operations such as: AND(), OR(), NOT(), XOR()
  • " + "
  • Comparison operations such as: =, >, >=, <, <=, <>
  • " + "
  • All JavaScript Math constants such as: PI(), E(), LN10(), LN2(), LOG10E(), LOG2E(), SQRT1_2(), SQRT2()
  • " + "
  • Error handling: #DIV/0!, #ERROR!, #VALUE!, #REF!, #NAME?, #N/A, #NUM!
  • " + "
  • String operations such as: & (concatenation eq. =-(2&5) will return -25)
  • " + "
  • Relative and absolute cell references such as: A1, $A1, A$1, $A$1
  • " + "
  • Build-in variables such as: TRUE, FALSE, NULL
  • " + "
"; } @NgModule({ imports: [CommonModule, HotTableModule], exports: [SpreadSheet], declarations: [SpreadSheet], schemas: [NO_ERRORS_SCHEMA] }) export class RdSpreedSheetModule { }