This is a sample script for using the values submitted from the HTML form using Google Apps Script and Javascript. In this case, the values include the files.
Issue
<form>
Text: <input type="text" name="sampleText1" /><br />
Single file: <input type="file" name="sampleFile1" /><br />
<input
type="submit"
name="button"
value="submit"
onclick="main(this.parentNode)"
/>
</form>
<script>
function main(e) {
google.script.run.sample(e);
}
</script>
This is a simple sample script for sending the values of form to Google Apps Script. In this case, texts and file are sent. When the button is clicked, main()
is run. In this case, this.parentNode
is sent to google.script.run.sample(this.parentNode)
. At that time, at Google Apps Script side, the text value can be correctly retrieved. But the file cannot be correctly sent. When the file is created as a file on Google Drive, the file is broken. I think that the reason of this issue might be due to character code.
So in this case, as the workaround, it is required to sent the file data as the string and byte array. I would like to propose for achieving this using the sample script.
Sample script
HTML & Javascript
<form>
Text: <input type="text" name="sampleText1" /><br />
Text: <input type="text" name="sampleText2" /><br />
Textarea: <textarea name="sampleTextarea"></textarea><br />
Number: <input type="number" name="sampleNumber" /><br />
Date: <input type="date" name="sampleDate" /><br />
Single file: <input type="file" name="sampleFile1" /><br />
Multiple files: <input type="file" name="sampleFile2" multiple /><br />
<input
type="submit"
name="button"
value="submit"
onclick="main(this);return false;"
/>
</form>
<div id="result"></div>
<script>
const parseValues = async (e) =>
Object.assign(
...(await Promise.all(
[...e.parentNode].map(
(obj) =>
new Promise(async (res) => {
const temp = { [obj.name]: { value: obj.value, type: obj.type } };
if (obj.type == "file") {
const files = obj.files;
temp[obj.name].value = await (async (files) => {
return await Promise.all(
[...files].map(
(file) =>
new Promise((resolve, reject) => {
const fr = new FileReader();
fr.onload = (f) =>
resolve({
filename: file.name,
mimeType: file.type,
bytes: [...new Int8Array(f.target.result)],
});
fr.onerror = (err) => reject(err);
fr.readAsArrayBuffer(file);
})
)
);
})(files).catch((err) => console.log(err));
}
res(temp);
})
)
))
);
async function main(e) {
e.value = "clicked";
const object = await parseValues(e);
google.script.run
.withSuccessHandler((f) => {
document.getElementById("result").innerHTML = f;
})
.sample(object);
}
</script>
Google Apps Script
function sample(object) {
const formObj = Object.entries(object).reduce((o, [k, v]) => {
let temp = { [k]: v.value };
if (v.type == "file")
temp[k] = v.value.map((e) =>
Utilities.newBlob(e.bytes, e.mimeType, e.filename)
);
Object.assign(o, temp);
return o;
}, {});
return "Done.";
}
- In this sample script,
parentNode
from the form is parsed and the files are converted to the byte array (int8Array). And then, the values are sent to Google Apps Script side usinggoogle.script.run
.
Result
When above script is run and the submit button is clicked after the values and files were inputted, the following values can be retrieved as formObj
at Google Apps Script side. In this case, when Blob
is created as a file, the inputted file is created.
{
"sampleFile2": [Blob, Blob],
"button": "clicked",
"sampleNumber": "1",
"sampleTextarea": "texts",
"sampleFile1": [Blob],
"sampleText1": "text1",
"sampleText2": "text2",
"sampleDate": "2000-01-01"
}
Note
- When you use this script, please enable V8 runtime at the script editor.
Limitation
- In this case, at Google Apps Script, the maximum size of blob, which can create a file, is 50 MB. So please be careful this.
Reference
- Google Apps Script is corrupting/blanking-out all files uploaded through a form I created. How do I fix this?
- This sample script have been answered for this thread in Stackoverflow.