6
votes

I'm trying to upload a file to a specific google drive folder along with form data into a spreadsheet. The spreadsheet portion of this code works, but the file upload function does not. Any help on fixing this would be appreciated.

Code.gs

var submissionSSKey = 'SS ID';
function doGet(e) {
      var template = HtmlService.createTemplateFromFile('Form.html');
  template.action = ScriptApp.getService().getUrl();
  return template.evaluate();
}

function doPost(e) {
  var template = HtmlService.createTemplateFromFile('Thanks.html');
  var LoanType = template.name = e.parameter.name;
  var borrower = template.department = e.parameter.department;
  var amount = template.message = e.parameter.message;
  var emailed = template.email = e.parameter.email;
  var comp = 'N/A'

  var sheet = SpreadsheetApp.openById(submissionSSKey).getSheets()[0];
  var lastRow = sheet.getLastRow();
  var targetRange = sheet.getRange(lastRow+1, 1, 1, 5).setValues([[comp,LoanType,borrower,amount,emailed]]);

  var fileBlob = e.paramater.thefile
  var doc = DriveApp.getFolderById('folder ID');
            doc.createFile(fileBlob)//.rename('New Name');


  return template.evaluate();


}

Form.html

<html>
    <head>
        <title></title>
    </head>
    <body>
    <form action="<?= action ?>" enctype="multipart/form-data" method="post">
    <table border="0" cellpadding="1" cellspacing="0" style="width: 500px;">
    <tbody>
    <tr>
    <td>
    Name:</td>
    <td>
    <input name="name" type="text" /></td>
    </tr>
    <tr>
    <td>
    Department:</td>
    <td>
    <select name="department">
    <option>Select Option</option>
    <option>Cashier</option>
    <option>Greeter</option>
    <option>Runner</option>
    <option>Line Control</option>
    <option>IDB</option>
    <option>Unknown</option>
    </select></td>
    </tr>
    <tr>
    <td>
    Email:</td>
    <td>
    <input name="email" type="text" /></td>
    </tr>
    <tr>
    <td>
    Message:</td>
    <td>
    <textarea name="message" style="margin: 2px; height: 148px; width: 354px;"></textarea></td>
    </tr>
    <tr>
    <td>
    <p>
    School Schedule (Image Files Only):</p>
    </td>
    <td>
    <p>
    <input type="file" id="thefile" name="thefile">
    </p></td>
    </tr>
    <tr>
    <td>
    <input type="submit" value="Submit" /></td>
    <td>
    You will receive an email confirmation upon submission</td>
    </tr>
    </tbody>
    </table>
  </form></body>
</html>

Thanks.html

<html>
  <body>
    <h1>Thanks</h1>
    <p>Thank you for your submission.</p>
    Name: <?= name ?><br/>
    Department: <?= department ?><br/>
    Message: <?= message ?><br/>
    Email: <?= email ?><br/>
  </body>
</html>
1

1 Answers

9
votes

Edit: Working example

The HtmlService does not support the post method for HTML forms. The input elements collected by a form can be communicated to a server-side function using a handler function instead. For more details, see HTML Service: Communicate with Server Functions.

Here's an example based on the code you've posted in your question.

Form.html

<script>
  // Javascript function called by "submit" button handler,
  // to show results.
  function updateOutput(resultHtml) {
    toggle_visibility('inProgress');
    var outputDiv = document.getElementById('output');
    outputDiv.innerHTML = resultHtml;
  }
  
  // From blog.movalog.com/a/javascript-toggle-visibility/
  function toggle_visibility(id) {
    var e = document.getElementById(id);
    if(e.style.display == 'block')
      e.style.display = 'none';
    else
      e.style.display = 'block';
  }
</script>

<div id="formDiv">
<!-- Form div will be hidden after form submission -->
<form id="myForm">

    Name: <input name="name" type="text" /><br/>
    Department:  <select name="department">
    <option>Select Option</option>
    <option>Cashier</option>
    <option>Greeter</option>
    <option>Runner</option>
    <option>Line Control</option>
    <option>IDB</option>
    <option>Unknown</option>
    </select><br/>
    Email: <input name="email" type="text" /><br/>
    Message: <textarea name="message" style="margin: 2px; height: 148px; width: 354px;"></textarea><br/>
    School Schedule (Image Files Only): <input name="myFile" type="file" /><br/>
  <input type="button" value="Submit"
      onclick="toggle_visibility('formDiv'); toggle_visibility('inProgress');
        google.script.run
          .withSuccessHandler(updateOutput)
          .processForm(this.parentNode)" />
</form>
</div>

<div id="inProgress" style="display: none;">
<!-- Progress starts hidden, but will be shown after form submission. -->
Uploading. Please wait...
</div>

<div id="output">
  <!-- Blank div will be filled with "Thanks.html" after form submission. -->
</div>

Thanks.html

<div>
    <h1>Thanks</h1>
    <p>Thank you for your submission.</p>
    Name: <?= name ?><br/>
    Department: <?= department ?><br/>
    Message: <?= message ?><br/>
    Email: <?= email ?><br/>
    File URL: <?= fileUrl ?><br/>
</div>

Code.gs

var submissionSSKey = '--Spreadsheet-key--';
var folderId = "--Folder-Id--";

function doGet(e) {
  var template = HtmlService.createTemplateFromFile('Form.html');
  template.action = ScriptApp.getService().getUrl();
  return template.evaluate();
}


function processForm(theForm) {
  var fileBlob = theForm.myFile;
  var folder = DriveApp.getFolderById(folderId);
  var doc = folder.createFile(fileBlob);
  
  // Fill in response template
  var template = HtmlService.createTemplateFromFile('Thanks.html');
  var name = template.name = theForm.name;
  var department = template.department = theForm.department;
  var message = template.message = theForm.message;
  var email = template.email = theForm.email;     
  var fileUrl = template.fileUrl = doc.getUrl();
  
  // Record submission in spreadsheet
  var sheet = SpreadsheetApp.openById(submissionSSKey).getSheets()[0];
  var lastRow = sheet.getLastRow();
  var targetRange = sheet.getRange(lastRow+1, 1, 1, 5).setValues([[name,department,message,email,fileUrl]]);
  
  // Return HTML text for display in page.
  return template.evaluate().getContent();
}

Original answer, which was focused on basic debugging:

Where does this code come from originally? There have been multiple questions about it, and it might be helpful to see the original tutorial or example it was taken from.

When you run this code as a published web app, and submit a file, the error you receive is TypeError: Cannot read property "thefile" from undefined. Without any more digging, this tells you that there's an undefined object being used in your code. What object is that? Don't know yet, but a clue is that the code is looking for a property named "thefile".

If you have the script open in the editor, and launched the webapp from there (by clicking on Test web app for your latest code in the Publish / Deploy as Web App dialog), then you can also check the Execution Transcript for more details. (under View menu) You'll find it contains something like this:

[13-12-25 07:49:12:447 EST] Starting execution
[13-12-25 07:49:12:467 EST] HtmlService.createTemplateFromFile([Thanks.html]) [0 seconds]
[13-12-25 07:49:12:556 EST] SpreadsheetApp.openById([--SSID--]) [0.089 seconds]
[13-12-25 07:49:12:557 EST] Spreadsheet.getSheets() [0 seconds]
[13-12-25 07:49:12:626 EST] Sheet.getLastRow() [0.067 seconds]
[13-12-25 07:49:12:627 EST] Sheet.getRange([1, 1, 1, 5]) [0 seconds]
[13-12-25 07:49:12:629 EST] Range.setValues([[[N/A, , Select Option, , ]]]) [0.001 seconds]
[13-12-25 07:49:12:983 EST] Execution failed: TypeError: Cannot read property "thefile" from undefined. (line 20, file "Code") [0.17 seconds total runtime]

We see that same error, but now we know the line number. That line contains a spelling mistake:

var fileBlob = e.paramater.thefile
                 ^^^^^^^^^