Javascript Read File + Convert to Base64 Waiting For Result Undefined - javascript

I need to convert an uploaded file into a base64, and pass it to a Web Api as a parameter.
In the examples if i write to console the reader.result it write the correct base64 result, but if i return it as a return var, i obtain an Undefined.
So i can't retrieve the result from this function, because i have to pass it to the ajax call.
How can i wait for the completation of the encoding, and get the result?
Thank u all
function getBase64(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
return (reader.result);
};
reader.onerror = function (error) {
return ('Error: ', error);
};
}
$(document).ready(function () {
var base64File;
var files = document.getElementById('file').files; // uploaded file
if (files.length > 0) {
base64File = getBase64(files[0]);
}
console.log(base64File) // undefined
});

The getBase64 function returns only a console log, shouldn't it return reader.result?

Related

HTML 5 Filereader Not returning Base64 URL Onloadend

I am using the following script for reading image data as base64 url.
function getBase64(incomingfile) {
var reader = new FileReader;
reader.readAsDataURL(incomingfile);
reader.onloadend = ()=>{
console.log(reader.result);
}
}
This is working fine and printing the result on console. But when I try to apply this below code
function getBase64(incomingfile) {
var reader = new FileReader;
reader.readAsDataURL(incomingfile);
reader.onloadend = ()=>{
return reader.result;
}
}
I am not getting the result of this function after calling. What should I do to get return value of Filereader.
the file The FileReader methods work asynchronously but don't return a Promise so when attempting to retrieve the result immediately after calling a method will not work
try this
let logBase64 = "";
function getBase64(incomingfile) {
var reader = new FileReader();
reader.readAsDataURL(incomingfile);
return new Promise((resolve, reject) => {
reader.onloadend = () => {
resolve(reader.result);
};
}).then((result) => {
logBase64 = result;
console.log(logBase64);
});
}

uploading files in js

i'm using below method to upload files to laravel backend
setFile(id, e) {
let self = this;
let reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onload = function () {
console.log(reader.result);
self.documentArray.forEach(function (element) {
if (id == element.id && reader.result) {
element.file = reader.result;
element.file_browse_name = e.target.files[0].name;
}
});
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
},
but when i select a file larger than 5mb or around, it doesn't add the element to the relevant object of the documentArray but it logs the result in console, so i cant add validation on backend. please give me a way to solve this problem
Maybe the problem is with your PHP settings. Check your upload_max_filesize and your post_max_size

Javascript Downloading and reading file contents from Dropbox

I am trying to download a file I uploaded as test to Dropbox. The download function works and I am getting the fileblob as well but having trouble to actually read the file contents
function downloadFile() {
dbx.filesDownload({path: '/_bk_test/test3.json'})
.then(function(response) {
var blob = response.fileBlob;
var reader = new FileReader();
reader.addEventListener("loadend", function() {
console.log(reader.result); // will print out file content
});
reader.readAsText(blob);
})
.catch(function(error) {
console.error(error);
});
}
But I am getting this error as output
Promise {<pending>}
VM215:11 TypeError: reader.addEventListener is not a function
at <anonymous>:5:24
This is strange.
But if I store the response.fileBlob in a global variable and then use the reader function, it wont show the TypeError. But I still cant read the file contents.
Either way, these are the issues
1. In a function the FileReader is throwing an exception.
2. Outside the function, the FileReader is not showing the file contents.
PS - Testing in Cordova
Alright, Cordova has a different API
function downloadFile() {
dbx.filesDownload({path: '/_bk_test/test3.json'})
.then(function(response) {
var blob = response.fileBlob;
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("read success");
console.log(evt.target.result);
};
reader.readAsText(blob);
})
.catch(function(error) {
console.error(error);
});
}

JS convert PDF to base64 in local path

my project have this foldes:
-html
index.html
-css
-js
my.js
-pdf
test.pdf
I need to convert this "test.pdf" to base 64 and send by POST
I try use a function like this:
function getBase64() {
var reader = new FileReader();
var file = new File("/pdf/test.pdf","r");
reader.addEventListener("loadend", function() {
// reader.result contains the contents of blob as a typed array
reader.readAsDataURL(file);
reader.onload = function () {
console.log(reader.result);
return reader.result;
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
});
But I'm not the correct way to get past the folder path, or if I have to use another object and not File.
var file = new File("/pdf/test.pdf","r");
What's the best way to do it?
Thank you!

How do I write FileReader test in Jasmine?

I'm trying to make this test work, but I couldn't get my head around how to write a test with FileReader. This is my code
function Uploader(file) {
this.file = file;
}
Uploader.prototype = (function() {
function upload_file(file, file_contents) {
var file_data = new FormData()
file_data.append('filename', file.name)
file_data.append('mimetype', file.type)
file_data.append('data', file_contents)
file_data.append('size', file.size)
$.ajax({
url: "/upload/file",
type: "POST",
data: file_contents,
contentType: file.type,
success: function(){
// $("#thumbnail").attr("src", "/upload/thumbnail");
},
error: function(){
alert("Failed");
},
xhr: function() {
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress',showProgress, false);
} else {
console.log("Upload progress is not supported.");
}
return myXhr;
}
});
}
return {
upload : function() {
var self = this,
reader = new FileReader(),
file_content = {};
reader.onload = function(e) {
file_content = e.target.result.split(',')[1];
upload_file(self.file, file_content);
}
}
};
})();
And this is my test
describe("Uploader", function() {
it("should upload a file successfully", function() {
spyOn($, "ajax");
var fakeFile = {};
var uploader = new Uploader(fakeFile);
uploader.upload();
expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/upload/file");
})
});
But it never gets to reader.onload.
The problem here is the use of reader.onload which is hard to test. You could use reader.addEventListener instead so you can spy on the global FileReader object and return a mock:
eventListener = jasmine.createSpy();
spyOn(window, "FileReader").andReturn({
addEventListener: eventListener
})
then you can fire the onload callback by yourself:
expect(eventListener.mostRecentCall.args[0]).toEqual('load');
eventListener.mostRecentCall.args[1]({
target:{
result:'the result you wanna test'
}
})
This syntax changed in 2.0. Code below gives an example based on Andreas Köberle's answer but using the new syntax
// create a mock object, its a function with some inspection methods attached
var eventListener = jasmine.createSpy();
// this is going to be returned when FileReader is instantiated
var dummyFileReader = { addEventListener: eventListener };
// pipe the dummy FileReader to the application when FileReader is called on window
// this works because window.FileReader() is equivalent to new FileReader()
spyOn(window, "FileReader").and.returnValue(dummyFileReader)
// your application will do something like this ..
var reader = new FileReader();
// .. and attach the onload event handler
reader.addEventListener('load', function(e) {
// obviously this wouldnt be in your app - but it demonstrates that this is the
// function called by the last line - onloadHandler(event);
expect(e.target.result).toEqual('url');
// jasmine async callback
done();
});
// if addEventListener was called on the spy then mostRecent() will be an object.
// if not it will be null so careful with that. the args array contains the
// arguments that addEventListener was called with. in our case arg[0] is the event name ..
expect(eventListener.calls.mostRecent().args[0]).toEqual('load');
// .. and arg[1] is the event handler function
var onloadHandler = eventListener.calls.mostRecent().args[1];
// which means we can make a dummy event object ..
var event = { target : { result : 'url' } };
// .. and call the applications event handler with our test data as if the user had
// chosen a file via the picker
onloadHandler(event);
I also faced similar problem and was able to achieve it without use of addeventlistener. I had used onloadend, so below is what I did.
My ts file had below code:-
let reader = new FileReader();
reader.onloadend = function() {
let dataUrl = reader.result;
// Some working here
};
reader.readAsDataURL(blob);
My spec file (test) case code :-
let mockFileReader = {
result:'',
readAsDataURL:(blobInput)=> {
console.log('readAsDataURL');
},
onloadend:()=> {
console.log('onloadend');
}
};
spyOn<any>(window, 'FileReader').and.returnValue(mockFileReader);
spyOn<any>(mockFileReader, 'readAsDataURL').and.callFake((blobInput)=> {
// debug your running application and assign to "encodedString" whatever
//value comes actually after using readAsDataURL for e.g.
//"data:*/*;base64,XoteIKsldk......"
mockFileReader.result = encodedString;
mockFileReader.onloadend();
});
This way you have mocked the FileReader object and returned a fake call to your own "readAsDataURL". And thus now when your actual code calls "reasAsDataURL" your fake function is called in which you are assigning an encoded string in "result" and calling "onloadend" function which you had already assigned a functionality in your code (.ts) file. And hence it gets called with expected result.
Hope it helps.
I think the best way is to use the real FileReader (don't mock it), and pass in a real File or Blob. This improves your test coverage and makes your tests less brittle.
If your tests don't run in IE, you can use the File constructor, e.g.
const fakeFile = new File(["some contents"], "file.txt", {type: "text/plain"});
If you need to be compatible with IE, you can construct a Blob and make it look like a file:
const fakeFile = new Blob(["some contents"]);
fakeFile.name = "file.txt";
fakeFile.type = "text/plain";
The FileReader can read either of these objects so there is no need to mock it.
i found easiest for myself to do next.
mock blob file
run reader.onload while in test environment.
as result - i do not mock Filereader
// CONTROLLER
$scope.handleFile = function (e) {
var f = e[0];
$scope.myFile = {
name: "",
size: "",
base64: ""
};
var reader = new FileReader();
reader.onload = function (e) {
try {
var buffer = e.target.result;
$scope.myFile = {
name: f.name,
size: f.size,
base64: XLSX.arrayBufferToBase64(buffer)
};
$scope.$apply();
} catch (error) {
$scope.error = "ERROR!";
$scope.$apply();
}
};
reader.readAsArrayBuffer(f);
//run in test env
if ( typeof jasmine == 'object') {reader.onload(e)}
}
//JASMINE TEST
it('handleFile 0', function () {
var fileContentsEncodedInHex = ["\x45\x6e\x63\x6f\x64\x65\x49\x6e\x48\x65\x78\x42\x65\x63\x61\x75\x73\x65\x42\x69\x6e\x61\x72\x79\x46\x69\x6c\x65\x73\x43\x6f\x6e\x74\x61\x69\x6e\x55\x6e\x70\x72\x69\x6e\x74\x61\x62\x6c\x65\x43\x68\x61\x72\x61\x63\x74\x65\x72\x73"];
var blob = new Blob(fileContentsEncodedInHex);
blob.type = 'application/zip';
blob.name = 'name';
blob.size = 11111;
var e = {0: blob, target: {result: {}}};
$scope.handleFile(e);
expect($scope.error ).toEqual("");
});
I struggled to figure out how to test onloadend when it gets called from readAsDataURL.
Here is a dump of what I ended up with.
Production code:
loadFileDataIntoChargeback(tempFileList) {
var fileNamesAndData = [];
for (var i = 0, f; f = tempFileList[i]; i++) {
let theFile = tempFileList[i];
var reader = new FileReader();
reader.onloadend = ((theFile) => {
return (fileData) => {
var insertionIndex = this.chargeback.fileList.length;
this.chargeback.fileList.push({ FileName: theFile.name, Data: fileData.target.result, FileType: theFile.type });
this.loadFilePreviews(theFile, insertionIndex);
}
})(f);
reader.readAsDataURL(f);
}
this.fileInputPath = "";
}
Test code:
describe('when the files are loaded into the chargeback', () => {
it('loads file previews', () => {
let mockFileReader = {
target: { result: '' },
readAsDataURL: (blobInput) => {},
onloadend: () => {}
};
spyOn(chargeback, "loadFilePreviews");
spyOn(window, 'FileReader').and.returnValue(mockFileReader);
spyOn(mockFileReader, 'readAsDataURL').and.callFake((blobInput) => {
mockFileReader.onloadend({ target: { result: "data:image/jpeg;base64,/9j/4QAYRXh" } });
});
var readFileList = chargeback.getArrayFromFileInput([getImageFile1()]);
chargeback.loadFileDataIntoChargeback(readFileList);
expect(chargeback.loadFilePreviews).toHaveBeenCalled();
});
});

Categories