0

Trying to learn Google Web Apps, I'm having the hardest time in 4 years of studying Google services. At this point, with help from other people, I have assembled a Web App form which successfully processes a few questions and accepts the submission of a file, sending the file to a folder on my Google Drive, appending the form answers to a Google Sheet, and sending me an email alerting me to the form submission. I think I understand how it works, but in trying to make the simplest of changes to it, it stopped working and gave me an error message I don't what to do with.

The form requires the user to upload an image of their COVID vaccination card. Since some people have more than one card, the form allows the user to upload more than file. This screen shot shows what the form displays upon successful submission.

screen snap

The form fields and their answers remain in place, and below them appears the message "Uploaded successfully! You may upload another." What I want to have happen, besides a message like this appearing, is for all form fields and their answers disappear except for the Vacc Card/Choose File and Submit buttons.

So, I am trying to follow the instructions in this video from the highly popular YouTube Channel Learn Google Sheets & Excel Spreadsheets: Create Views (Pages) in Web App - Google Apps Script Web App Tutorial - Part 7

In this video, we see how to make the submission of a Web App form add to the current URL the string "?v=form" or "?v=whatever" and have the DoGet(e) function offer a different HTML file depending on whether the URL contains "&v" and if does, what follows that.

However, in following THE VERY FIRST STEP in the instructions, the App stopped working. All I did was cut what was inside the function doGet(e), place it inside a new function loadForm(), and put inside the doGet a calling of that function:

function doGet(e) {
  if (e.parameters.v == 'form') {
    return loadForm()
  } 

This one change caused the App to fail, returning nothing but a screen reading "The script completed but did not return anything."

My code:

/*

* Original doGet function; works fine. */
// function doGet(e){
//   return HtmlService.createTemplateFromFile('index').evaluate().addMetaTag('viewport', 'width=device-width, initial-scale=1')
//   .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
// }

/** Step that caused this to fail: */
function doGet(e) {
  if (e.parameters.v == 'form') {
    return loadForm()
    } // else {HtmlService.createHtmlOutput('<h1>Hello<h1>')} // This would have been the next step, and the step after that making a second HTML file.
    //                                                           Commenting out this step did NOT help.
}

function loadForm(){
  return HtmlService.createTemplateFromFile('index').evaluate().addMetaTag('viewport', 'width=device-width, initial-scale=1')
  .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
} /** There you have it. All that follows is part of what works. */

function uploadFiles(formObject) {
  var folderID = "1nvhxUoj9uRlE0KpBNjW3cosIuuRpAQly"; // Massage / VaccinationCards 
  try {
    var folder = DriveApp.getFolderById(folderID);
    var fileUrl = "";
    //Upload file if exists 
    if (formObject.myFile.length > 0) {
      var name = formObject.name;
      var namePref = formObject.namePref;
      var pronouns = formObject.pronouns;
      var ready = formObject.ready;
      var email = formObject.email;
      var phone = formObject.phone;
      var callTimes = formObject.callTimes;
      var questions = formObject.questions;
      var blob = formObject.myFile;
      var file = folder.createFile(blob);
      fileUrl = file.getUrl();

    } else {
      fileUrl = null;
  }
  SpreadsheetApp.openById("1S6RCLu8SKl0u8cVrEKd-3B71w5A-lvz0ikw_LPzgH50").getSheetByName("cards")
  .appendRow([name, namePref, pronouns, ready, email, phone, callTimes, questions, fileUrl, new Date()]);
  GmailApp.sendEmail('atiqzabinski@gmail.com', 'New Vax Card Uploaded!', 'Hey sweetie, smells like business! https://docs.google.com/spreadsheets/d/1S6RCLu8SKl0u8cVrEKd-3B71w5A-lvz0ikw_LPzgH50/edit', {name: 'Vacc Card Robot'});
  return fileUrl;
  } catch (error) {
    return error.message;
  }
}

My HTML:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body style = "background:none transparent;">
  <!-- <link href="/tpm-styles.css" rel="stylesheet" type="text/css"> -->
  <link href="https://transformphillymassage.com/tpm-styles.css" rel="stylesheet" type="text/css">
  <link href="https://transformphillymassage.com/formstyles.css" rel="stylesheet" type="text/css">
    <form id="myForm" onsubmit="handleFormSubmit(this)">
      <p>
        <label for="FormControlFile">Legal Name:</label>
        <input name="name" class="form-control-file" type="text" size="35" required/>
      <br>
        <label for="FormControlFile">Preferred Name:</label>
        <input name="namePref" class="form-control-file" type="text" size="30">
      <br>  <label for="FormControlFile">Pronouns:</label>
        <input name="pronouns" class="form-control-file" type="text" size = "35">
      </p>
      
      <p>
        <label for="FormControlFile">Choose One:</label>
  <!-- <select id = "id_ready" name = "ready" class="form-control-file" required/> -->
        <!-- <select id = "id_ready" name = "ready" required/> -->
        <select name = "ready" class="form-control-file" required/>
          <option value = "I'm ready to book!">I'm ready to book!</option>
          <option value = "I have questions.">I have questions.</option>
        </select>
      </p>    
      <p>
        <label for="FormControlFile">email:</label>
        <input name="email" class="form-control-file" type="text" size = "40" required/>
     <br>
        <label for="FormControlFile">Phone Number:</label>
        <input name="phone" class="form-control-file" type="text" size = "28" />
      <br>
        <label for="FormControlFile">Best Times To Call:</label><br>
        <input name="callTimes" class="form-control-file" type="text" size="50"/>      
      </p>
      <p>
        <label for="FormControlFile">Vacc Card:</label>
        <input name="myFile" class="form-control-file" type="file" required/>     
      </p>
      <p>
        <label for="FormControlFile">Questions / Comments:</label><br>
        <textarea name ="questions" class="form-control-file" cols="45" rows="4"></textarea>
      <br>

      <button type="submit"><span class="charm spanlavender">Submit</span></button>
      </p>
  </form>
  <div id="urlOutput"></div>
    <script>
      function preventFormSubmit() {
        var forms = document.querySelectorAll('form');
        for (var i = 0; i < forms.length; i++) {
          forms[i].addEventListener('submit', function(event) {
            event.preventDefault();
          });
        }
      }

      window.addEventListener('load', preventFormSubmit);

      function handleFormSubmit(formObject){
        google.script.run.withSuccessHandler(updateUrl).withFailureHandler(onFailure).uploadFiles(formObject); 
      }

      function updateUrl(url) {
        var div = document.getElementById('urlOutput');
        if(isValidURL(url)){
          div.innerHTML = '<div class="alert alert-success" role="alert"><a href="' + url + '">Uploaded successfully!</a><br>You may upload another.</div>';
          // document.getElementById("myForm").reset();
        } else {
        //Show warning message if file is not uploaded or provided
          div.innerHTML = '<div class="alert alert-danger" role="alert">'+ url +'!</div>';
        }
      }

      function onFailure(error) {
      var div = document.getElementById('urlOutput');
      div.innerHTML = '<div class="alert alert-danger" role="alert">'+ error.message +'!</div>';
      }

      function isValidURL(string) {
      var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
      return (res !== null);
      }
    </script>
  </body>
</html>

1 Answers1

1

return is missing on the else part of your if-else statement

Replace your doGet function by

function doGet(e) {
  if (e.parameters.v == 'form') {
    return loadForm()
  } else {
    return HtmlService.createHtmlOutput('<h1>Hello<h1>')
  }
}

Below are a couple of function that could be used to debug your doGet function by using the Google Apps Script editor.

/**
 * Test case 1: v parameter equal to 'form'
 *
 */
function test_1_doGet(){
  const e = {
    parameter: {}
  };
  e.parameter.v = 'form';
  doGet(e);
}
 
/**
 * Test case 2: No v parameter
 *
 */
function test_1_doGet(){
  const e = {
    parameter: {}
  };
  doGet(e);
}

Related

Rubén
  • 34,714
  • 9
  • 70
  • 166
  • I'm still puzzled, though. It was failing regardless of whether the URL included ?v=form. Why in those cases did the if(e.parameters.v == 'form') function not just pass the loadForm() successfully? – Atiq Zabinski Sep 14 '22 at 17:54
  • 2
    I'm sorry, I can't tell what happened in your tests as I'm not sure about what you really did. You might find helpful use console.log to understand what happened during the execution, i.e. add `console.log(JSON.stringify(e))` before the if-statement – Rubén Sep 14 '22 at 18:17
  • What I mean is that before I made your fix, I was getting that error message instead of the form, regardless of whether the URL (of the Web App or the page I installed it into) included ?v=form. Why did changing the else {} part change the outcome of the first part? The same URL that now returns the form was returning the error before I made your fix. – Atiq Zabinski Sep 14 '22 at 18:48
  • BTW, I just tried your advice with the console.log function and now I'm confused about that as well. When do I get to read the console message? Opening the Web App and submitting the form does nothing to the Execution Log, and trying to run doGet from the console unsurprisingly only returns "TypeError: Cannot read property 'parameters' of undefined". – Atiq Zabinski Sep 14 '22 at 18:55
  • I'm sorry to repeat myself, I can't tell what happened in your tests as I'm not sure about what you really did. I suggest you to spend some time learning about how to create a [mcve]. In the case of understanding the event object, the execution logs, the console on client-side, include the doGet function with a parameter for the event object (usually `e`), the code that build the HttpOutput object without using html files, and `console.log(JSON.stringify(e))` before the return statement. On the question description include the steps to deploy the web app and use test deployment for testing. – Rubén Sep 14 '22 at 21:01
  • 1
    By the way, if the code use an event object properties, i.e. e.parameter, do not call the function that has the event object as parameter from the Google Apps Script editor, you have to call another function that creates an object with the properties of the event object. Related https://stackoverflow.com/q/16089041/1595451 – Rubén Sep 14 '22 at 21:07
  • Sorry if I wasn't clear about what I did. What I did was view the Web app (sometimes in an iFrame on my site, other times just in the script.google.com/macros/ preview; didn't matter which, results were the same) I would then add ?v=form to the URL manually. Before I made the fix you recommended, I would always get that error message, regardless of whether I included ?v=form in the URL. Your fix made the form appear when ?v=form was included and in all other cases returned the simple "Hello" html. This is exactly what is expected at this step. – Atiq Zabinski Sep 14 '22 at 22:11
  • What I don't understand is that your fix was only to the else {} outcome. So why did it fix both outcomes? Or rather, how come I couldn't get the loadform() function to run when I did include the ?v=form which should should have passed the if() as true? – Atiq Zabinski Sep 14 '22 at 22:13
  • Also, as I indicated in the Comments on my Code, I experienced this failure even when I stepped back to *before I even declared the else clause.* This is not making sense to me. – Atiq Zabinski Sep 14 '22 at 22:14
  • @AtiqZabinski The original code is in your question. Right? Can you reproduce the error now? – TheMaster Sep 14 '22 at 22:18
  • 1
    Thanks for confirming that question is already answered. I suggest you to post new questions regarding your new inquiries. I'm sorry if I don't have the "conversational style" that you are looking, I very rarely read thoroughly questions and code that aren't concise / "mcve " style. Please bear in mind that comments are not intend to have extended discussions either for making follow-up questions. Another option that might help you to reach other seasoned SO - google-apps script community members is to use the SO chat. There is a chat room for Google Apps Script, the link is in the tag wiki. – Rubén Sep 14 '22 at 22:47