2017-10-01 3 views
2

J'essayais de retourner le résultat de FileReader et j'ai trouvé l'implémentation this. Mais comme il est obsolète, je me demande comment mettre en œuvre la même chose en utilisant ES6 Promises ou Rx Observables.Angular: Retour Observable/Promesse ES6 de FileReader

Voici ci-dessous mon code de référence avec le lien mentionné précédemment et cela fonctionne comme prévu.

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(); 
    } 

} 

Dans le consommateur component

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

Ce sera génial si quelqu'un me aide à ce que je suis nouveau à la programmation asynchrone.

+0

double possible de https://stackoverflow.com/questions/46510235/how-to-convert-method-created-to-return-a-promise-with-q-library-to-use-an -es6/46510601 # 46510601 – estus

Répondre

1

Voici comment je l'ai fait, au cas où quelqu'un veut un service Angular qui lit les fichiers Excel et répond avec un observable du contenu comme JSON. J'utilise SheetJS pour lire le fichier et sortir 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 => { 
     // if success 
     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 
     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); 
     } 

     // if failed 
     fileReader.onerror = error => observer.error(error); 
    }); 
    } 

} 

De l'component, il suffit de passer l'événement à ce service comme indiqué ci-dessous et il répondra avec JSON.

this.excelReaderService.importFromExcel(ev) 
    .subscribe(response => { 
    // do something with the response 
    }); 
3

Comme il est indiqué dans similar case, afin d'éviter motif FileReader événement load devrait être promisified d'abord été reportée (anti):

let fileReader = new FileReader(); 
    const fileReaderPromise = new Promise(resolve => fileReader.onload = resolve); 

    if (xlsxflag) 
    fileReader.readAsArrayBuffer((<any>ev.target).files[0]); 
    else 
    fileReader.readAsBinaryString((<any>ev.target).files[0]); 

    return fileReaderPromise.then(e => { 
    let excelInJSON; 
    ... 
    return excelInJSON; 
    }); 

Il peut également être converti en une observable avec fromEvent:

const fileReader$ = Observable.fromEvent(fileReader, 'load') 
.map(e => ...) 
.first(); 

if (xlsxflag) 
    fileReader.readAsArrayBuffer((<any>ev.target).files[0]); 
    else 
    fileReader.readAsBinaryString((<any>ev.target).files[0]); 
    ... 

    return fileReader$; 
+0

Désolé, mais je ne comprends pas votre solution. N'y a-t-il pas quelque chose d'aussi simple que l'extrait dans ma question? Je retourne juste une «promesse» ou une «observable» que je peux abonner/consommer dans un composant où j'ai injecté le 'ExcelReaderService' ci-dessus? – karthikaruna

+0

L'extrait est censé résider dans la méthode 'importFromExcel' que vous avez publiée. Vous créez 'fileReaderPromise' et le renvoyez à partir de là. – estus