Angular: Return Observable / ES6 Promise from FileReader

karthikaruna

I was trying to return result from FileReader and I found this implementation. But since it is outdated, I'm wondering how to implement the same using ES6 Promises or Rx Observables.

Below is my code with reference to the aforementioned link and it works as expected.

import { Injectable } from '@angular/core';
import * as XLSX from 'xlsx';
import * as XLS from 'xlsx';

@Injectable()
export class ExcelReaderService {

  constructor() { }

  importFromExcel(ev): JQueryPromise<any> {
    let deferred = $.Deferred();

    let regex = /^([a-zA-Z0-9\s_\\.\-:])+(.xlsx|.xls)$/;

    let workbook;
    let excelInJSON;

    if (regex.test(ev.target.files[0].name.toString().toLowerCase())) {
      let xlsxflag = false; /*Flag for checking whether excel is .xls format or .xlsx format*/
      if (ev.target.files[0].name.toString().toLowerCase().indexOf(".xlsx") > 0) {
        xlsxflag = true;
      }

      let fileReader = new FileReader();

      fileReader.onload = (ev) => {
        let binary = "";
        let bytes = new Uint8Array((<any>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*/
        if (xlsxflag) {
          workbook = XLSX.read(binary, { type: 'binary', cellDates: true, cellStyles: true });
          // only first sheet
          excelInJSON = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
          deferred.resolve(excelInJSON);
        }
        else {
          workbook = XLS.read(binary, { type: 'binary', cellDates: true, cellStyles: true });
          excelInJSON = <{}[]>XLS.utils.sheet_to_row_object_array(workbook.Sheets[workbook.SheetNames[0]]);
          deferred.resolve(excelInJSON);
        }
      }

      // init read
      if (xlsxflag)
        fileReader.readAsArrayBuffer((<any>ev.target).files[0]);
      else
        fileReader.readAsBinaryString((<any>ev.target).files[0]);
    } else {
      deferred.reject('Invalid file!');
    }
    return deferred.promise();
  }

}

In the consumer component

this.excelReaderService.importFromExcel(ev).then((result) => {
    this.detailHeadings = Object.keys(result[0]);
    this.detailData = result;
})

It'll be great if someone helps me with this as I'm new to asynchronous programming.

karthikaruna

This is how I did it, in case anyone wants an Angular service that reads Excel files and responds with an observable of the content as JSON.

I'm using SheetJS for reading the file and outputting JSON.

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import * as XLSX from 'xlsx';

@Injectable()
export class ExcelReaderService {

  constructor() { }

  importFromExcel(ev): Observable<any> {
    let workbook;
    let excelInJSON;

    const fileReader = new FileReader();

    // init read
    fileReader.readAsArrayBuffer((<any>ev.target).files[0]);

    return Observable.create((observer: Subscriber<any[]>): void => {
      // if success
      fileReader.onload = ((ev: ProgressEvent): void => {
        let binary = "";
        let bytes = new Uint8Array((<any>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);
      }
    });
  }

}

From the component, just pass the event to this service as shown below and it will respond with the JSON.

this.excelReaderService.importFromExcel(ev)
  .subscribe((response: any[]): void => {
    // do something with the response
  });

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Return a Promise from Redux Observable

Angular 6 - Expected validator to return Promise or Observable in async validator

Angular 6 return Observable

Return Observable From Promise That Gets Rejected

Return Resolved Observable from Inside of a Promise

how to return observable from function that has a promise

Angular 9 return Observable from an Observable

Angular - How to return an observable from another observable

Return observable from observable in angular 2

Angular return observable from eventListener

return observable from angular service

Angular Return Observable from subscription

Return value from a promise in Angular

Return promise from Angular service

How can I use promise.all to return after multiple if statements in ES6/Typescript/Angular?

How to convert from observable to promise in angular

Angular AuthGuard canActivate with observable from promise not working

Keep Checking: Angular Observable from Promise

How to convert method created to return a promise with $q library to use an ES6 Promise. Angularjs app to Angular4+

Transform pipe in Angular 6 with Observable or Promise

Return Observable inside the Promise

Angular 2 Firebase Observable to promise doesn't return anything

Angular Custom Validator Error (Expected validator to return Promise or Observable)

How to return a default value in an AsyncPipe in Angular/Ionic Observable/Promise

How to return an Observable from a sample data [Angular]

Angular 2 - Return data directly from an Observable

Angular 8 return Observable<boolean> from function

How to return object from Observable in Angular 7

How to properly return a promise from an angular service?