ngx-gem-spaas
Version:
This library contains services, components, images and styles to provide a unified look and way-of-working throughout GEM SPaaS.
349 lines (340 loc) • 18.4 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Component, Input, EventEmitter, Output, NgModule } from '@angular/core';
import * as i4 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import { CommonModule } from '@angular/common';
import * as i1 from 'ngx-gem-spaas';
import { UtilsService, BaseComponent } from 'ngx-gem-spaas';
import { takeUntil } from 'rxjs/operators';
import * as ExcelJS from 'exceljs';
import { saveAs } from 'file-saver';
import * as i3 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
class ExcelService {
constructor(settingsService, snackbarService) {
this.settingsService = settingsService;
this.snackbarService = snackbarService;
this.settings = this.settingsService.getSettings();
}
exportFile(sheetsToExport, fileName, colsToInclude = [], colsToExclude = [], isToStringify = false) {
const workbook = new ExcelJS.Workbook();
const sheetsCreated = [];
for (const sheet of sheetsToExport) {
// check that a sheet with the same name has not been created yet (throws an error in ExcelJS)
if (!sheetsCreated.includes(sheet.sheetName)) {
// IF NOT AN ARRAY THEN WRAP IN ARRAY
let arrData = Array.isArray(sheet.sheetData) ? UtilsService.copy(sheet.sheetData) : UtilsService.copy([sheet.sheetData]);
// SOME COLUMNS CONTAIN OBJECTS: STRINGIFY
if (isToStringify) {
for (const curData of arrData) {
for (const curCol in curData) {
if (curData.hasOwnProperty(curCol) && UtilsService.checkJSON(JSON.stringify(curData[curCol]))) {
curData[curCol] = JSON.stringify(curData[curCol]);
}
}
}
}
// add sheet
const worksheet = workbook.addWorksheet(sheet.sheetName);
// add headers
let headers = colsToInclude?.length ? colsToInclude : Object.keys(sheet.sheetData[0]);
if (colsToExclude?.length) {
headers = headers.filter((h) => !colsToExclude.includes(h));
}
worksheet.addRow(headers);
// add data
for (const row of sheet.sheetData) {
let r = [];
for (const header of headers) {
if (this.settings.exportExtension === 'csv' && this.settings.decimalSeparator === 'comma') {
row[header] = typeof row[header] === 'number' ? ('' + row[header]).replace('.', ',') : row[header];
}
r.push(row[header]);
}
worksheet.addRow(r);
}
sheetsCreated.push(sheet.sheetName);
}
else {
this.snackbarService.error(`Duplicate sheet names: a sheet with name "${sheet.sheetName}" has already been created!`);
}
}
// CLEAN FILENAME
const fName = fileName.replace(/ /g, '_');
if (this.settings?.exportExtension === 'xlsx') {
workbook.xlsx.writeBuffer()
.then((buffer) => {
saveAs(new Blob([buffer]), fName + '.' + this.settings.exportExtension);
});
}
else {
workbook.csv.writeBuffer({ formatterOptions: { delimiter: this.settings.getCsvDelimiter() } }).then((buffer) => {
saveAs(new Blob([buffer]), fName + '.' + this.settings.exportExtension);
});
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelService, deps: [{ token: i1.SettingsService }, { token: i1.SnackbarService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.SettingsService }, { type: i1.SnackbarService }] });
class ExcelExportComponent extends BaseComponent {
constructor(excelExportService, settingsService) {
super();
this.excelExportService = excelExportService;
this.settingsService = settingsService;
// TOOLTIP MESSAGE
this.tooltipMsg = '';
// FILENAME FOR THE EXCEL FILE
this.fileName = '';
// DATE TO EXPORT
this.sheets = [];
this.settings = null;
this.getSettings();
}
// ********************************************************************************************************
// LOAD DATA
// ********************************************************************************************************
getSettings() {
this.settingsService.onNewSettings()
.pipe(takeUntil(this.onDestroy$))
.subscribe((settings) => {
this.settings = settings;
if (!this.tooltipMsg) {
// set default label
this.tooltipMsg = 'export to ' + settings.exportExtension;
}
});
}
// ********************************************************************************************************
// DOM
// ********************************************************************************************************
// EVENT LISTENERS
onExport() {
if (!this.settings) {
throw new Error('something is wrong with your library implementation: no settings received from settings.service');
}
this.excelExportService.exportFile(this.sheets, this.fileName);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelExportComponent, deps: [{ token: ExcelService }, { token: i1.SettingsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ExcelExportComponent, selector: "spaas-excel-export", inputs: { tooltipMsg: "tooltipMsg", fileName: "fileName", sheets: "sheets" }, usesInheritance: true, ngImport: i0, template: "<mat-icon (click)=\"onExport()\"\r\n fontIcon=\"download\"\r\n matTooltipPosition=\"below\"\r\n [matTooltip]=\"tooltipMsg\">\r\n</mat-icon>\r\n", styles: [""], dependencies: [{ kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelExportComponent, decorators: [{
type: Component,
args: [{ selector: 'spaas-excel-export', template: "<mat-icon (click)=\"onExport()\"\r\n fontIcon=\"download\"\r\n matTooltipPosition=\"below\"\r\n [matTooltip]=\"tooltipMsg\">\r\n</mat-icon>\r\n" }]
}], ctorParameters: () => [{ type: ExcelService }, { type: i1.SettingsService }], propDecorators: { tooltipMsg: [{
type: Input
}], fileName: [{
type: Input,
args: [{ required: true }]
}], sheets: [{
type: Input,
args: [{ required: true }]
}] } });
class ExcelImportComponent extends BaseComponent {
static parseWorksheet(worksheet) {
const newSheet = { sheetData: [], sheetName: worksheet.name };
const sheetColumns = [];
worksheet.eachRow({ includeEmpty: false }, (row, rowNumber) => {
// set columns if not set yet
// do not rely on rowNumber to define the first row (being zero or one), it's the actual row number in excel
if (!sheetColumns.length) {
// take column header values from first row as attributes for the rows
row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
sheetColumns.push('' + cell.value);
});
}
else {
// parse all other rows (so except the first one, which is considered to contain headers)
let rowData = {};
row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
// colNumber is 1-based !!
if (sheetColumns[colNumber - 1] !== 'null') {
rowData[sheetColumns[colNumber - 1]] = cell.formula ? cell.result : cell.value;
}
});
newSheet.sheetData.push(rowData);
}
});
return newSheet;
}
constructor(settingsService, snackbarService) {
super();
this.settingsService = settingsService;
this.snackbarService = snackbarService;
// TOOLTIP MESSAGE
this.tooltipMsg = '';
// EMIT THE IMPORTED SHEETS
this.sheetsImported = new EventEmitter();
this.rawFileContent = null;
this.settings = null;
this.getSettings();
}
// ********************************************************************************************************
// LOAD DATA
// ********************************************************************************************************
getSettings() {
this.settingsService.onNewSettings()
.pipe(takeUntil(this.onDestroy$))
.subscribe((settings) => {
this.settings = settings;
if (!this.tooltipMsg) {
// set default label
this.tooltipMsg = 'import from ' + settings.exportExtension;
}
});
}
// ********************************************************************************************************
// PROCESS DATA
// ********************************************************************************************************
readFile(e) {
this.rawFileContent = null;
if (e?.target?.files && e.target.files.length === 1) {
const file = e.target.files[0];
// READ FILE IF EXCEL
const reader = new FileReader();
const isExcel = this.settings?.exportExtension === 'xlsx' && file.type.match('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
const isCsv = this.settings?.exportExtension === 'csv' && file.type.match('text/csv');
if (isExcel) {
reader.onloadend = () => {
// RESET UPLOADER
e.target.value = null;
// THEN PROCESS RESULT
this.rawFileContent = reader.result;
if (this.rawFileContent) {
this.parseExcel();
}
else {
this.snackbarService.message('File does not contain valid data');
}
};
reader.readAsArrayBuffer(file);
}
else if (isCsv) {
reader.onloadend = () => {
// RESET UPLOADER
e.target.value = null;
// THEN PROCESS RESULT
this.rawFileContent = reader.result;
if (this.rawFileContent) {
this.parseCsv();
}
else {
this.snackbarService.message('File does not contain valid data');
}
};
reader.readAsText(file);
}
else {
// neither a valid xlsx, nor a valid csv
this.snackbarService.message(`File type not supported (should be .${this.settings?.exportExtension})`);
}
}
}
parseExcel() {
const sheets = [];
const workBook = new ExcelJS.Workbook();
let hasAnyData = false;
workBook.xlsx.load(this.rawFileContent)
.then((wb) => {
if (wb.worksheets.length) {
wb.eachSheet((worksheet, sheetId) => {
const newSheet = ExcelImportComponent.parseWorksheet(worksheet);
hasAnyData = hasAnyData || newSheet.sheetData.length > 0;
sheets.push(newSheet);
});
this.emitSheets(hasAnyData, sheets);
}
else {
this.snackbarService.error('Your file does not contain any sheets');
}
})
.catch((reason) => {
this.snackbarService.error('There was an error importing your file: ' + reason);
return;
});
}
parseCsv() {
const sheet = { sheetName: 'csv import', sheetData: [] };
let dataHeaders = [];
const rows = ('' + this.rawFileContent).split('\n') || [];
for (const row of rows) {
const cells = row.split(this.settings?.getCsvDelimiter() || ',');
if (!dataHeaders.length) {
// take first row with data as headers
dataHeaders = cells;
continue;
}
const newRow = {};
for (let cellIdx = 0; cellIdx < cells.length; cellIdx++) {
newRow[dataHeaders[cellIdx]] = cells[cellIdx];
}
sheet.sheetData.push(newRow);
}
this.emitSheets(sheet.sheetData.length > 0, [sheet]);
}
emitSheets(hasAnyData, sheets) {
if (!hasAnyData) {
this.snackbarService.error('Your file does not contain any data, are you sure you uploaded the correct one?');
}
else {
this.sheetsImported.emit(sheets.sort((a, b) => a.sheetName < b.sheetName ? -1 : 1));
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelImportComponent, deps: [{ token: i1.SettingsService }, { token: i1.SnackbarService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ExcelImportComponent, selector: "spaas-excel-import", inputs: { tooltipMsg: "tooltipMsg" }, outputs: { sheetsImported: "sheetsImported" }, usesInheritance: true, ngImport: i0, template: "<label>\r\n <mat-icon [matTooltip]=\"tooltipMsg\"\r\n matTooltipPosition=\"below\"\r\n fontIcon=\"file_upload\">\r\n </mat-icon>\r\n <input type=\"file\"\r\n (change)=\"readFile($event);\">\r\n</label>\r\n", styles: ["input[type=file]{display:none}\n"], dependencies: [{ kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ExcelImportComponent, decorators: [{
type: Component,
args: [{ selector: 'spaas-excel-import', template: "<label>\r\n <mat-icon [matTooltip]=\"tooltipMsg\"\r\n matTooltipPosition=\"below\"\r\n fontIcon=\"file_upload\">\r\n </mat-icon>\r\n <input type=\"file\"\r\n (change)=\"readFile($event);\">\r\n</label>\r\n", styles: ["input[type=file]{display:none}\n"] }]
}], ctorParameters: () => [{ type: i1.SettingsService }, { type: i1.SnackbarService }], propDecorators: { tooltipMsg: [{
type: Input
}], sheetsImported: [{
type: Output
}] } });
class SpaasExcelModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasExcelModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.12", ngImport: i0, type: SpaasExcelModule, declarations: [ExcelExportComponent,
ExcelImportComponent], imports: [CommonModule,
MatIconModule,
MatTooltipModule], exports: [ExcelExportComponent,
ExcelImportComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasExcelModule, imports: [CommonModule,
MatIconModule,
MatTooltipModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SpaasExcelModule, decorators: [{
type: NgModule,
args: [{
declarations: [
ExcelExportComponent,
ExcelImportComponent,
],
exports: [
ExcelExportComponent,
ExcelImportComponent,
],
imports: [
CommonModule,
MatIconModule,
MatTooltipModule,
],
providers: []
}]
}] });
class ExcelSheetModel {
constructor() {
this.sheetName = '';
this.sheetData = [];
}
}
// MODULE
/**
* Generated bundle index. Do not edit.
*/
export { ExcelExportComponent, ExcelImportComponent, ExcelService, ExcelSheetModel, SpaasExcelModule };
//# sourceMappingURL=ngx-gem-spaas-excel.mjs.map