Store contents of fileReader in a variable - javascript

trying to do something that I feel like should be releatively straight forward.
I just want to read a text files content and store it in a variable.
Here is my code:
readToCSV(file) {
// console.log(file);
let cat = "";
var reader = new FileReader();
reader.onloadend = function (event) {
if (event.target.readyState == FileReader.DONE) {
var data = event.target.result;
}
console.log("data:", data)
cat = data;
};
reader.readAsText(file)
console.log("cat:",cat);
};
Ive tried just about everything, and keep getting undefined outside the function. Do i just have to nest any further processing inside the onloadend function. That seems silly.

Ok, so I found a work around and wanted to post it for anyone else who is trying to just get fileContents into a veriable (seriously, why should that be so difficult)
anyways, I ended up wrapping the reader in a promise and storing that.
Anyways, new code as follows:
async handleFileUpload(e){
console.log("e",e)
await this.setState({file:e[0]})
console.log("state: ",this.state.file)
const fileContents = await this.readToText(this.state.file)
console.log("fc:",fileContents);
//await this.readToCSV(fileContents)
}
async readToText(file) {
const temporaryFileReader = new FileReader();
return new Promise((resolve, reject) => {
temporaryFileReader.onerror = () => {
temporaryFileReader.abort();
reject(new DOMException("Problem parsing input file."));
};
temporaryFileReader.onload = () => {
resolve(temporaryFileReader.result);
};
temporaryFileReader.readAsText(file);
});
};

I just want to read a text files content and store it in a variable.
The way you're currently doing it, cat will be an empty string because of the async nature of the FileReader.
I would do it with a callback.
var cat = '';
const reader = new FileReader();
reader.readAsText(document.querySelector('input[type="file"]').files[0]);
reader.onload = () => storeResults(reader.result);
function storeResults(result) {
cat = result;
}
This way you get the job done and don't have to nest further processing directly within onloadend.
Hope that helps!

Related

How to pass image data as base64 to a global variable after the input changes as has happend in an input field in an async function case

I am very new to this concept of async ,await ,promise ..paradigms ..Please help me
I have an input field like this
I have a global variable var base64.How to fill base64 global variable with base encoded value. Inside the function in addEventListener reader.result shows base encoded value.How Can i pass it to outside global variable.I tried a lot .. as it seems to be a async function ..the behavior seems to be quiet different and seems very difficult in catching up and also I am not getting the expected result
<input type="file" id="photo" accept="image/*" required #change="UploadPhoto()" />
The change function of UploadPhoto() is ..{This i got from mozilla}
function UploadPhoto() {
const file = document.querySelector('#photo').files[0];
const reader = new FileReader();
reader.addEventListener("load", function () {
// convert image file to base64 string
console.log(reader.result);
}, false);
if (file) {
reader.readAsDataURL(file);
}
}
Also I will be greatful if you can explain me the working of reader.addEventListener and reader.readAsDataURL(file); with the case of asynchronous behavioured ..I googled a lot but couldnt find an article with detailed explaination of these two functions.
Wanting a global (in this case) is a symptom of not having the tools you need to do without it.
If you really needed a global, you could get it this way...
let b64Encoded;
function UploadPhoto() {
const file = document.querySelector('#photo').files[0];
const reader = new FileReader();
reader.addEventListener("load", function () {
// convert image file to base64 string
b64Encoded = btoa(reader.result);
}, false);
But, as you suppose, the modern way to do it is to use promises. This will make the code simpler to understand, and will prove an even better decision when you get to actually posting the encoded file...
First wrap the file reader in a promise. Here's a fine post on the subject, and here's the punchline (slightly modernized)
async function readAsDataURL(file) {
return new Promise((resolve, reject) => {
const fr = new FileReader();
fr.onerror = reject;
fr.onload = () => {
resolve(fr.result);
}
fr.readAsDataURL(file);
});
}
Use it like this:
// we don't need this anymore :-)
// let b64Encoded;
async function UploadPhoto() {
const file = document.querySelector('#photo').files[0];
const result = await readAsDataURL(file);
const b64Encoded = btoa(result); // stack var, as it should be!
// insert real (promise-based) network code here
return myNetworkLibrary.post(b64Encoded);
}
The addEventListener method on file reader is part of the old school async: It says: file reader is going to do i/o on a separate thread. It will you tell you when it's done (that's the "event" part) by calling a function you specify (that's the "listener" part), pass it a function to call (that's the "add" part).

How can I make .push work in FileReader.onload()?

I have the following code in which I'm trying to read a file using FileReader and put its contents in an array. Only after all the data has been pushed do I want to continue. Here's what I have currently:
const confirm = () => {
var reader = new FileReader();
let images = [];
reader.onload = function(e) {
images.push(e.target.result);
};
reader.readAsDataURL(formValues.images[0].file);
console.log('images base 64');
console.log(images); // this prints the empty array.
};
I want to continue on only after images have been updated with the file contents. How can I do that?
-- edit --
I want to in fact add multiple files to the array, so I tried the following.
var reader = new FileReader();
let images = [];
reader.onload = function(e) {
images.push(e.target.result);
console.log('images base 64');
console.log(images);
};
for (let i = 0; i < formValues.images.length; i++) {
reader.readAsDataURL(formValues.images[i].file);
}
But this gives the error "InvalidStateError: The object is in an invalid state."
You are trying to the result before it load. Move the console.log(images) inside onload function.
const confirm = () => {
var reader = new FileReader();
let images = [];
reader.onload = function(e) {
images.push(e.target.result);
console.log(images);
};
reader.readAsDataURL(formValues.images[0].file);
console.log('images base 64');
};
it works for me try like this , surly
this.file64=[];
reader.onloadend =(e) =>{
var result = reader.result;
console.log(result)
this.file64.push(result)
};

how to decode qr code that contains base 64 png in react js

I have been trying to decode this qr code that has json data.
In online tools its working example https://www.onlinebarcodereader.com/. It reads the data.
I am trying programmatically
here is my code
handleFileChange(event) {
const {target} = event;
const {files} = target;
if (files && files[0]) {
const reader = new FileReader();
// reader.onloadstart = () => this.setState({loading: true});
reader.onload = async event => {
this.setState({
data: event.target.result,
loading: false
});
// const img = document.getElementById('img');
console.log(event.target.result);
let result;
try {
var qr = new QrCode();
// set the callback that receives the decoded content as the tasks is async
qr.callback = function(decodedDATA){
alert(decodedDATA);
};
// event.target.result is
//data:image/png;base64,iVBORw0KGgoAAAANSU...
qr.decode(event.target.result);
} catch (err) {
console.log(err);
}
console.log(result);
};
reader.readAsDataURL(files[0]);
}
}
<input
id="img"
type="file"
accept="image/*"
onChange={this.handleFileChange}
/>
I have used this library https://www.npmjs.com/package/qrcode-reader
It has bug that cannot read data more than certain characters hence i am getting error.
I have also tried to use zxing library but i am using server side rendering getting error window is undefined. There are lot of configurations need to be done in webpack but i am not aware of those. I am looking for simple fix for this.
Can any one please help me out with the working library.
Found the solution with this library qrcode-decoder.
In my code
import QrcodeDecoder from 'qrcode-decoder';
const qr = new QrcodeDecoder();
const result = await qr.decodeFromImage(event.target.result);

Reading multiple files with FileReader and getting array of the filedatas

So I have FileList of files and I need to read them all to an array ie. [fileData1, fileData2], so that I can make a request with all the files to my backend. I'm stuck with all the async opertions and am not sure how to wait for things to finish. I need a way to detect when I can make the request to the backend. I also want to make this in a functional way of programming. Sorry if the question is unclear.
files.map((file) => {
const fr = new FileReader();
fr.readAsDataURL(file)
fr.addEventListener('load', (event) => {
// This is what I need to get to an array
const fileData = event.target.value.substr(fr.result.indexOf(',') + 1);
})
})
//Here I need to make a single post request with all the files in it
Since you added the functional-programming tag, how about a good old fashioned recursive function:
function read_files(cur_file) {
if (cur_file < files.length) {
// read the next file
const fr = new FileReader();
fr.readAsDataURL(files[cur_file]);
fr.addEventListener('load', (event) => {
// extract the file data from event here
read_files(cur_file+1);
}
}
else {
// we've read all the files
// send the request
}
}
read_files(0);

How to get the number of pages of a .PDF uploaded by user?

I have a file input, and before "uploading" i need to calculate the number of pages of that .pdf in JAVASCRIPT (eg. JQuery...)
In case you use pdf.js you may reference an example on github ('.../examples/node/getinfo.js') with following code that prints number of pages in a pdf file.
const pdfjsLib = require('pdfjs-dist');
...
pdfjsLib.getDocument(pdfPath).then(function (doc) {
var numPages = doc.numPages;
console.log('# Document Loaded');
console.log('Number of Pages: ' + numPages);
})
and a pure javascript solution:
var input = document.getElementById("files");
var reader = new FileReader();
reader.readAsBinaryString(input.files[0]);
reader.onloadend = function(){
var count = reader.result.match(/\/Type[\s]*\/Page[^s]/g).length;
console.log('Number of Pages:',count );
}
As has been stated in the other answers, something like pdf.js is be what you are looking for. I've taken a look at the API and it does include a numPages() function to return the total number of pages. It also seems to count pages for me when viewing the demo page from Mozilla.
It depends if you are able to use modern browsers and experimental technology for your solution. pdf.js is very impressive, but it is still experimental according to the github page .
If you are able to count the pages on the server after uploading, then you should look at pdftools or similar.
Something like pdftools --countpages is what you are looking for
I think the API has changed a little since Tracker1 posted an answer. I tried Tracker1's code and saw this error:
Uncaught TypeError: pdfjsLib.getDocument(...).then is not a function
A small change fixes it:
const pdfjsLib = require('pdfjs-dist');
...
pdfjsLib.getDocument(pdfPath).promise.then(function (doc) {
var numPages = doc.numPages;
console.log('# Document Loaded');
console.log('Number of Pages: ' + numPages);
}
In typescript class using Pdf-lib I use the following.
// getPAGE COUNT:
async getPageCount(formUrl: any): Promise<number>{
const LogPdfFields = [] as any[];
const formPdfBytes = await fetch(formUrl).then((res) => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(formPdfBytes);
const pageCount = pdfDoc.getPageCount();
return pageCount;
}
Call as a promise
You could also use pdf-lib.
You will need to read the file from the input field and then make use of pdf-lib to get the number of pages. The code would be like this:
import { PDFDocument } from 'pdf-lib';
...
const readFile = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
reader.readAsArrayBuffer(file);
});
}
const getNumPages =async (file) => {
const arrayBuffer = await readFile(file);
const pdf = await PDFDocument.load(arrayBuffer);
return pdf.getPages();
}
And then just get the number of pages of the attached file with:
const numPages = await getNumPages(input.files[0]);
being input the variable which stores the reference to the DOM element of the file input.

Categories