ngx-excel-viewer
Version:
Ngx-excel-viewer is an angular library to view/edit excel data in the angular application where data is in the form of matrix of string.
257 lines (250 loc) • 22.1 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Component, Input, Output, HostListener, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
class NgxExcelViewerService {
constructor() { }
}
NgxExcelViewerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
NgxExcelViewerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return []; } });
class NgxExcelViewerComponent {
constructor() {
this.id = "";
this.sheetNames = [];
this.editable = false;
this.events = null;
this.saveDataOutput = "complete";
this.onDataSave = new EventEmitter();
this.onScrollEnd = new EventEmitter();
this.currentSheetName = "";
this.maxOfColumns = 0;
this.selectedCellIndices = [-1, -1];
this.isEditingTheSelectedCell = false;
this.headers = [];
this.sheetData = [];
this.isSheetDataChanged = false;
this.backupSheetData = [];
this.modifiedRows = [];
this.renderedPages = 1;
this.lastScrollTop = 0;
this.loading = false;
}
ngOnInit() {
if (this.data != null) {
this.currentSheetName = this.sheetNames[0];
if (this.data[this.currentSheetName]) {
this.run();
}
}
if (this.events != null) {
this.events.subscribe(event => {
if (event.id == this.id) {
if (event.type == "cancel") {
this.sheetData = JSON.parse(JSON.stringify(this.backupSheetData));
this.isSheetDataChanged = false;
this.modifiedRows = [];
}
else if (event.type == "save") {
if (this.saveDataOutput == "complete") {
this.onDataSave.emit({ id: this.id, sheet: this.currentSheetName, data: this.sheetData.map((row) => row['value']) });
return;
}
let payload = {};
for (let rowIndex of this.modifiedRows) {
payload[`${rowIndex + 1}`] = this.sheetData[rowIndex].map((row) => row['value']);
}
this.onDataSave.emit({ id: this.id, sheet: this.currentSheetName, data: payload });
}
else if (event.type == "saved") {
for (let rowIndex of this.modifiedRows) {
this.data[rowIndex] = this.sheetData[rowIndex].map((row) => row['value']);
this.backupSheetData[rowIndex] = this.sheetData[rowIndex];
}
}
else if (event.type == "new_data") {
this.run();
}
}
});
}
}
run() {
this.loading = true;
setTimeout(() => {
this.calculateMaxColumns();
this.generateHeaders();
this.generateSheetData();
setTimeout(() => {
this.loading = false;
}, 100);
}, 100);
}
ngOnChanges(changes) {
if (changes['data'] && changes['data'].previousValue != changes['data'].currentValue) {
this.run();
}
}
calculateMaxColumns() {
this.maxOfColumns = 0;
if (this.data[this.currentSheetName]) {
for (let row of this.data[this.currentSheetName]) {
if (row.length > this.maxOfColumns) {
this.maxOfColumns = row.length;
}
}
}
}
generateHeaders() {
let headers = [];
for (let i = 0; i < this.maxOfColumns; i++) {
let header = "";
let num = i;
while (num >= 0) {
let remainder = num % 26;
header = String.fromCharCode(65 + remainder) + header;
num = Math.floor(num / 26) - 1;
}
headers.push(header);
}
this.headers = headers;
}
generateSheetData() {
if (this.data[this.currentSheetName]) {
this.sheetData = JSON.parse(JSON.stringify(this.data[this.currentSheetName].map((row) => row.map((r) => ({ "value": r })))));
this.backupSheetData = JSON.parse(JSON.stringify(this.sheetData));
}
else {
this.sheetData = [];
this.backupSheetData = [];
}
}
setSelectedSheetName(sheet) {
if (this.isSheetDataChanged) {
alert("Save sheet before switching");
return;
}
this.currentSheetName = sheet;
this.run();
}
selectCell(i, j) {
if ((this.selectedCellIndices[0] == i && this.selectedCellIndices[1] == j) || (i > this.sheetData.length - 1 || j > this.maxOfColumns - 1)) {
document.querySelector(`#input-${this.selectedCellIndices[0]}-${this.selectedCellIndices[1]}`).focus();
return;
}
i = i >= 0 ? i : 0;
j = j >= 0 ? j : 0;
this.selectedCellIndices = [i, j];
document.querySelector(`#input-${i}-${j}`).focus();
}
onDataChanges(event, i, j) {
if (!this.editable)
return;
if (this.backupSheetData[i][j]["value"] != event.target.innerText) {
this.sheetData[i][j]["value"] = event.target.innerText;
if (!this.modifiedRows.includes(i)) {
this.modifiedRows.push(i);
}
if (!this.isSheetDataChanged) {
this.isSheetDataChanged = true;
}
}
}
onKeyPress(event) {
if (event.which == 13) {
event.preventDefault();
}
}
onScroll(event) {
if (event.target.scrollTop > this.lastScrollTop) {
if ((event.target.offsetHeight + event.target.scrollTop) >= event.target.scrollHeight) {
this.onScrollEnd.emit({ id: this.id, pageNo: this.renderedPages++, sheet: this.currentSheetName });
}
}
this.lastScrollTop = event.target.scrollTop;
}
onKeyDown(event) {
var _a, _b, _c, _d;
if ((_a = event.key) === null || _a === void 0 ? void 0 : _a.includes("Arrow")) {
const key = event.key;
let i = this.selectedCellIndices[0];
let j = this.selectedCellIndices[1];
event.target.blur();
if (key == "ArrowUp") {
i--;
}
else if (key == "ArrowDown") {
i++;
}
else if (key == "ArrowLeft") {
if (((_b = window.getSelection()) === null || _b === void 0 ? void 0 : _b.anchorOffset) == 0)
j--;
}
else if (key == "ArrowRight") {
if (((_d = (_c = window.getSelection()) === null || _c === void 0 ? void 0 : _c.anchorOffset) !== null && _d !== void 0 ? _d : 0) >= event.target.innerText.length)
j++;
}
this.selectCell(i, j);
}
}
}
NgxExcelViewerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
NgxExcelViewerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.8", type: NgxExcelViewerComponent, selector: "ngx-excel-viewer", inputs: { id: "id", data: "data", sheetNames: "sheetNames", editable: "editable", events: "events", saveDataOutput: "saveDataOutput" }, outputs: { onDataSave: "onDataSave", onScrollEnd: "onScrollEnd" }, host: { listeners: { "keypress": "onKeyPress($event)", "keydown": "onKeyDown($event)" } }, usesOnChanges: true, ngImport: i0, template: "<div class=\"excel-file\">\r\n <div class=\"scrollable\" (scroll)=\"onScroll($event)\">\r\n <table *ngIf=\"sheetData.length != 0\">\r\n <thead>\r\n <tr>\r\n <th class=\"header s-no\"></th>\r\n <th class=\"header\" *ngFor=\"let header of headers\">{{header}}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <ng-container *ngIf=\"currentSheetName && data\">\r\n <tr *ngFor=\"let data of sheetData; let i=index\">\r\n <td class=\"s-no\">{{i+1}}</td>\r\n <td *ngFor=\"let cell of data; let j=index\"\r\n [ngClass]=\"{'main-selected': selectedCellIndices[0] == i && selectedCellIndices[1] == j}\"\r\n (click)=\"selectCell(i,j)\">\r\n <div [id]=\"'input-'+i+'-'+j\" (blur)=\"onDataChanges($event, i, j)\" (focus)=\"selectCell(i,j)\"\r\n [contentEditable]=\"editable\" [innerHTML]=\"cell['value']\"></div>\r\n </td>\r\n </tr>\r\n </ng-container>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"empty-data\" *ngIf=\"sheetData.length == 0\">\r\n Empty Sheet\r\n </div>\r\n <div class=\"footer\">\r\n Sheets: <div *ngFor=\"let sheet of sheetNames\" class=\"sheet\" [ngClass]=\"{'active': currentSheetName == sheet}\"\r\n (click)=\"setSelectedSheetName(sheet)\">{{sheet}}</div>\r\n </div>\r\n <div class=\"loading\" *ngIf=\"loading\">\r\n <div class=\"spinner\">\r\n <div class=\"lds-spinner\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: ["*{margin:0;padding:0}.excel-file{border:1px solid lightgrey;width:100%;min-height:20vh;height:100%;border-radius:5px;position:relative;font-family:sans-serif;-webkit-user-select:none;user-select:none;overflow:hidden}.excel-file .loading{position:absolute;inset:0;background-color:#0003;z-index:5}.excel-file .loading .spinner{position:absolute;top:50%;left:47%;transform:translate(-50%,-50%) scale(.7)}.excel-file .scrollable{width:100%;height:calc(100% - 50px);overflow:auto}.excel-file td,.excel-file th{padding:0;white-space:nowrap}.excel-file .s-no{min-width:25px;background-color:#efefef;position:sticky;left:-1.5px;text-align:center;z-index:1}.excel-file table{table-layout:fixed}.excel-file .main-selected{background-color:#87ceeb33;border:2px solid skyblue}.excel-file td div{outline:none;border:none;width:auto;padding:5px;background-color:transparent;min-height:10px}.excel-file table,.excel-file td,.excel-file th{border:1.5px solid #d9d9d9;border-collapse:collapse}.excel-file table .header,.excel-file td .header,.excel-file th .header{background-color:#efefef;position:sticky;top:-1.5px;z-index:2;padding:2px}.excel-file .empty-data{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.excel-file .footer{position:absolute;bottom:0;left:0;right:0;min-height:30px;z-index:5;padding:5px;background-color:#efefef;border-top:1.5px solid lightgray;overflow-x:auto;display:flex;align-items:center}.excel-file .footer .sheet{display:inline-block;position:relative;padding:5px;margin:5px 2px;border-radius:3px;cursor:pointer;transition:all .3s ease;white-space:nowrap}.excel-file .footer .sheet.active,.excel-file .footer .sheet:hover{margin:5px;background-color:#fff;box-shadow:0 0 5px #0003}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#f1f1f1}::-webkit-scrollbar-thumb{background:#888;border-radius:5px}::-webkit-scrollbar-thumb:hover{background:#555}.lds-spinner{color:official;display:inline-block;position:relative;width:80px;height:80px}.lds-spinner div{transform-origin:40px 40px;animation:lds-spinner 1.2s linear infinite}.lds-spinner div:after{content:\" \";display:block;position:absolute;top:3px;left:37px;width:6px;height:18px;border-radius:20%;background:#fff}.lds-spinner div:nth-child(1){transform:rotate(0);animation-delay:-1.1s}.lds-spinner div:nth-child(2){transform:rotate(30deg);animation-delay:-1s}.lds-spinner div:nth-child(3){transform:rotate(60deg);animation-delay:-.9s}.lds-spinner div:nth-child(4){transform:rotate(90deg);animation-delay:-.8s}.lds-spinner div:nth-child(5){transform:rotate(120deg);animation-delay:-.7s}.lds-spinner div:nth-child(6){transform:rotate(150deg);animation-delay:-.6s}.lds-spinner div:nth-child(7){transform:rotate(180deg);animation-delay:-.5s}.lds-spinner div:nth-child(8){transform:rotate(210deg);animation-delay:-.4s}.lds-spinner div:nth-child(9){transform:rotate(240deg);animation-delay:-.3s}.lds-spinner div:nth-child(10){transform:rotate(270deg);animation-delay:-.2s}.lds-spinner div:nth-child(11){transform:rotate(300deg);animation-delay:-.1s}.lds-spinner div:nth-child(12){transform:rotate(330deg);animation-delay:0s}@keyframes lds-spinner{0%{opacity:1}to{opacity:0}}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-excel-viewer', template: "<div class=\"excel-file\">\r\n <div class=\"scrollable\" (scroll)=\"onScroll($event)\">\r\n <table *ngIf=\"sheetData.length != 0\">\r\n <thead>\r\n <tr>\r\n <th class=\"header s-no\"></th>\r\n <th class=\"header\" *ngFor=\"let header of headers\">{{header}}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <ng-container *ngIf=\"currentSheetName && data\">\r\n <tr *ngFor=\"let data of sheetData; let i=index\">\r\n <td class=\"s-no\">{{i+1}}</td>\r\n <td *ngFor=\"let cell of data; let j=index\"\r\n [ngClass]=\"{'main-selected': selectedCellIndices[0] == i && selectedCellIndices[1] == j}\"\r\n (click)=\"selectCell(i,j)\">\r\n <div [id]=\"'input-'+i+'-'+j\" (blur)=\"onDataChanges($event, i, j)\" (focus)=\"selectCell(i,j)\"\r\n [contentEditable]=\"editable\" [innerHTML]=\"cell['value']\"></div>\r\n </td>\r\n </tr>\r\n </ng-container>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"empty-data\" *ngIf=\"sheetData.length == 0\">\r\n Empty Sheet\r\n </div>\r\n <div class=\"footer\">\r\n Sheets: <div *ngFor=\"let sheet of sheetNames\" class=\"sheet\" [ngClass]=\"{'active': currentSheetName == sheet}\"\r\n (click)=\"setSelectedSheetName(sheet)\">{{sheet}}</div>\r\n </div>\r\n <div class=\"loading\" *ngIf=\"loading\">\r\n <div class=\"spinner\">\r\n <div class=\"lds-spinner\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", styles: ["*{margin:0;padding:0}.excel-file{border:1px solid lightgrey;width:100%;min-height:20vh;height:100%;border-radius:5px;position:relative;font-family:sans-serif;-webkit-user-select:none;user-select:none;overflow:hidden}.excel-file .loading{position:absolute;inset:0;background-color:#0003;z-index:5}.excel-file .loading .spinner{position:absolute;top:50%;left:47%;transform:translate(-50%,-50%) scale(.7)}.excel-file .scrollable{width:100%;height:calc(100% - 50px);overflow:auto}.excel-file td,.excel-file th{padding:0;white-space:nowrap}.excel-file .s-no{min-width:25px;background-color:#efefef;position:sticky;left:-1.5px;text-align:center;z-index:1}.excel-file table{table-layout:fixed}.excel-file .main-selected{background-color:#87ceeb33;border:2px solid skyblue}.excel-file td div{outline:none;border:none;width:auto;padding:5px;background-color:transparent;min-height:10px}.excel-file table,.excel-file td,.excel-file th{border:1.5px solid #d9d9d9;border-collapse:collapse}.excel-file table .header,.excel-file td .header,.excel-file th .header{background-color:#efefef;position:sticky;top:-1.5px;z-index:2;padding:2px}.excel-file .empty-data{width:100%;height:100%;display:flex;justify-content:center;align-items:center}.excel-file .footer{position:absolute;bottom:0;left:0;right:0;min-height:30px;z-index:5;padding:5px;background-color:#efefef;border-top:1.5px solid lightgray;overflow-x:auto;display:flex;align-items:center}.excel-file .footer .sheet{display:inline-block;position:relative;padding:5px;margin:5px 2px;border-radius:3px;cursor:pointer;transition:all .3s ease;white-space:nowrap}.excel-file .footer .sheet.active,.excel-file .footer .sheet:hover{margin:5px;background-color:#fff;box-shadow:0 0 5px #0003}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#f1f1f1}::-webkit-scrollbar-thumb{background:#888;border-radius:5px}::-webkit-scrollbar-thumb:hover{background:#555}.lds-spinner{color:official;display:inline-block;position:relative;width:80px;height:80px}.lds-spinner div{transform-origin:40px 40px;animation:lds-spinner 1.2s linear infinite}.lds-spinner div:after{content:\" \";display:block;position:absolute;top:3px;left:37px;width:6px;height:18px;border-radius:20%;background:#fff}.lds-spinner div:nth-child(1){transform:rotate(0);animation-delay:-1.1s}.lds-spinner div:nth-child(2){transform:rotate(30deg);animation-delay:-1s}.lds-spinner div:nth-child(3){transform:rotate(60deg);animation-delay:-.9s}.lds-spinner div:nth-child(4){transform:rotate(90deg);animation-delay:-.8s}.lds-spinner div:nth-child(5){transform:rotate(120deg);animation-delay:-.7s}.lds-spinner div:nth-child(6){transform:rotate(150deg);animation-delay:-.6s}.lds-spinner div:nth-child(7){transform:rotate(180deg);animation-delay:-.5s}.lds-spinner div:nth-child(8){transform:rotate(210deg);animation-delay:-.4s}.lds-spinner div:nth-child(9){transform:rotate(240deg);animation-delay:-.3s}.lds-spinner div:nth-child(10){transform:rotate(270deg);animation-delay:-.2s}.lds-spinner div:nth-child(11){transform:rotate(300deg);animation-delay:-.1s}.lds-spinner div:nth-child(12){transform:rotate(330deg);animation-delay:0s}@keyframes lds-spinner{0%{opacity:1}to{opacity:0}}\n"] }]
}], ctorParameters: function () { return []; }, propDecorators: { id: [{
type: Input
}], data: [{
type: Input
}], sheetNames: [{
type: Input
}], editable: [{
type: Input
}], events: [{
type: Input
}], saveDataOutput: [{
type: Input
}], onDataSave: [{
type: Output
}], onScrollEnd: [{
type: Output
}], onKeyPress: [{
type: HostListener,
args: ['keypress', ['$event']]
}], onKeyDown: [{
type: HostListener,
args: ['keydown', ['$event']]
}] } });
class NgxExcelViewerModule {
}
NgxExcelViewerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
NgxExcelViewerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerModule, declarations: [NgxExcelViewerComponent], imports: [CommonModule], exports: [NgxExcelViewerComponent] });
NgxExcelViewerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerModule, imports: [CommonModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.8", ngImport: i0, type: NgxExcelViewerModule, decorators: [{
type: NgModule,
args: [{
declarations: [
NgxExcelViewerComponent,
],
imports: [
CommonModule,
],
exports: [
NgxExcelViewerComponent
]
}]
}] });
/*
* Public API Surface of ngx-excel-viewer
*/
/**
* Generated bundle index. Do not edit.
*/
export { NgxExcelViewerComponent, NgxExcelViewerModule, NgxExcelViewerService };
//# sourceMappingURL=ngx-excel-viewer.mjs.map