15

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

5 Answers 5

33

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.

Sign up to request clarification or add additional context in comments.

3 Comments

readThis(inputValue: any) : void { var file:File = inputValue.files[0]; var myReader:FileReader = new FileReader(); ... works as well .. i thought looks more cleaner .. great help though thanks
This works, fine, but I would like to add something. For some reason (at least in my case) this won' t work if you make all work in 'changeListener' method only. For some reason (which I don' t know) if you use 'myReader.onloadend(...)' in changeListener it will not be ever fired.
@haz111 does this readAsText() return base64 of any file ? I want to base64encode the file thats uploaded
8

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> 

Comments

1

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

Comments

1

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]) 

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.