I want to get a base64 string from an uploaded image. First time when i run the code, it returns undefined. When i run after it works fine. How can i fix this?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Upload</title>
</head>
<body>
<input type="file" id="file">
<button id="button" onclick="upload()">Upload</button>
<script type="text/javascript">
var result;
function getBase64(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
result = reader.result;
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
return result;
}
function upload() {
var file = document.querySelector('input').files[0];
console.log(getBase64(file));
}
</script>
</body>
</html>
CodePudding user response:
The answer ASDFGerte linked does explain this, but I will explain in the context of your question.
Lets examine what happens:
user clicks button
function upload executes
getBase64 is called
create a file reader and read file
assign a function to the .onload
event listener
assign a function to the .onerror
event listener
return variable result, which at this point does not exist, because .onload
event has not been triggered yet.
After your second click, the event has triggered, but for the previous result, not a new result.
The second goal is to fix this, and my favorite way is using the async await
syntax.
check out this rework of your code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Upload</title>
</head>
<body>
<input type="file" id="file">
<button id="button" onclick="upload()">Upload</button>
<script type="text/javascript">
async function getBase64(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
let result;
await new Promise(resolve => {
reader.onload = function () {
result = reader.result;
resolve();
};
reader.onerror = function (error) {
console.log('Error: ', error);
resolve();
};
});
return result;
}
async function upload() {
var file = document.querySelector('input').files[0];
const result = await getBase64(file);
console.log(result);
}
</script>
</body>
</html>
CodePudding user response:
function getBase64(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
return reader.result;
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
}
async function upload() {
var file = document.querySelector('input').files[0];
let result = await getBase64(file)
console.log(result);
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
FileReader
runs asynchronously so reader.onload
does not complete instantly. You return result
before reader.onload
has finished so result
does not have a value.
The second time you run upload
, result does have a value because reader.onload
has finished. The result logged will most likely be the result from the previous call to upload
.
You can fix this by making upload
an asynchronous function that uteawaits a response from getBase64
. This will also require you rn the result in reader.onload
instead of setting the value globally in the <script>
tag
CodePudding user response:
you need to declare FileReader
outside of upload()
and use the onload
function for the console.log
.
var reader = new FileReader();
reader.onload = function (event) {
var dataURL = event.target.result;
console.log(dataURL);
};
in update
function use only readDataURL
function upload() {
var file = document.querySelector("input").files[0];
reader.readAsDataURL(file)
}