Search code examples
javascripthtmlgoogle-apps-scriptweb-applicationsgoogle-drive-api

Combine google.script.run and javascript function


I'm building a custom "Google Forms"-form with a file upload function. The form uses a custom "Thankyou"-page (see 1st line: iframe).
I've found a file upload script that needs to run in the Google Script environment and it will upload files to my Google Drive.

Now I need to combine this upload script with my custom Google Form. But I don't know exactly how to achieve this because there actions that need to be combined and the file upload has to be completed first before going to the "Thank you" page.

I've tried to combine it which looks like the code below.

The form:

<iframe name="hidden_iframe" id="hidden_iframe" style="display:none;" onload="if(submitted)  { picUploadJs(myForm); }"></iframe>

<form id="myForm" action="https://docs.google.com/forms/d/e/xxx/formResponse" target="hidden_iframe" onsubmit="submitted=true;">
     <input placeholder="1234" name="entry.1234" id="user" type="text">
     <label for="user">User:</label>

     <input name="picToLoad" type="file" />

     <div id="status" style="display: none">
       Uploading. Please wait...
     </div

   <button type="submit" name="action">Send</button>
</form>

The upload script:

<script>

  function picUploadJs(frmData) {

    document.getElementById('status').style.display = 'inline';

    google.script.run
      .withSuccessHandler(updateOutput)
      .processForm(frmData)
    };

  function updateOutput() {

    var outputDiv = document.getElementById('status');
    outputDiv.innerHTML = "The File was UPLOADED!";
    window.location='https://thankyoupage/';
  }

</script>

This now results in: Form input data is submitted, upload status text appears but nothing happens: "Uploading. Please wait...".

The result should be: Form input data submit, upload file to drive and redirect to the thankyou page.

EDIT: Google Script code

function doGet(e) {
  return HtmlService.createTemplateFromFile('test')
    .evaluate() // evaluate MUST come before setting the Sandbox mode
    .setTitle('Name To Appear in Browser Tab')
    //.setSandboxMode();//Defaults to IFRAME which is now the only mode available
}

function processForm(theForm) {
  var fileBlob = theForm.picToLoad;

  Logger.log("fileBlob Name: " + fileBlob.getName())
  Logger.log("fileBlob type: " + fileBlob.getContentType())
  Logger.log('fileBlob: ' + fileBlob);

  var fldrSssn = DriveApp.getFolderById('xxxx');
    fldrSssn.createFile(fileBlob);

  return true;
}


Solution

    • When you click "Send" button,
      • Google Form works fine.
      • document.getElementById('status').style.display = 'inline' works.
      • Function of processForm(frmData) at Google Apps Script doesn't work.
      • Function of updateOutput() at Javascript doesn't work.

    If my understanding is correct, how about this modification? Please think of this as just one of several answers.

    Modification points:

    • In this modification, the file was retrieved using onclick event, while the script for submitting to Google Form is not modified.
    • The retrieved file is converted to base64 and sent to Google Apps Script.

    Modified script:

    HTML:

    <form id="myForm" action="https://docs.google.com/forms/d/e/xxx/formResponse" target="hidden_iframe" onsubmit="submitted=true;">
      <input placeholder="1234" name="entry.1234" id="user" type="text">
      <label for="user">User:</label>
      <input name="picToLoad" type="file" id="sampleFile" /> <!-- Modified -->
      <div id="status" style="display: none">
      Uploading. Please wait...
      </div>
      <button type="submit" name="action" id="sampleId" >Send</button> <!-- Modified -->
    </form>
    

    Javascript:

    <script>
      // Below script was added.
      document.getElementById("sampleId").onclick = function(e) {
        e.stopPropagation();
        e.preventDefault();
        var file = document.getElementById("sampleFile").files[0];
        const f = new FileReader();
        f.onload = (e) => {
          const data = e.target.result.split(",");
          const obj = {fileName: file.name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
          picUploadJs(obj);
        }
        f.readAsDataURL(file);
      };
    
      function picUploadJs(frmData) {
        document.getElementById('status').style.display = 'inline';
        google.script.run.withSuccessHandler(updateOutput).processForm(frmData)
      };
    
      function updateOutput() {
        var outputDiv = document.getElementById('status');
        outputDiv.innerHTML = "The File was UPLOADED!";
        window.location='https://thankyoupage/';
      }
    </script>
    

    Google Apps Script:

    function processForm(theForm) {
      var fileBlob = Utilities.newBlob(Utilities.base64Decode(theForm.data), theForm.mimeType, theForm.fileName);
      var fldrSssn = DriveApp.getFolderById('xxxx');
      fldrSssn.createFile(fileBlob);
      return true;
    }
    

    Note:

    • When the file is selected and click a "Send" button, the file is send to Google Apps Script and is created as a file on Google Drive, while Google Form is submitted. Then updateOutput() at Javascript side is run.
    • In this modified script, The blob is used. So the maximum size of a file for uploading is 50 MB. Please be careful this.

    Edit 1:

    At your comment, it was found that When I remove the id=sampleId from the submit button, the Google Form data is submitted correctly. Using this, please test the following modification.

    In this modification, id="sampleId" was removed and the event is triggered using the name of element.

    HTML:

    <form id="myForm" target="hidden_iframe" onsubmit="submitted=true;">
      <input placeholder="1234" name="entry.1234" id="user" type="text">
      <label for="user">User:</label>
      <input name="picToLoad" type="file" id="sampleFile" />
      <div id="status" style="display: none">
      Uploading. Please wait...
      </div>
      <button type="submit" name="action">Send</button> <!-- Modified -->
    </form>
    

    Javascript:

    var button = document.getElementsByName('action')[0]; // Modified
    button.onclick = function(e) { // Modified
      e.stopPropagation();
      e.preventDefault();
      var file = document.getElementById("sampleFile").files[0];
      const f = new FileReader();
      f.onload = (e) => {
        const data = e.target.result.split(",");
        const obj = {fileName: file.name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
        picUploadJs(obj);
      }
      f.readAsDataURL(file);
    };
    

    Edit 2:

    I updated HTML and Javascript. Please confirm it. Google Apps Script is not modified.

    HTML:

    <iframe name="hidden_iframe" id="hidden_iframe" style="display:none;" onload="if(submitted)  { picUploadJs(myForm); }"></iframe>
    <form id="myForm" action="https://docs.google.com/forms/d/e/xxx/formResponse" target="hidden_iframe" onsubmit="submitted=true;">
      <input placeholder="1234" name="entry.1234" id="user" type="text">
      <label for="user">User:</label>
      <input name="picToLoad" type="file" id="sampleFile" /> <!-- Modified -->
      <div id="status" style="display: none">
      Uploading. Please wait...
      </div>
      <button type="submit" name="action">Send</button>
    </form>
    

    Javascript:

    <script>
      // This function was modified.
      function picUploadJs(myForm) {
        var file = document.getElementById("sampleFile").files[0];
        const f = new FileReader();
        f.onload = (e) => {
          const data = e.target.result.split(",");
          const obj = {fileName: file.name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
          document.getElementById('status').style.display = 'inline';
          google.script.run.withSuccessHandler(updateOutput).processForm(obj);
        }
        f.readAsDataURL(file);
      }
    
      function updateOutput() {
        var outputDiv = document.getElementById('status');
        outputDiv.innerHTML = "The File was UPLOADED!";
        window.location='https://thankyoupage/';
      }
    </script>