Using Values Submitted from HTML Form using Google Apps Script

Gists

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 using google.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

 Share!