My web app has a few file input elements where the user can upload any number of files of different types. I'm trying to store all data first in an array the same size of the number of input elements, where each item in the said array contains an array of data (filename, blob, mimetype) from each uploaded file.
The user can choose to upload or not, but if they don't, I still need to save some reference for that row with an empty upload by getting its data attribute (header).
The data appears in the browser console, but it returns undefined/empty/null when accessed from the client side of Google Apps Script. I'm not very familiar with the FileReader.
On the server side, I want to create a file in Google Drive from each blob and finally store the URL in Sheets.
Thanks in advance!
function saveFormData(){
var fileInputs = document.querySelectorAll('tr.result-row td > input.upload');
var firstUploadIndex = fileInputs[0].parentElement.parentElement.getAttribute('data-index');
//Loop through all upload rows
var uploads = []; //will be array of arrays of multi-uploaded files; each item inside belongs to 1 column in db
Array.from(fileInputs).forEach(input => {
var files = input.files; //object file list
if(files.length < 1){ //if there's no file in the upload input
var header = input.getAttribute('data-uploadtype'); //save the header name as reference
var fileData = [header, '', '', ''];
uploads.push(fileData);
} else { //if there's a file/s in the upload input
var innerUploads = []; //array of data for each file
//Loop through all these files
for(var i = 0; i < files.length; i++){
var currentFile = files[i];
if(!currentFile) return; //if no current file, just in case
const fr = new FileReader();
fr.onload = (e) => {
var data = e.target.result.split(','); //split current file
var fileData = { binary: data[1], mimeType: data[0].match(/:(\w.+);/)[1], filename: currentFile.name };
innerUploads.push(fileData);
}
fr.readAsDataURL(currentFile);
} //CLOSES FOR LOOP
uploads.push(innerUploads);
} //CLOSES IF
}); //CLOSES FOR EACH LOOP
google.script.run.saveToDrive(uploads);
} //CLOSES FUNCTION
I believe your goal is as follows.
fileInputs
and create an array of uploads
including the values like [header, '', '', '']
and { binary: data[1], mimeType: data[0].match(/:(\w.+);/)[1], filename: currentFile.name }
.When I saw your script, I thought that the reason for your current issue is due to that FileReader is run with the asynchronous process. This has already been mentioned in my 1st comment.
When this is reflected in your script, how about the following modification?
Please modify your Javascript as follows.
function getFiles(file) {
return new Promise((resolve, reject) => {
const fr = new FileReader();
fr.onload = e => {
const data = e.target.result.split(",");
const obj = { binary: data[1], mimeType: data[0].match(/:(\w.+);/)[1], fileName: file.name };
resolve(obj);
}
if (file) {
fr.readAsDataURL(file);
} else {
reject("No file");
}
});
}
async function saveFormData() {
var fileInputs = document.querySelectorAll('tr.result-row td > input.upload');
// var firstUploadIndex = fileInputs[0].parentElement.parentElement.getAttribute('data-index'); // This is not used in your showing script.
var uploads = [];
var ar = Array.from(fileInputs);
for (var i = 0; i < ar.length; i++) {
var files = ar[i].files;
if (files.length == 0) {
var header = ar[i].getAttribute('data-uploadtype'); //save the header name as reference
var fileData = [header, '', '', ''];
uploads.push(fileData);
} else {
for (var j = 0; j < ar[i].files.length; j++) {
var res = await getFiles(ar[i].files[j]).catch(err => console.log(err));
uploads.push(res);
}
}
}
console.log(uploads); // You can confirm the value in the log.
google.script.run.saveToDrive(uploads);
}