Reputation: 15
I've been trying to make my code work for hours and i'm getting so annoyed and tired of this and would like to ask for some help.
I'm trying to make a easy API for the file input type (don't start saying my code is bad, i just want something that works and would like to ask for your help. Thank you.
I know that onload is asynchronous and I've tried every possible thing i can think of and this is irritating me. Ill be checking back here later on to see if anyone could help.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Input - Testing</title>
<script src="js/app_2.js" defer></script>
</head>
<body>
<input type="file" id="file_input" />
<img id="image_preview" />
</body>
</html>
let file_input;
document.addEventListener("DOMContentLoaded", function() {
file_input = document.querySelector("#file_input");
file_input.addEventListener("change", () => on_file_update());
});
function FileInputManager(files) {
if (!files || typeof files !== "object")
return console.error("FileInputManager: Missing file_input_element.files, please provide it so I can run!");
let reader = new FileReader();
let file = files[0];
let types = file.type.split("/");
let full_type = types[0] === "" ? "empty" : types.join("/");
if (!file)
return console.error("FileInputManager: No file selected, maybe something went wrong?");
// Determine How To Read The File By Testing The Mime-Type
this.determine_read_type = function() {
switch (types[0]) {
case "image":
return reader.readAsDataURL(file);
case "text":
return reader.readAsText(file);
case "application":
return reader.readAsText(file);
default:
console.warn(`FileInputManager: File reading has been aborted, file type [type: ${full_type}] unsupported.`);
break;
}
}
this.determine_read_type();
let result = "unknown";
reader.onload = function() {
result = reader.result;
};
// switch(types[1]) {
// case "octet-stream":
// return console.error(`FileInputManager: Unable to run, file type [type: ${full_type}] not allowed.`);
this.getResult = function() {
return result;
}
this.getMimeType = function() {
if (types.length <= 0)
return console.error("FileInputManager: Mime-Type is missing, maybe something went wrong?");
return String(types.join("/"));
}
return;
}
function on_file_update() {
let reader_file = new FileInputManager(file_input.files);
console.log(reader_file.getResult());
if (reader_file.getMimeType().startsWith("image"))
document.querySelector("#image_preview").src = reader_file.getResult();
if (reader_file.getMimeType().startsWith("text"))
console.log(reader_file.getResult());
}
Upvotes: 1
Views: 3033
Reputation: 281764
As you correctly state that onLoad
is asynchronous, but you still try to access the result immediately after calling new FileInputManager(file_input.files);
in below line
let reader_file = new FileInputManager(file_input.files);
console.log(reader_file.getResult());
You instead need to return a promise from FileInputManager's getResult and wait on it
function FileInputManager(files) {
let callbackRes = () => {};
const promise = new Promise((res, rej ) => {
this.callbackRes = res;
});
if (!files || typeof files !== "object")
return console.error("FileInputManager: Missing file_input_element.files, please provide it so I can run!");
let reader = new FileReader();
let file = files[0];
let types = file.type.split("/");
let full_type = types[0] === "" ? "empty" : types.join("/");
if (!file)
return console.error("FileInputManager: No file selected, maybe something went wrong?");
// Determine How To Read The File By Testing The Mime-Type
this.determine_read_type = function() {
switch (types[0]) {
case "image":
return reader.readAsDataURL(file);
case "text":
return reader.readAsText(file);
case "application":
return reader.readAsText(file);
default:
console.warn(`FileInputManager: File reading has been aborted, file type [type: ${full_type}] unsupported.`);
break;
}
}
this.determine_read_type();
let result = "unknown";
reader.onload = function() {
callbackRes(reader.result);
};
// switch(types[1]) {
// case "octet-stream":
// return console.error(`FileInputManager: Unable to run, file type [type: ${full_type}] not allowed.`);
this.getResult = function() {
return promise;
}
this.getMimeType = function() {
if (types.length <= 0)
return console.error("FileInputManager: Mime-Type is missing, maybe something went wrong?");
return String(types.join("/"));
}
return;
}
async function on_file_update() {
let reader_file = new FileInputManager(file_input.files);
const res = await reader_file.getResult();
console.log(res);
if (reader_file.getMimeType().startsWith("image"))
document.querySelector("#image_preview").src = reader_file.getResult();
if (reader_file.getMimeType().startsWith("text"))
console.log(res);
}
Upvotes: 2
Reputation: 1074495
You're calling getResult
before the result is available. As you said, the reading process is asynchronous, but your code isn't waiting for the read to be complete. You start the process in FileInputManager
, but then on_file_update
immediately calls getResult
, which is still "unkonwn"
because nothing has assigned to it since you assigned "unknown"
.
You have to wait for that onload
callback before you can use the result. FileInputManager
will need to provide some way of hooking into the callback it gets — letting you provide your own callback, returning a promise, that sort of thing.
Upvotes: 2