Hemos estado indagando por el mundo online para así traerte la solución a tu dilema, en caso de alguna inquietud deja tu comentario y te responderemos porque estamos para servirte.
Solución:
Así lo hice yo, por si alguien quiere un servicio de Angular que lea archivos de Excel y responda con un observable
del contenido como JSON
.
Estoy usando SheetJS para leer el archivo y generar JSON
.
import Injectable from '@angular/core';
import Observable from 'rxjs/Observable';
import * as XLSX from 'xlsx';
@Injectable()
export class ExcelReaderService
constructor()
importFromExcel(ev): Observable
let workbook;
let excelInJSON;
const fileReader = new FileReader();
// init read
fileReader.readAsArrayBuffer((ev.target).files[0]);
return Observable.create((observer: Subscriber): void =>
// if success
fileReader.onload = ((ev: ProgressEvent): void =>
let binary = "";
let bytes = new Uint8Array((ev.target).result);
let length = bytes.byteLength;
for (let i = 0; i < length; i++)
binary += String.fromCharCode(bytes[i]);
// Converts the excel data in to json
workbook = XLSX.read(binary, type: 'binary', cellDates: true, cellStyles: true );
// only first sheet
excelInJSON = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
observer.next(excelInJSON);
observer.complete();
// if failed
fileReader.onerror = (error: FileReaderProgressEvent): void =>
observer.error(error);
);
Desde el component
simplemente pase el evento a este servicio como se muestra a continuación y responderá con el JSON.
this.excelReaderService.importFromExcel(ev)
.subscribe((response: any[]): void =>
// do something with the response
);
Como se muestra en un caso similar, para evitar un (anti) patrón diferido FileReader
load
El evento debe ser prometido primero:
let fileReader = new FileReader();
const fileReaderPromise = new Promise(resolve => fileReader.onload = resolve);
if (xlsxflag)
fileReader.readAsArrayBuffer((ev.target).files[0]);
else
fileReader.readAsBinaryString((ev.target).files[0]);
return fileReaderPromise.then(e =>
let excelInJSON;
...
return excelInJSON;
);
También se puede convertir en un observable con fromEvent
:
const fileReader$ = Observable.fromEvent(fileReader, 'load')
.map(e => ...)
.first();
if (xlsxflag)
fileReader.readAsArrayBuffer((ev.target).files[0]);
else
fileReader.readAsBinaryString((ev.target).files[0]);
...
return fileReader$;
Mejorando la respuesta anterior de @karthikaruna, agregaría con Observables, es fácil hacer un .pipe
cadena devuelve lo que quieras de un File
objeto:
(Tenga en cuenta que estos tipos pueden no ser 100% correctos).
import Injectable from '@angular/core';
import Observable, Subscriber from 'rxjs';
import map from 'rxjs/operators';
import * as XLSX from 'xlsx';
@Injectable()
export class ExcelReaderService
public importFromExcel(ev): Observable
return this.fileToString(ev.target.files[0])
.pipe(
// convert from file contents to Excel rows
map((binary: string): any[] =>
// Converts the excel data in to json
const workbook = XLSX.read(binary, type: 'binary', cellDates: true, cellStyles: true );
// only first sheet
const excelInJSON = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
return excelInJSON;
),
);
// end importFromExcel()
private fileToString(file: File): Observable
return Observable.create(
(sub: Subscriber): void =>
const r = new FileReader;
// if success
r.onload = (ev: ProgressEvent): void =>
sub.next((ev.target as any).result);
;
// if failed
r.onerror = (ev: FileReaderProgressEvent): void =>
sub.error(ev);
;
r.readAsText(file);
);
// end fileToString()
Calificaciones y comentarios
Acuérdate de que puedes comentar si te fue de ayuda.