Saltar al contenido

Angular: Return Observable / ES6 Promise de FileReader

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 componentsimplemente 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 FileReaderload 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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *