Ron
Ron

Reputation: 2019

Passing file contents to outside variable

I'm using a FileReader and the HTML file dialog to read a file in my script. How do I pass this file's contents out of the FileReader.onload function?

function readFileData(evt) {
  var file = evt.target.files[0];
  var reader = new FileReader();

  reader.onload = function(e) {
    var contents = e.target.result;
  }
  reader.readAsText(file);
}
document.getElementById('file').addEventListener
    ('change', readFileData, false);

/* I want to access the contents here */

I tried sticking returns in the readFileData and onload functions, but I'm not sure what they return to.

Upvotes: 7

Views: 6039

Answers (7)

Fastersixth
Fastersixth

Reputation: 123

I had a similar problem in Angular 7 (typescript), and this is how I solved my problem.

What I wanted to do was to access the base64 conversion that was happening inside fileReader -> reader.onload

Then pass that parameter to another method where I could convert it to a JSON object then post it to the API seeing I want to post another parameter as well in the post. (not added in this code)

What I did first was to declare what I potentially needed to access outside the Method that.

base: any = null;
base64File: any = null;
fileToTest: any = null;

Then I converted the pdf to base64 when the upload event fired


convertToBase64 (e){

  this.fileToTest = e.target.files[0];
  var reader = new FileReader();
      reader.onload = () => { 
        this.base64File = reader.result.slice(28); 
};

reader.onerror = function (error) {
  console.log('Error: ', error);

}.bind(this.base64File);

reader.readAsDataURL(this.fileToTest);

return this.base64File;
}

Finally access the base64 file in the other method


 onSubmit() {

  console.log("base 64 file is visible", this.base64File);

    var base = 
      {
        "FileBase64": this.base64File,
        "Path": "document",
        "FileType": ".pdf"
      };

  console.log("JSON object visible", base);
  this.uploadService.base64Post(base);
}   

Everything works now, and hopefully maybe this can help someone else finding themselves with the same problem.

Using Angular 7, code is in the component file, and the post function is in the Service file. Without my comments the code is exactly like this in the component file.

Upvotes: 0

user3917831
user3917831

Reputation: 21

var contents;
function readFileData(evt) {
  var file = evt.target.files[0];
  var reader = new FileReader();

  reader.onload = function(e) {
   contents = e.target.result;
  }

 reader.readAsText(file);

 reader.onloadend=function(e) {
   console.log(contents)
 }
}  

document.getElementById('file').addEventListener('change', readFileData, false);    

Upvotes: 2

kmario23
kmario23

Reputation: 61355

I faced a similar challenge and this is what I used to solve the issue.

var contents;
function readFileData(evt) {
  var file = evt.target.files[0];
  var reader = new FileReader();

  reader.onload = function(e) {
   contents = e.target.result;
  }

 reader.readAsText(file);

 //calling to access the 'contents' variable
 accessFileContents();
}  

document.getElementById('file').addEventListener('change', readFileData, false);
var wait4file2load = 1000;

/* To access 'contents' here */
function accessFileContents(){
  setTimeout(function(){
    console.log(contents);
  }, wait4file2load);
}

It won't give undefined value since we are calling it after the file is completely uploaded.

Upvotes: 0

NPE
NPE

Reputation: 500357

Just declare contents outside both functions and assign to it inside the inner function:

var contents;
var outer_fn = function() {
  var inner_fn = function() {
    contents = '42';
  }
  inner_fn();
}
outer_fn();
// here, `contents' is '42'

Upvotes: 0

Martin Jespersen
Martin Jespersen

Reputation: 26183

Firstly, you have to realize that reading a file with a FileReader is an asynchronous task, and you cannot work with it in a synchronous manner.

There are many ways to handle this, but many of them are not suited for recommendations ;)

I would do it one of these 2 ways:

1: you can call a function from within the onload event handler and pass the file contents as a parameter

2: you can trigger an event from within the onload event handler and pass the file contents as event data

Upvotes: 0

Justice Erolin
Justice Erolin

Reputation: 2879

This is a scoping issue. When you're declaring contents within the onload, it's no longer available after that function has run. You need to declare contents outside of that scope first.

var contents;
function readFileData(evt) {
  var file = evt.target.files[0];
  var reader = new FileReader();

  reader.onload = function(e) {
   contents = e.target.result;
  }
  reader.readAsText(file);
}
document.getElementById('file').addEventListener
    ('change', readFileData, false);

//make changes here
//contents should have the correct value

Upvotes: 0

user405398
user405398

Reputation:

I assume that you know, its async and all.

So, the short answer is: No, you can not do that.

However, if you want the contents to be globally accessible for any future calls, you could something like this:-

var contents;// declared `contents` outside
function readFileData(evt) {
  var file = evt.target.files[0];
  var reader = new FileReader();

  reader.onload = function(e) {
    contents = e.target.result; //<-- I removed the `var` keyword
  }
  reader.readAsText(file);
}

document.getElementById('file').addEventListener('change', readFileData, false);

var reasonableTimeToWaitForFileToLoad = 100000;

console.log(contents); //`contents` access first attempt: prints undefined



setTimeout(function() {
  console.log(contents);//`contents` access second attempt: prints the contents 'may be if the time allows.'
}, reasonableTimeToWaitForFileToLoad);

Upvotes: 3

Related Questions