简体   繁体   中英

How to make FileReader work with Angular2?

How to make FileReader work with Angular2 !!

When reading a file from client side with Angular2 and Typescript,

I try to use FileReader in this way:

var fileReader = new FileReader();
fileReader.onload = function(e) {
    console.log("run fileReader.onload");
   //  ......
}

But it doesn't work at all, this 'fileReader.onload' function will never be called.

Really need a solution for reading files, please help. Thanks

Check this from an online IDE:

preview: https://angular2-butaixianran.c9.io/src/index.html

editor: https://ide.c9.io/butaixianran/angular2

First you have to specify the target of the change event on input form in template:

@View({
  template:`
    <div>
      Select file:
      <input type="file" (change)="changeListener($event)">
    </div>
  `
})

As you can see I binded a changeListener() method to (change) event. My implementation of class:

  changeListener($event) : void {
    this.readThis($event.target);
  }

  readThis(inputValue: any) : void {
    var file:File = inputValue.files[0]; 
    var myReader:FileReader = new FileReader();

    myReader.onloadend = function(e){
      // you can perform an action with readed data here
      console.log(myReader.result);
    }

    myReader.readAsText(file);
  }

Listener is passing file from event to readThis method. Read this have implemented it's own FileReader . You can also define FileReader in component instead in function.

answer from @haz111 already works, but just in case you want to make file reader a reusable component , you could possibly use this or better: improve on this:

inputfilereader.ts

import {Component, ElementRef, EventEmitter} from 'angular2/angular2';

@Component({
    selector: 'filereader',
    templateUrl: './commons/inputfilereader/filereader.html',
    styleUrls: ['./commons/inputfilereader/filereader.css'],
    providers: [ElementRef],
    events : ['complete']
})

export class InputFileReader {
    complete :EventEmitter = new EventEmitter();

    constructor(public elementRef: ElementRef) {
    }

    resultSet:any; // dont need it 

    changeListener($event: any) {
        var self = this;
        var file:File = $event.target.files[0];
        var myReader:FileReader = new FileReader();
        myReader.readAsText(file);
        var resultSet = [];
        myReader.onloadend = function(e){
            // you can perform an action with data read here
            // as an example i am just splitting strings by spaces
            var columns = myReader.result.split(/\r\n|\r|\n/g);

            for (var i = 0; i < columns.length; i++) {
                resultSet.push(columns[i].split(' '));
            }

            self.resultSet=resultSet; // probably dont need to do this atall
            self.complete.next(self.resultSet); // pass along the data which would be used by the parent component
        };
    }
}

filereader.html

<input type="file" (change)="changeListener($event)" />

Usage in other files

anotherfile lets say dfs.ts

import {Component, ElementRef} from 'angular2/angular2';
import {InputFileReader} from '../../commons/inputfilereader/inputfilereader';

@Component({
    selector: 'dfs',
    templateUrl: './components/dfs/dfs.html',
    styleUrls: ['./components/dfs/dfs.css'],
    providers: [ElementRef],
    directives:[InputFileReader]
})

export class DfsCmp {
    constructor(public eleRef :ElementRef) {}

    callSomeFunc(data):void {
        console.log("I am being called with ", data);
    }
}

dfs.html

<filereader (complete)="callSomeFunc($event)"></filereader> 

Just add

fr.readAsText(event.files[0]);

After the onLoad definition.

Maybe this can help you, this is my upload handler function for the file upload library of primeng

archivoUploadHandler(event) {
  let contenido;
  let fr = new FileReader();
  fr.onload = (e) => {
    contenido = fr.result;
    console.log(contenido);
  };
  fr.readAsText(event.files[0]);
}

a little late to the party here. This can also be done creating the FileReader as service. This would help the unit tests and will decouple the FileReader from the component that is using it.

you can create the token like this:

export const FileReaderService = new InjectionToken<FileReader>('FileReader', {
  factory: () => new FileReader(),
});

And then you can use it as like this: (I believe it could be used as a regular service. I haven't tested it yet. But the way I am showing here works just fine)

class MyService { // this could be a component too
  constructor(@Inject(FileReaderService) private reader: FileReader) {}
  readFile() {
    const file = // the file you want to read
    this.reader.onload = // whateever you need
    this.reader.readAsDataURL(file)
  }
}

I would create a method like below

readFileContent(file: File): Promise<string | ArrayBuffer> {
    return new Promise<string | ArrayBuffer>((resolve, reject) => {

      const myReader: FileReader = new FileReader();

      myReader.onloadend = (e) => {
        resolve(myReader.result);
      };

      myReader.onerror = (e) => {
        reject(e);
      };

      myReader.readAsText(file);
    });
  }

and call it like

const content = await this.readFileContent(inputValue.files[0])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM